ctrl to unstuck components

This commit is contained in:
bancika
2011-01-20 20:33:42 +00:00
parent e0fd55c374
commit 2309e80edc
7 changed files with 85 additions and 52 deletions
@@ -233,8 +233,11 @@ public interface IPlugInPort {
* Note: point coordinates are scaled for zoom factor. * Note: point coordinates are scaled for zoom factor.
* *
* @param point * @param point
* @param ctrlDown
* @param shiftDown
* @param altDown
*/ */
void dragStarted(Point point); void dragStarted(Point point, boolean ctrlDown, boolean shiftDown, boolean altDown);
/** /**
* Checks if it's possible to drop over the specified point. * Checks if it's possible to drop over the specified point.
@@ -5,7 +5,6 @@ import java.awt.dnd.DragGestureListener;
import org.diylc.common.IPlugInPort; import org.diylc.common.IPlugInPort;
/** /**
* {@link DragGestureListener} for {@link CanvasPanel}. * {@link DragGestureListener} for {@link CanvasPanel}.
* *
@@ -22,7 +21,8 @@ class CanvasGestureListener implements DragGestureListener {
@Override @Override
public void dragGestureRecognized(DragGestureEvent dge) { public void dragGestureRecognized(DragGestureEvent dge) {
presenter.dragStarted(dge.getDragOrigin()); presenter.dragStarted(dge.getDragOrigin(), dge.getTriggerEvent().isControlDown(), dge
.getTriggerEvent().isShiftDown(), dge.getTriggerEvent().isAltDown());
dge.startDrag(presenter.getCursorAt(dge.getDragOrigin()), new EmptyTransferable(), dge.startDrag(presenter.getCursorAt(dge.getDragOrigin()), new EmptyTransferable(),
new CanvasSourceListener(presenter)); new CanvasSourceListener(presenter));
} }
@@ -76,7 +76,7 @@ class CanvasPanel extends JComponent implements Autoscroll {
private void initializeDnD() { private void initializeDnD() {
// Initialize drag source recognizer. // Initialize drag source recognizer.
DragSource.getDefaultDragSource().createDefaultDragGestureRecognizer(this, DragSource.getDefaultDragSource().createDefaultDragGestureRecognizer(this,
DnDConstants.ACTION_MOVE, new CanvasGestureListener(plugInPort)); DnDConstants.ACTION_COPY_OR_MOVE | DnDConstants.ACTION_LINK, new CanvasGestureListener(plugInPort));
// Initialize drop target. // Initialize drop target.
new DropTarget(this, DnDConstants.ACTION_COPY_OR_MOVE, new DropTarget(this, DnDConstants.ACTION_COPY_OR_MOVE,
new CanvasTargetListener(plugInPort), true); new CanvasTargetListener(plugInPort), true);
@@ -202,13 +202,14 @@ public class StatusBar extends JPanel implements IPlugIn {
Collection<IDIYComponent<?>> stuckComponents = (Collection<IDIYComponent<?>>) params[1]; Collection<IDIYComponent<?>> stuckComponents = (Collection<IDIYComponent<?>>) params[1];
Collection<String> componentNames = new HashSet<String>(); Collection<String> componentNames = new HashSet<String>();
for (IDIYComponent<?> component : selection) { for (IDIYComponent<?> component : selection) {
componentNames.add(component.getName()); componentNames.add("<font color='blue'>" + component.getName() + "</font>");
} }
this.selectedComponentNames = new ArrayList<String>(componentNames); this.selectedComponentNames = new ArrayList<String>(componentNames);
Collections.sort(this.selectedComponentNames); Collections.sort(this.selectedComponentNames);
this.stuckComponentNames = new ArrayList<String>(); this.stuckComponentNames = new ArrayList<String>();
for (IDIYComponent<?> component : stuckComponents) { for (IDIYComponent<?> component : stuckComponents) {
this.stuckComponentNames.add(component.getName()); this.stuckComponentNames.add("<font color='blue'>" + component.getName()
+ "</font>");
} }
this.stuckComponentNames.removeAll(this.selectedComponentNames); this.stuckComponentNames.removeAll(this.selectedComponentNames);
Collections.sort(this.stuckComponentNames); Collections.sort(this.stuckComponentNames);
@@ -242,21 +243,22 @@ public class StatusBar extends JPanel implements IPlugIn {
} }
private void refreshStatusText() { private void refreshStatusText() {
String statusText = "";
if (componentSlot == null) { if (componentSlot == null) {
if (componentsUnderCursor != null && !componentsUnderCursor.isEmpty()) { if (componentsUnderCursor != null && !componentsUnderCursor.isEmpty()) {
String formattedNames = Utils.toCommaString(componentsUnderCursor); String formattedNames = Utils.toCommaString(componentsUnderCursor);
getStatusLabel().setText("Drag control point(s) of " + formattedNames); statusText = "Drag control point(s) of " + formattedNames;
} else if (selectedComponentNames != null && !selectedComponentNames.isEmpty()) { } else if (selectedComponentNames != null && !selectedComponentNames.isEmpty()) {
StringBuilder builder = new StringBuilder(); StringBuilder builder = new StringBuilder();
builder.append(Utils.toCommaString(selectedComponentNames)); builder.append(Utils.toCommaString(selectedComponentNames));
if (!stuckComponentNames.isEmpty()) { if (!stuckComponentNames.isEmpty()) {
builder.append(" ("); builder.append(" (hold <b>Ctrl</b> to unstuck from ");
builder.append(Utils.toCommaString(stuckComponentNames)); builder.append(Utils.toCommaString(stuckComponentNames));
builder.append(" would be affected by dragging as well)"); builder.append(")");
} }
getStatusLabel().setText("Selection: " + builder.toString()); statusText = "<html>Selection: " + builder.toString() + "</html>";
} else { } else {
getStatusLabel().setText(""); statusText = "";
} }
} else { } else {
switch (componentSlot.getCreationMethod()) { switch (componentSlot.getCreationMethod()) {
@@ -267,16 +269,22 @@ public class StatusBar extends JPanel implements IPlugIn {
} else { } else {
count = "second"; count = "second";
} }
getStatusLabel().setText( statusText = "Click on the canvas to set the " + count + " control point of a new "
"Click on the canvas to set the " + count + " control point of a new " + componentSlot.getName() + " or press Esc to cancel";
+ componentSlot.getName() + " or press Esc to cancel");
break; break;
case SINGLE_CLICK: case SINGLE_CLICK:
getStatusLabel().setText( statusText = "Click on the canvas to create a new " + componentSlot.getName()
"Click on the canvas to create a new " + componentSlot.getName() + " or press Esc to cancel";
+ " or press Esc to cancel");
break; break;
} }
} }
final String finalStatus = statusText;
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
getStatusLabel().setText(finalStatus);
}
});
} }
} }
@@ -26,7 +26,7 @@ class ToolboxGestureListener implements DragGestureListener {
@Override @Override
public void dragGestureRecognized(DragGestureEvent dge) { public void dragGestureRecognized(DragGestureEvent dge) {
presenter.dragStarted(dge.getDragOrigin()); // presenter.dragStarted(dge.getDragOrigin());
dge.startDrag(Cursor.getDefaultCursor(), new StringSelection(className), dge.startDrag(Cursor.getDefaultCursor(), new StringSelection(className),
new ToolboxSourceListener(presenter)); new ToolboxSourceListener(presenter));
} }
@@ -20,6 +20,7 @@ import java.util.Set;
import org.diylc.common.ComponentSelection; import org.diylc.common.ComponentSelection;
import org.diylc.common.DrawOption; import org.diylc.common.DrawOption;
import org.diylc.common.EventType;
import org.diylc.common.GridType; import org.diylc.common.GridType;
import org.diylc.common.IComponentFiler; import org.diylc.common.IComponentFiler;
import org.diylc.core.ComponentState; import org.diylc.core.ComponentState;
@@ -29,6 +30,7 @@ import org.diylc.core.VisibilityPolicy;
import org.diylc.utils.Constants; import org.diylc.utils.Constants;
import com.diyfever.gui.miscutils.ConfigurationManager; import com.diyfever.gui.miscutils.ConfigurationManager;
import com.diyfever.gui.simplemq.MessageDispatcher;
/** /**
* Utility that deals with painting {@link Project} on the {@link Graphics2D} * Utility that deals with painting {@link Project} on the {@link Graphics2D}
@@ -36,10 +38,12 @@ import com.diyfever.gui.miscutils.ConfigurationManager;
* *
* @author Branislav Stojkovic * @author Branislav Stojkovic
*/ */
public class ProjectPainter { public class DrawingManager {
public static int CONTROL_POINT_SIZE = 7;
public static final int CONTROL_POINT_SIZE = 7;
public static final String ANTIALIASING_KEY = "anti-aliasing"; public static final String ANTIALIASING_KEY = "anti-aliasing";
public static final String ZOOM_KEY = "zoom";
public static boolean DEBUG_COMPONENT_AREAS = false; public static boolean DEBUG_COMPONENT_AREAS = false;
public static Color GRID_COLOR = new Color(240, 240, 240); public static Color GRID_COLOR = new Color(240, 240, 240);
@@ -54,8 +58,14 @@ public class ProjectPainter {
private Composite slotComposite = AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.3f); private Composite slotComposite = AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.3f);
public ProjectPainter() { private double zoomLevel = 1d;// ConfigurationManager.getInstance().readDouble(ZOOM_KEY,
// 1d);
private MessageDispatcher<EventType> messageDispatcher;
public DrawingManager(MessageDispatcher<EventType> messageDispatcher) {
super(); super();
this.messageDispatcher = messageDispatcher;
componentAreaMap = new HashMap<IDIYComponent<?>, Area>(); componentAreaMap = new HashMap<IDIYComponent<?>, Area>();
lastDrawnStateMap = new HashMap<IDIYComponent<?>, ComponentState>(); lastDrawnStateMap = new HashMap<IDIYComponent<?>, ComponentState>();
} }
@@ -63,7 +73,7 @@ public class ProjectPainter {
public void drawProject(Graphics2D g2d, Project project, Set<DrawOption> drawOptions, public void drawProject(Graphics2D g2d, Project project, Set<DrawOption> drawOptions,
IComponentFiler filter, Rectangle selectionRect, ComponentSelection selectedComponents, IComponentFiler filter, Rectangle selectionRect, ComponentSelection selectedComponents,
Set<IDIYComponent<?>> groupedComponents, List<Point> controlPointSlot, Set<IDIYComponent<?>> groupedComponents, List<Point> controlPointSlot,
IDIYComponent<?> componentSlot, boolean dragInProgress, double zoomLevel) { IDIYComponent<?> componentSlot, boolean dragInProgress) {
if (project == null) { if (project == null) {
return; return;
} }
@@ -247,6 +257,16 @@ public class ProjectPainter {
} }
} }
public double getZoomLevel() {
return zoomLevel;
}
public void setZoomLevel(double zoomLevel) {
this.zoomLevel = zoomLevel;
fireZoomChanged();
// ConfigurationManager.getInstance().writeValue(ZOOM_KEY, zoomLevel);
}
public void invalidateComponent(IDIYComponent<?> component) { public void invalidateComponent(IDIYComponent<?> component) {
componentAreaMap.remove(component); componentAreaMap.remove(component);
lastDrawnStateMap.remove(component); lastDrawnStateMap.remove(component);
@@ -290,4 +310,9 @@ public class ProjectPainter {
} }
return new Dimension((int) width, (int) height); return new Dimension((int) width, (int) height);
} }
public void fireZoomChanged() {
messageDispatcher.dispatchMessage(EventType.ZOOM_CHANGED, zoomLevel);
messageDispatcher.dispatchMessage(EventType.REPAINT);
}
} }
@@ -60,11 +60,9 @@ public class Presenter implements IPlugInPort {
public static final VersionNumber CURRENT_VERSION = new VersionNumber(3, 0, 1); public static final VersionNumber CURRENT_VERSION = new VersionNumber(3, 0, 1);
public static final String DEFAULTS_KEY_PREFIX = "default."; public static final String DEFAULTS_KEY_PREFIX = "default.";
public static final String METRIC_KEY = "metric"; public static final String METRIC_KEY = "metric";
public static final String ZOOM_KEY = "zoom";
public static final int ICON_SIZE = 32; public static final int ICON_SIZE = 32;
private double zoomLevel = ConfigurationManager.getInstance().readDouble(ZOOM_KEY, 1d);
private Project currentProject; private Project currentProject;
private Map<String, List<ComponentType>> componentTypes; private Map<String, List<ComponentType>> componentTypes;
// Maps component class names to ComponentType objects. // Maps component class names to ComponentType objects.
@@ -78,7 +76,7 @@ public class Presenter implements IPlugInPort {
// Utilities // Utilities
private Cloner cloner; private Cloner cloner;
private ProjectPainter projectPainter; private DrawingManager drawingManager;
private ProjectFileManager projectFileManager; private ProjectFileManager projectFileManager;
private Rectangle selectionRect; private Rectangle selectionRect;
@@ -113,7 +111,7 @@ public class Presenter implements IPlugInPort {
selectedComponents = new ComponentSelection(); selectedComponents = new ComponentSelection();
currentProject = new Project(); currentProject = new Project();
cloner = new Cloner(); cloner = new Cloner();
projectPainter = new ProjectPainter(); drawingManager = new DrawingManager(messageDispatcher);
projectFileManager = new ProjectFileManager(messageDispatcher); projectFileManager = new ProjectFileManager(messageDispatcher);
// lockedLayers = EnumSet.noneOf(ComponentLayer.class); // lockedLayers = EnumSet.noneOf(ComponentLayer.class);
@@ -142,19 +140,16 @@ public class Presenter implements IPlugInPort {
@Override @Override
public double getZoomLevel() { public double getZoomLevel() {
return zoomLevel; return drawingManager.getZoomLevel();
} }
@Override @Override
public void setZoomLevel(double zoomLevel) { public void setZoomLevel(double zoomLevel) {
LOG.info(String.format("setZoomLevel(%s)", zoomLevel)); LOG.info(String.format("setZoomLevel(%s)", zoomLevel));
if (this.zoomLevel == zoomLevel) { if (drawingManager.getZoomLevel() == zoomLevel) {
return; return;
} }
this.zoomLevel = zoomLevel; drawingManager.setZoomLevel(zoomLevel);
ConfigurationManager.getInstance().writeValue(ZOOM_KEY, zoomLevel);
messageDispatcher.dispatchMessage(EventType.ZOOM_CHANGED, zoomLevel);
messageDispatcher.dispatchMessage(EventType.REPAINT);
} }
@Override @Override
@@ -163,7 +158,7 @@ public class Presenter implements IPlugInPort {
if (componentTypeSlot == null) { if (componentTypeSlot == null) {
// Scale point to remove zoom factor. // Scale point to remove zoom factor.
Point2D scaledPoint = scalePoint(point); Point2D scaledPoint = scalePoint(point);
if (projectPainter.isCursorOverArea(scaledPoint)) { if (drawingManager.isCursorOverArea(scaledPoint)) {
return Cursor.getPredefinedCursor(Cursor.HAND_CURSOR); return Cursor.getPredefinedCursor(Cursor.HAND_CURSOR);
} }
if (controlPointMap != null && !controlPointMap.isEmpty()) { if (controlPointMap != null && !controlPointMap.isEmpty()) {
@@ -175,7 +170,8 @@ public class Presenter implements IPlugInPort {
@Override @Override
public Dimension getCanvasDimensions(boolean useZoom) { public Dimension getCanvasDimensions(boolean useZoom) {
return projectPainter.getCanvasDimensions(currentProject, zoomLevel, useZoom); return drawingManager.getCanvasDimensions(currentProject, drawingManager.getZoomLevel(),
useZoom);
} }
@Override @Override
@@ -302,9 +298,9 @@ public class Presenter implements IPlugInPort {
} else { } else {
componentSlotToDraw = componentSlot; componentSlotToDraw = componentSlot;
} }
projectPainter.drawProject(g2d, currentProject, drawOptions, filter, selectionRect, drawingManager.drawProject(g2d, currentProject, drawOptions, filter, selectionRect,
selectedComponents, groupedComponents, Arrays.asList(controlPointSlot, selectedComponents, groupedComponents, Arrays.asList(controlPointSlot,
potentialControlPoint), componentSlotToDraw, dragInProgress, zoomLevel); potentialControlPoint), componentSlotToDraw, dragInProgress);
} }
@Override @Override
@@ -334,7 +330,7 @@ public class Presenter implements IPlugInPort {
* @return * @return
*/ */
private List<IDIYComponent<?>> findComponentsAt(Point point) { private List<IDIYComponent<?>> findComponentsAt(Point point) {
return projectPainter.findComponentsAt(point, currentProject); return drawingManager.findComponentsAt(point, currentProject);
} }
@Override @Override
@@ -495,7 +491,7 @@ public class Presenter implements IPlugInPort {
if (selectedComponents.contains(component) && componentType.isStretchable() if (selectedComponents.contains(component) && componentType.isStretchable()
&& findAllGroupedComponents(component).size() == 1) { && findAllGroupedComponents(component).size() == 1) {
try { try {
if (scaledPoint.distance(controlPoint) < ProjectPainter.CONTROL_POINT_SIZE) { if (scaledPoint.distance(controlPoint) < DrawingManager.CONTROL_POINT_SIZE) {
Set<Integer> indices = new HashSet<Integer>(); Set<Integer> indices = new HashSet<Integer>();
if (componentType.isStretchable()) { if (componentType.isStretchable()) {
indices.add(pointIndex); indices.add(pointIndex);
@@ -553,7 +549,7 @@ public class Presenter implements IPlugInPort {
} }
@Override @Override
public void dragStarted(Point point) { public void dragStarted(Point point, boolean ctrlDown, boolean shiftDown, boolean altDown) {
LOG.debug(String.format("dragStarted(%s)", point)); LOG.debug(String.format("dragStarted(%s)", point));
dragInProgress = true; dragInProgress = true;
preDragProject = cloner.deepClone(currentProject); preDragProject = cloner.deepClone(currentProject);
@@ -607,9 +603,11 @@ public class Presenter implements IPlugInPort {
} }
} }
// Expand control points to include all stuck components. // Expand control points to include all stuck components.
if (!ctrlDown) {
includeStuckComponents(controlPointMap); includeStuckComponents(controlPointMap);
} }
} }
}
/** /**
* Finds any components that are stuck to one of the components already in * Finds any components that are stuck to one of the components already in
@@ -643,7 +641,7 @@ public class Presenter implements IPlugInPort {
Point secondPoint = entry.getKey().getControlPoint(j); Point secondPoint = entry.getKey().getControlPoint(j);
// If they are close enough we can consider them // If they are close enough we can consider them
// matched. // matched.
if (firstPoint.distance(secondPoint) < ProjectPainter.CONTROL_POINT_SIZE) { if (firstPoint.distance(secondPoint) < DrawingManager.CONTROL_POINT_SIZE) {
componentMatches = true; componentMatches = true;
break; break;
} }
@@ -724,7 +722,7 @@ public class Presenter implements IPlugInPort {
// Update all points. // Update all points.
for (Map.Entry<IDIYComponent<?>, Set<Integer>> entry : controlPointMap.entrySet()) { for (Map.Entry<IDIYComponent<?>, Set<Integer>> entry : controlPointMap.entrySet()) {
IDIYComponent<?> c = entry.getKey(); IDIYComponent<?> c = entry.getKey();
projectPainter.invalidateComponent(c); drawingManager.invalidateComponent(c);
for (Integer index : entry.getValue()) { for (Integer index : entry.getValue()) {
Point p = new Point(c.getControlPoint(index)); Point p = new Point(c.getControlPoint(index));
p.translate(dx, dy); p.translate(dx, dy);
@@ -786,7 +784,7 @@ public class Presenter implements IPlugInPort {
} }
selectedComponents.clear(); selectedComponents.clear();
for (IDIYComponent<?> component : currentProject.getComponents()) { for (IDIYComponent<?> component : currentProject.getComponents()) {
Area area = projectPainter.getComponentArea(component); Area area = drawingManager.getComponentArea(component);
if ((area != null) && (selectionRect != null) && area.intersects(selectionRect)) { if ((area != null) && (selectionRect != null) && area.intersects(selectionRect)) {
selectedComponents.addAll(findAllGroupedComponents(component)); selectedComponents.addAll(findAllGroupedComponents(component));
} }
@@ -844,7 +842,7 @@ public class Presenter implements IPlugInPort {
ungroupComponents(selectedComponents); ungroupComponents(selectedComponents);
// Remove from area map. // Remove from area map.
for (IDIYComponent<?> component : selectedComponents) { for (IDIYComponent<?> component : selectedComponents) {
projectPainter.invalidateComponent(component); drawingManager.invalidateComponent(component);
} }
currentProject.getComponents().removeAll(selectedComponents); currentProject.getComponents().removeAll(selectedComponents);
this.selectedComponents.clear(); this.selectedComponents.clear();
@@ -978,7 +976,7 @@ public class Presenter implements IPlugInPort {
boolean metric = ConfigurationManager.getInstance().readBoolean(METRIC_KEY, true); boolean metric = ConfigurationManager.getInstance().readBoolean(METRIC_KEY, true);
Area area = new Area(); Area area = new Area();
for (IDIYComponent<?> component : selectedComponents) { for (IDIYComponent<?> component : selectedComponents) {
Area componentArea = projectPainter.getComponentArea(component); Area componentArea = drawingManager.getComponentArea(component);
if (componentArea != null) { if (componentArea != null) {
area.add(componentArea); area.add(componentArea);
} }
@@ -1097,7 +1095,7 @@ public class Presenter implements IPlugInPort {
Project oldProject = cloner.deepClone(currentProject); Project oldProject = cloner.deepClone(currentProject);
try { try {
for (IDIYComponent<?> component : selectedComponents) { for (IDIYComponent<?> component : selectedComponents) {
projectPainter.invalidateComponent(component); drawingManager.invalidateComponent(component);
for (PropertyWrapper property : properties) { for (PropertyWrapper property : properties) {
property.writeTo(component); property.writeTo(component);
} }
@@ -1155,8 +1153,7 @@ public class Presenter implements IPlugInPort {
.deepClone(currentProject), "Edit Project"); .deepClone(currentProject), "Edit Project");
projectFileManager.notifyFileChange(); projectFileManager.notifyFileChange();
} }
messageDispatcher.dispatchMessage(EventType.REPAINT); drawingManager.fireZoomChanged();
messageDispatcher.dispatchMessage(EventType.ZOOM_CHANGED, zoomLevel);
} }
} }
@@ -1202,7 +1199,7 @@ public class Presenter implements IPlugInPort {
* @return * @return
*/ */
private Point scalePoint(Point point) { private Point scalePoint(Point point) {
return point == null ? null : new Point((int) (point.x / zoomLevel), return point == null ? null : new Point((int) (point.x / drawingManager.getZoomLevel()),
(int) (point.y / zoomLevel)); (int) (point.y / drawingManager.getZoomLevel()));
} }
} }