Added "Snap To Objects" feature that snaps control points to control

points of the nearest components
This commit is contained in:
bancika
2020-03-23 23:04:02 +01:00
parent 257c7bc3bf
commit a6b7debfd7
8 changed files with 83 additions and 15 deletions
@@ -60,7 +60,8 @@ public interface IPlugInPort extends ISelectionProcessor, IMouseProcessor, IKeyP
public static final String EXPORT_GRID_KEY = "exportGrid";
public static final String STICKY_POINTS_KEY = "stickyPoints";
public static final String METRIC_KEY = "metric";
public static final String SNAP_TO_GRID_KEY = "snapToGrid";
public static final String SNAP_TO_KEY = "snapTo";
public static final String CONTINUOUS_CREATION_KEY = "continuousCreation";
public static final String AUTO_EDIT_KEY = "autoEdit";
public static final String ABNORMAL_EXIT_KEY = "abnormalExit";
@@ -77,6 +78,11 @@ public interface IPlugInPort extends ISelectionProcessor, IMouseProcessor, IKeyP
public static final String EXTRA_SPACE_KEY = "extraSpace";
public static final String FAVORITES_KEY = "favorites";
public static final String SNAP_TO_NONE = "None";
public static final String SNAP_TO_GRID = "Grid";
public static final String SNAP_TO_OBJECTS = "Objects";
public static final String SNAP_TO_DEFAULT = SNAP_TO_GRID;
public static final int DND_TOGGLE_STICKY = 0x1;
public static final int DND_TOGGLE_SNAP = 0x40000000;
@@ -22,7 +22,9 @@
package org.diylc.presenter;
import java.awt.Point;
import java.util.List;
import org.diylc.core.IDIYComponent;
import org.diylc.core.measures.Size;
public class CalcUtils {
@@ -43,4 +45,16 @@ public class CalcUtils {
int y = roundToGrid(point.y, gridSpacing);
point.setLocation(x, y);
}
public static void snapPointToObjects(Point point, Size gridSpacing, IDIYComponent<?> component, List<IDIYComponent<?>> components) {
for (IDIYComponent<?> c : components) {
if (c == component)
continue;
for (int i = 0; i < c.getControlPointCount(); i++)
if (c.isControlPointSticky(i) && point.distance(c.getControlPoint(i)) < gridSpacing.convertToPixels() / 2) {
point.setLocation(c.getControlPoint(i));
return;
}
}
}
}
@@ -740,10 +740,12 @@ public class Presenter implements IPlugInPort {
return false;
}
boolean snapToGrid = ConfigurationManager.getInstance().readBoolean(IPlugInPort.SNAP_TO_GRID_KEY, true);
String snapTo = ConfigurationManager.getInstance().readString(IPlugInPort.SNAP_TO_KEY, IPlugInPort.SNAP_TO_DEFAULT);
if (shiftDown) {
snapToGrid = !snapToGrid;
snapTo = IPlugInPort.SNAP_TO_NONE;
}
boolean snapToGrid = snapTo.equalsIgnoreCase(IPlugInPort.SNAP_TO_GRID);
boolean snapToObjects = snapTo.equalsIgnoreCase(IPlugInPort.SNAP_TO_OBJECTS);
if (altDown) {
Project oldProject = null;
@@ -804,7 +806,7 @@ public class Presenter implements IPlugInPort {
}
Project oldProject = currentProject.clone();
moveComponents(controlPointMap, dx, dy, snapToGrid);
moveComponents(controlPointMap, dx, dy, snapToGrid, snapToObjects);
messageDispatcher.dispatchMessage(EventType.PROJECT_MODIFIED, oldProject, currentProject.clone(), "Move Selection");
messageDispatcher.dispatchMessage(EventType.REPAINT);
return true;
@@ -1009,7 +1011,7 @@ public class Presenter implements IPlugInPort {
int dy = (int) yOffset.convertToPixels();
Project oldProject = currentProject.clone();
moveComponents(controlPointMap, dx, dy, false);
moveComponents(controlPointMap, dx, dy, false, false);
messageDispatcher.dispatchMessage(EventType.PROJECT_MODIFIED, oldProject, currentProject.clone(), "Move Selection");
messageDispatcher.dispatchMessage(EventType.REPAINT);
drawingManager.clearContinuityArea();
@@ -1171,10 +1173,17 @@ public class Presenter implements IPlugInPort {
}
private boolean isSnapToGrid() {
boolean snapToGrid = ConfigurationManager.getInstance().readBoolean(IPlugInPort.SNAP_TO_GRID_KEY, true);
String snapTo = ConfigurationManager.getInstance().readString(IPlugInPort.SNAP_TO_KEY, IPlugInPort.SNAP_TO_DEFAULT);
if (this.dragAction == IPlugInPort.DND_TOGGLE_SNAP)
snapToGrid = !snapToGrid;
return snapToGrid;
return false;
return snapTo.equalsIgnoreCase(IPlugInPort.SNAP_TO_GRID);
}
private boolean isSnapToObjects() {
String snapTo = ConfigurationManager.getInstance().readString(IPlugInPort.SNAP_TO_KEY, IPlugInPort.SNAP_TO_DEFAULT);
if (this.dragAction == IPlugInPort.DND_TOGGLE_SNAP)
return false;
return snapTo.equalsIgnoreCase(IPlugInPort.SNAP_TO_OBJECTS);
}
@Override
@@ -1188,7 +1197,7 @@ public class Presenter implements IPlugInPort {
int dx = (scaledPoint.x - previousDragPoint.x);
int dy = (scaledPoint.y - previousDragPoint.y);
Point actualD = moveComponents(this.controlPointMap, dx, dy, isSnapToGrid());
Point actualD = moveComponents(this.controlPointMap, dx, dy, isSnapToGrid(), isSnapToObjects());
if (actualD == null)
return true;
@@ -1212,7 +1221,7 @@ public class Presenter implements IPlugInPort {
return true;
}
private Point moveComponents(Map<IDIYComponent<?>, Set<Integer>> controlPointMap, int dx, int dy, boolean snapToGrid) {
private Point moveComponents(Map<IDIYComponent<?>, Set<Integer>> controlPointMap, int dx, int dy, boolean snapToGrid, boolean snapToObjects) {
// After we make the transfer and snap to grid, calculate actual dx
// and dy. We'll use them to translate the previous drag point.
int actualDx = 0;
@@ -1232,6 +1241,8 @@ public class Presenter implements IPlugInPort {
testPoint.translate(dx, dy);
if (snapToGrid) {
CalcUtils.snapPointToGrid(testPoint, currentProject.getGridSpacing());
} else if (snapToObjects) {
CalcUtils.snapPointToObjects(testPoint, currentProject.getGridSpacing(), entry.getKey(), currentProject.getComponents());
}
actualDx = testPoint.x - firstPoint.x;
@@ -2714,6 +2714,10 @@
<changeType>NEW_FEATURE</changeType>
<description>New app bundle for Mac OS using appbundler instead of javabundler</description>
</org.diylc.appframework.update.Change>
<org.diylc.appframework.update.Change>
<changeType>NEW_FEATURE</changeType>
<description>Added "Snap To Objects" feature that snaps control points to control points of the nearest components</description>
</org.diylc.appframework.update.Change>
<org.diylc.appframework.update.Change>
<changeType>NEW_FEATURE</changeType>
<description>New Mac OS app icon</description>
Binary file not shown.
Binary file not shown.
@@ -242,6 +242,10 @@ public class ActionFactory {
return new ConfigAction(plugInPort, title, configKey, defaultValue, tipKey);
}
public ToggleAction createToggleAction(String title, String configKey, String groupName, String defaultValue) {
return new ToggleAction(title, configKey, groupName, defaultValue);
}
public ThemeAction createThemeAction(IPlugInPort plugInPort, Theme theme) {
return new ThemeAction(plugInPort, theme);
}
@@ -1576,6 +1580,27 @@ public class ActionFactory {
}
}
public static class ToggleAction extends AbstractAction {
private static final long serialVersionUID = 1L;
private String configKey;
public ToggleAction(String title, String configKey, String groupName, String defaultValue) {
super();
this.configKey = configKey;
putValue(AbstractAction.NAME, title);
putValue(IView.RADIO_BUTTON_GROUP_KEY, groupName);
putValue(AbstractAction.SELECTED_KEY, ConfigurationManager.getInstance().readString(configKey, defaultValue).equalsIgnoreCase(title));
}
@Override
public void actionPerformed(ActionEvent e) {
LOG.info(getValue(AbstractAction.NAME) + " toggle triggered");
ConfigurationManager.getInstance().writeValue(configKey, getValue(AbstractAction.NAME));
}
}
public static class ThemeAction extends AbstractAction {
private static final long serialVersionUID = 1L;
@@ -46,6 +46,7 @@ public class ConfigPlugin implements IPlugIn {
private static final String CONFIG_MENU = "Config";
private static final String THEME_MENU = "Theme";
private static final String SNAP_MENU = "Snap To...";
private static final String COMPONENT_BROWSER_MENU = "Toolbox";
public static final String COMPONENT_BROWSER = "componentBrowser";
public static final String SEARCHABLE_TREE = "Searchable Tree";
@@ -96,12 +97,19 @@ public class ConfigPlugin implements IPlugIn {
swingUI.injectMenuAction(
ActionFactory.getInstance().createConfigAction(plugInPort, "Show Rulers", IPlugInPort.SHOW_RULERS_KEY, true),
CONFIG_MENU);
swingUI.injectSubmenu(SNAP_MENU, null, CONFIG_MENU);
swingUI.injectMenuAction(
ActionFactory.getInstance().createConfigAction(plugInPort, "Show Grid", IPlugInPort.SHOW_GRID_KEY, true),
CONFIG_MENU);
swingUI.injectMenuAction(
ActionFactory.getInstance().createConfigAction(plugInPort, "Snap to Grid", IPlugInPort.SNAP_TO_GRID_KEY, true),
CONFIG_MENU);
ActionFactory.getInstance().createToggleAction("None", IPlugInPort.SNAP_TO_KEY, SNAP_MENU, IPlugInPort.SNAP_TO_DEFAULT),
SNAP_MENU);
swingUI.injectMenuAction(
ActionFactory.getInstance().createToggleAction("Grid", IPlugInPort.SNAP_TO_KEY, SNAP_MENU, IPlugInPort.SNAP_TO_DEFAULT),
SNAP_MENU);
swingUI.injectMenuAction(
ActionFactory.getInstance().createToggleAction("Objects", IPlugInPort.SNAP_TO_KEY, SNAP_MENU, IPlugInPort.SNAP_TO_DEFAULT),
SNAP_MENU);
swingUI.injectMenuAction(
ActionFactory.getInstance()
.createConfigAction(plugInPort, "Sticky Points", IPlugInPort.STICKY_POINTS_KEY, true), CONFIG_MENU);