diff --git a/diylc/diylc-core/src/org/diylc/common/ComponentType.java b/diylc/diylc-core/src/org/diylc/common/ComponentType.java
index 715526bb..8d66ade9 100644
--- a/diylc/diylc-core/src/org/diylc/common/ComponentType.java
+++ b/diylc/diylc-core/src/org/diylc/common/ComponentType.java
@@ -1,148 +1,150 @@
/*
+ *
+ * DIY Layout Creator (DIYLC). Copyright (c) 2009-2018 held jointly by the individual authors.
+ *
+ * This file is part of DIYLC.
+ *
+ * DIYLC is free software: you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License as published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * DIYLC is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
+ * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
+ * Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with DIYLC. If not, see
+ * .
+ */
+package org.diylc.common;
- DIY Layout Creator (DIYLC).
- Copyright (c) 2009-2018 held jointly by the individual authors.
+import javax.swing.Icon;
- This file is part of DIYLC.
+import org.diylc.core.CreationMethod;
+import org.diylc.core.IDIYComponent;
+import org.diylc.core.annotations.BomPolicy;
+import org.diylc.core.annotations.KeywordPolicy;
- DIYLC is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
+/**
+ * Entity class used to describe a component type.
+ *
+ * @author Branislav Stojkovic
+ *
+ * @see IDIYComponent
+ */
+public class ComponentType {
- DIYLC is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
+ private String name;
+ private String description;
+ private CreationMethod creationMethod;
+ private String category;
+ private String namePrefix;
+ private String author;
+ private Icon icon;
+ private Class extends IDIYComponent>> instanceClass;
+ private double zOrder;
+ private boolean flexibleZOrder;
+ private boolean stretchable;
+ private BomPolicy bomPolicy;
+ private boolean autoEdit;
+ private IComponentTransformer transformer;
+ private KeywordPolicy keywordPolicy;
+ private String keywordTag;
+ private boolean continuity;
- You should have received a copy of the GNU General Public License
- along with DIYLC. If not, see .
+ public ComponentType(String name, String description, CreationMethod creationMethod, String category,
+ String namePrefix, String author, Icon icon, Class extends IDIYComponent>> instanceClass, double zOrder,
+ boolean flexibleZOrder, boolean stretchable, BomPolicy bomPolicy, boolean autoEdit,
+ IComponentTransformer transformer, KeywordPolicy keywordPolicy, String keywordTag, boolean continuity) {
+ super();
+ this.name = name;
+ this.description = description;
+ this.creationMethod = creationMethod;
+ this.category = category;
+ this.namePrefix = namePrefix;
+ this.author = author;
+ this.icon = icon;
+ this.instanceClass = instanceClass;
+ this.zOrder = zOrder;
+ this.flexibleZOrder = flexibleZOrder;
+ this.stretchable = stretchable;
+ this.bomPolicy = bomPolicy;
+ this.autoEdit = autoEdit;
+ this.transformer = transformer;
+ this.keywordPolicy = keywordPolicy;
+ this.keywordTag = keywordTag;
+ this.continuity = continuity;
+ }
-*/
-package org.diylc.common;
-
-import javax.swing.Icon;
-
-import org.diylc.core.CreationMethod;
-import org.diylc.core.IDIYComponent;
-import org.diylc.core.annotations.BomPolicy;
-import org.diylc.core.annotations.KeywordPolicy;
-
-/**
- * Entity class used to describe a component type.
- *
- * @author Branislav Stojkovic
- *
- * @see IDIYComponent
- */
-public class ComponentType {
-
- private String name;
- private String description;
- private CreationMethod creationMethod;
- private String category;
- private String namePrefix;
- private String author;
- private Icon icon;
- private Class extends IDIYComponent>> instanceClass;
- private double zOrder;
- private boolean flexibleZOrder;
- private boolean stretchable;
- private BomPolicy bomPolicy;
- private boolean autoEdit;
- private IComponentTransformer transformer;
- private KeywordPolicy keywordPolicy;
- private String keywordTag;
-
- public ComponentType(String name, String description, CreationMethod creationMethod, String category,
- String namePrefix, String author, Icon icon, Class extends IDIYComponent>> instanceClass, double zOrder,
- boolean flexibleZOrder, boolean stretchable, BomPolicy bomPolicy, boolean autoEdit, IComponentTransformer transformer,
- KeywordPolicy keywordPolicy, String keywordTag) {
- super();
- this.name = name;
- this.description = description;
- this.creationMethod = creationMethod;
- this.category = category;
- this.namePrefix = namePrefix;
- this.author = author;
- this.icon = icon;
- this.instanceClass = instanceClass;
- this.zOrder = zOrder;
- this.flexibleZOrder = flexibleZOrder;
- this.stretchable = stretchable;
- this.bomPolicy = bomPolicy;
- this.autoEdit = autoEdit;
- this.transformer = transformer;
- this.keywordPolicy = keywordPolicy;
- this.keywordTag = keywordTag;
- }
-
- public String getName() {
- return name;
- }
-
- public String getDescription() {
- return description;
- }
-
- public CreationMethod getCreationMethod() {
- return creationMethod;
- }
-
- public String getCategory() {
- return category;
- }
-
- public String getNamePrefix() {
- return namePrefix;
- }
-
- public String getAuthor() {
- return author;
- }
-
- public Icon getIcon() {
- return icon;
- }
-
- public Class extends IDIYComponent>> getInstanceClass() {
- return instanceClass;
- }
-
- public double getZOrder() {
- return zOrder;
- }
-
- public boolean isFlexibleZOrder() {
- return flexibleZOrder;
- }
-
- public boolean isStretchable() {
- return stretchable;
- }
-
- public BomPolicy getBomPolicy() {
- return bomPolicy;
- }
-
- public boolean isAutoEdit() {
- return autoEdit;
- }
-
- public IComponentTransformer getTransformer() {
- return transformer;
- }
-
- public KeywordPolicy getKeywordPolicy() {
- return keywordPolicy;
- }
-
- public String getKeywordTag() {
- return keywordTag;
- }
-
- @Override
- public String toString() {
- return name;
- }
-}
+ public String getName() {
+ return name;
+ }
+
+ public String getDescription() {
+ return description;
+ }
+
+ public CreationMethod getCreationMethod() {
+ return creationMethod;
+ }
+
+ public String getCategory() {
+ return category;
+ }
+
+ public String getNamePrefix() {
+ return namePrefix;
+ }
+
+ public String getAuthor() {
+ return author;
+ }
+
+ public Icon getIcon() {
+ return icon;
+ }
+
+ public Class extends IDIYComponent>> getInstanceClass() {
+ return instanceClass;
+ }
+
+ public double getZOrder() {
+ return zOrder;
+ }
+
+ public boolean isFlexibleZOrder() {
+ return flexibleZOrder;
+ }
+
+ public boolean isStretchable() {
+ return stretchable;
+ }
+
+ public BomPolicy getBomPolicy() {
+ return bomPolicy;
+ }
+
+ public boolean isAutoEdit() {
+ return autoEdit;
+ }
+
+ public IComponentTransformer getTransformer() {
+ return transformer;
+ }
+
+ public KeywordPolicy getKeywordPolicy() {
+ return keywordPolicy;
+ }
+
+ public String getKeywordTag() {
+ return keywordTag;
+ }
+
+ public boolean isContinuity() {
+ return continuity;
+ }
+
+ @Override
+ public String toString() {
+ return name;
+ }
+}
diff --git a/diylc/diylc-core/src/org/diylc/common/IPlugInPort.java b/diylc/diylc-core/src/org/diylc/common/IPlugInPort.java
index dc51c980..f25c8d5d 100644
--- a/diylc/diylc-core/src/org/diylc/common/IPlugInPort.java
+++ b/diylc/diylc-core/src/org/diylc/common/IPlugInPort.java
@@ -70,7 +70,8 @@ public interface IPlugInPort extends ISelectionProcessor, IMouseProcessor, IKeyP
public static final String RECENT_COMPONENTS_KEY = "recentComponents";
public static final String RECENT_FILES_KEY = "recentFiles";
public static final String SHOW_RULERS_KEY = "showRulers";
- public static final String SHOW_GRID_KEY = "showGrid";
+ public static final String SHOW_GRID_KEY = "showGrid";
+ public static final String HIGHLIGHT_CONTINUITY_AREA = "highlightContinuityArea";
public static final int DND_TOGGLE_STICKY = 0x1;
public static final int DND_TOGGLE_SNAP = 0x40000000;
diff --git a/diylc/diylc-core/src/org/diylc/components/AbstractCurvedComponent.java b/diylc/diylc-core/src/org/diylc/components/AbstractCurvedComponent.java
index abe220e6..1d5b040f 100644
--- a/diylc/diylc-core/src/org/diylc/components/AbstractCurvedComponent.java
+++ b/diylc/diylc-core/src/org/diylc/components/AbstractCurvedComponent.java
@@ -61,7 +61,7 @@ public abstract class AbstractCurvedComponent extends AbstractTransparentComp
* @param componentState
* @param theme
*/
- protected abstract void drawCurve(CubicCurve2D curve, Graphics2D g2d, ComponentState componentState);
+ protected abstract void drawCurve(CubicCurve2D curve, Graphics2D g2d, ComponentState componentState, IDrawingObserver drawingObserver);
/**
* @return default color.
@@ -110,7 +110,7 @@ public abstract class AbstractCurvedComponent extends AbstractTransparentComp
// g2d.setColor(color);
// g2d.setStroke(new BasicStroke(thickness - 2));
// g2d.draw(path);
- drawCurve(curve, g2d, componentState);
+ drawCurve(curve, g2d, componentState, drawingObserver);
g2d.setComposite(oldComposite);
}
diff --git a/diylc/diylc-core/src/org/diylc/components/AbstractLeadedComponent.java b/diylc/diylc-core/src/org/diylc/components/AbstractLeadedComponent.java
index 42c10cd9..8805dfa2 100644
--- a/diylc/diylc-core/src/org/diylc/components/AbstractLeadedComponent.java
+++ b/diylc/diylc-core/src/org/diylc/components/AbstractLeadedComponent.java
@@ -32,7 +32,8 @@ import java.awt.Shape;
import java.awt.geom.AffineTransform;
import java.awt.geom.Ellipse2D;
import java.awt.geom.Rectangle2D;
-
+import java.util.Observable;
+
import org.diylc.appframework.miscutils.ConfigurationManager;
import org.diylc.common.Display;
import org.diylc.common.IPlugInPort;
@@ -84,6 +85,10 @@ public abstract class AbstractLeadedComponent extends AbstractTransparentComp
} catch (NullPointerException e) {
// This will happen if components do not have any shape.
}
+ }
+
+ protected boolean IsCopperArea() {
+ return false;
}
@Override
@@ -93,7 +98,7 @@ public abstract class AbstractLeadedComponent extends AbstractTransparentComp
Shape shape = getBodyShape();
// If there's no body, just draw the line connecting the ending points.
if (shape == null) {
- drawLead(g2d, componentState);
+ drawLead(g2d, componentState, drawingObserver, IsCopperArea());
} else if (supportsStandingMode() && length.convertToPixels() > points[0].distance(points[1])) {
// When ending points are too close draw the component in standing
// mode.
@@ -124,7 +129,7 @@ public abstract class AbstractLeadedComponent extends AbstractTransparentComp
g2d.setColor(finalBorderColor);
g2d.draw(body);
if (!outlineMode) {
- drawLead(g2d, componentState);
+ drawLead(g2d, componentState, drawingObserver, false);
}
} else {
// Normal mode with component body in the center and two lead parts.
@@ -293,12 +298,17 @@ public abstract class AbstractLeadedComponent extends AbstractTransparentComp
g2d.drawLine(points[1].x, points[1].y, endX, endY);
}
- private void drawLead(Graphics2D g2d, ComponentState componentState) {
+ private void drawLead(Graphics2D g2d, ComponentState componentState, IDrawingObserver observer, boolean isCopperArea) {
+ if (isCopperArea)
+ observer.startTrackingContinuityArea(true);
g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(getLeadThickness()));
Color leadColor =
shouldShadeLeads() ? getLeadColorForPainting(componentState).darker() : getLeadColorForPainting(componentState);
g2d.setColor(leadColor);
- g2d.drawLine(points[0].x, points[0].y, points[1].x, points[1].y);
+ g2d.drawLine(points[0].x, points[0].y, points[1].x, points[1].y);
+
+ if (isCopperArea)
+ observer.stopTrackingContinuityArea();
if (shouldShadeLeads()) {
g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(getLeadThickness() - 2));
diff --git a/diylc/diylc-core/src/org/diylc/core/IDrawingObserver.java b/diylc/diylc-core/src/org/diylc/core/IDrawingObserver.java
index 4a476b7d..0ee8ac6a 100644
--- a/diylc/diylc-core/src/org/diylc/core/IDrawingObserver.java
+++ b/diylc/diylc-core/src/org/diylc/core/IDrawingObserver.java
@@ -31,5 +31,9 @@ public interface IDrawingObserver {
void stopTracking();
- void startTracking();
+ void startTracking();
+
+ void stopTrackingContinuityArea();
+
+ void startTrackingContinuityArea(boolean positive);
}
diff --git a/diylc/diylc-core/src/org/diylc/core/annotations/ComponentDescriptor.java b/diylc/diylc-core/src/org/diylc/core/annotations/ComponentDescriptor.java
index 4ba7121d..53b0b567 100644
--- a/diylc/diylc-core/src/org/diylc/core/annotations/ComponentDescriptor.java
+++ b/diylc/diylc-core/src/org/diylc/core/annotations/ComponentDescriptor.java
@@ -116,6 +116,13 @@ public @interface ComponentDescriptor {
*
* @return
*/
- String keywordTag() default "";
+ String keywordTag() default "";
+
+ /**
+ * For components that show continuity between the two ending points, e.d. wires, jumpers, etc.
+ *
+ * @return
+ */
+ boolean continuity() default false;
}
diff --git a/diylc/diylc-core/src/org/diylc/presenter/ComponentArea.java b/diylc/diylc-core/src/org/diylc/presenter/ComponentArea.java
new file mode 100644
index 00000000..56297194
--- /dev/null
+++ b/diylc/diylc-core/src/org/diylc/presenter/ComponentArea.java
@@ -0,0 +1,51 @@
+/*
+
+ DIY Layout Creator (DIYLC).
+ Copyright (c) 2009-2018 held jointly by the individual authors.
+
+ This file is part of DIYLC.
+
+ DIYLC is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ DIYLC is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with DIYLC. If not, see .
+
+*/
+package org.diylc.presenter;
+
+import java.awt.geom.Area;
+import java.util.List;
+
+public class ComponentArea {
+
+ private Area outlineArea;
+ private List continuityPositiveAreas;
+ private List continuityNegativeAreas;
+
+ public ComponentArea(Area outlineArea, List continuityPositiveAreas, List continuityNegativeAreas) {
+ super();
+ this.outlineArea = outlineArea;
+ this.continuityPositiveAreas = continuityPositiveAreas;
+ this.continuityNegativeAreas = continuityNegativeAreas;
+ }
+
+ public Area getOutlineArea() {
+ return outlineArea;
+ }
+
+ public List getContinuityPositiveAreas() {
+ return continuityPositiveAreas;
+ }
+
+ public List getContinuityNegativeAreas() {
+ return continuityNegativeAreas;
+ }
+}
diff --git a/diylc/diylc-core/src/org/diylc/presenter/ComponentProcessor.java b/diylc/diylc-core/src/org/diylc/presenter/ComponentProcessor.java
index 383192ff..e241c18d 100644
--- a/diylc/diylc-core/src/org/diylc/presenter/ComponentProcessor.java
+++ b/diylc/diylc-core/src/org/diylc/presenter/ComponentProcessor.java
@@ -97,7 +97,8 @@ public class ComponentProcessor {
boolean autoEdit;
IComponentTransformer transformer;
KeywordPolicy keywordPolicy;
- String keywordTag;
+ String keywordTag;
+ boolean continuity;
if (clazz.isAnnotationPresent(ComponentDescriptor.class)) {
ComponentDescriptor annotation = clazz.getAnnotation(ComponentDescriptor.class);
name = annotation.name();
@@ -113,7 +114,8 @@ public class ComponentProcessor {
autoEdit = annotation.autoEdit();
transformer = getComponentTransformer(annotation.transformer());
keywordPolicy = annotation.keywordPolicy();
- keywordTag = annotation.keywordTag();
+ keywordTag = annotation.keywordTag();
+ continuity = annotation.continuity();
} else { // default
name = clazz.getSimpleName();
description = "";
@@ -128,7 +130,8 @@ public class ComponentProcessor {
autoEdit = true;
transformer = null;
keywordPolicy = KeywordPolicy.NEVER_SHOW;
- keywordTag = null;
+ keywordTag = null;
+ continuity = false;
}
icon = null;
// Draw component icon.
@@ -148,7 +151,7 @@ public class ComponentProcessor {
}
ComponentType componentType =
new ComponentType(name, description, creationMethod, category, namePrefix, author, icon, clazz, zOrder,
- flexibleZOrder, stretchable, bomPolicy, autoEdit, transformer, keywordPolicy, keywordTag);
+ flexibleZOrder, stretchable, bomPolicy, autoEdit, transformer, keywordPolicy, keywordTag, continuity);
componentTypeMap.put(clazz.getName(), componentType);
return componentType;
}
diff --git a/diylc/diylc-core/src/org/diylc/presenter/DrawingManager.java b/diylc/diylc-core/src/org/diylc/presenter/DrawingManager.java
index 526bd5fb..e4d3ef3d 100644
--- a/diylc/diylc-core/src/org/diylc/presenter/DrawingManager.java
+++ b/diylc/diylc-core/src/org/diylc/presenter/DrawingManager.java
@@ -1,403 +1,591 @@
/*
+ *
+ * DIY Layout Creator (DIYLC). Copyright (c) 2009-2018 held jointly by the individual authors.
+ *
+ * This file is part of DIYLC.
+ *
+ * DIYLC is free software: you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License as published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * DIYLC is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
+ * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
+ * Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with DIYLC. If not, see
+ * .
+ */
+package org.diylc.presenter;
- DIY Layout Creator (DIYLC).
- Copyright (c) 2009-2018 held jointly by the individual authors.
+import java.awt.AlphaComposite;
+import java.awt.BasicStroke;
+import java.awt.Color;
+import java.awt.Composite;
+import java.awt.Dimension;
+import java.awt.Graphics2D;
+import java.awt.Point;
+import java.awt.Rectangle;
+import java.awt.RenderingHints;
+import java.awt.geom.Area;
+import java.awt.geom.Path2D;
+import java.awt.geom.PathIterator;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
- This file is part of DIYLC.
+import org.apache.log4j.Logger;
+import org.diylc.appframework.miscutils.ConfigurationManager;
+import org.diylc.appframework.simplemq.MessageDispatcher;
+import org.diylc.common.ComponentType;
+import org.diylc.common.DrawOption;
+import org.diylc.common.EventType;
+import org.diylc.common.GridType;
+import org.diylc.common.IComponentFiler;
+import org.diylc.common.IPlugInPort;
+import org.diylc.common.ObjectCache;
+import org.diylc.core.ComponentState;
+import org.diylc.core.IDIYComponent;
+import org.diylc.core.Project;
+import org.diylc.core.Theme;
+import org.diylc.core.VisibilityPolicy;
+import org.diylc.utils.Constants;
- DIYLC is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
+/**
+ * Utility that deals with painting {@link Project} on the {@link Graphics2D} and keeps areas taken
+ * by each drawn component.
+ *
+ * @author Branislav Stojkovic
+ */
+public class DrawingManager {
- DIYLC is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
+ private static final Logger LOG = Logger.getLogger(DrawingManager.class);
- You should have received a copy of the GNU General Public License
- along with DIYLC. If not, see .
+ public static int CONTROL_POINT_SIZE = 7;
-*/
-package org.diylc.presenter;
-
-import java.awt.AlphaComposite;
-import java.awt.BasicStroke;
-import java.awt.Color;
-import java.awt.Composite;
-import java.awt.Dimension;
-import java.awt.Graphics2D;
-import java.awt.Point;
-import java.awt.Rectangle;
-import java.awt.RenderingHints;
-import java.awt.geom.Area;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
-import org.apache.log4j.Logger;
-import org.diylc.appframework.miscutils.ConfigurationManager;
-import org.diylc.appframework.simplemq.MessageDispatcher;
-import org.diylc.common.DrawOption;
-import org.diylc.common.EventType;
-import org.diylc.common.GridType;
-import org.diylc.common.IComponentFiler;
-import org.diylc.common.IPlugInPort;
-import org.diylc.common.ObjectCache;
-import org.diylc.core.ComponentState;
-import org.diylc.core.IDIYComponent;
-import org.diylc.core.Project;
-import org.diylc.core.Theme;
-import org.diylc.core.VisibilityPolicy;
-import org.diylc.utils.Constants;
-
-/**
- * Utility that deals with painting {@link Project} on the {@link Graphics2D} and keeps areas taken
- * by each drawn component.
- *
- * @author Branislav Stojkovic
- */
-public class DrawingManager {
-
- private static final Logger LOG = Logger.getLogger(DrawingManager.class);
-
- public static int CONTROL_POINT_SIZE = 7;
-
- public static final String ZOOM_KEY = "zoom";
-
- public static String DEBUG_COMPONENT_AREAS = "org.diylc.debugComponentAreas";
-
- public static Color CONTROL_POINT_COLOR = Color.blue;
- public static Color SELECTED_CONTROL_POINT_COLOR = Color.green;
-
- private Theme theme = (Theme) ConfigurationManager.getInstance().readObject(IPlugInPort.THEME_KEY,
- Constants.DEFAULT_THEME);
-
- // Keeps Area object of each drawn component.
- private Map, Area> componentAreaMap;
- // Maps components to the last state they are drawn in. Also, used to
- // determine which components are invalidated when they are not in the map.
- private Map, ComponentState> lastDrawnStateMap;
-
- private Composite slotComposite = AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.3f);
- private Composite lockedComposite = AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.3f);
- private List> failedComponents = new ArrayList>();
-
- private double zoomLevel = 1d;// ConfigurationManager.getInstance().readDouble(ZOOM_KEY,
- // 1d);
-
- private MessageDispatcher messageDispatcher;
-
- private boolean debugComponentAreas;
-
- public DrawingManager(MessageDispatcher messageDispatcher) {
- super();
- this.messageDispatcher = messageDispatcher;
- componentAreaMap = new HashMap, Area>();
- lastDrawnStateMap = new HashMap, ComponentState>();
- String debugComponentAreasStr = System.getProperty(DEBUG_COMPONENT_AREAS);
- debugComponentAreas = debugComponentAreasStr != null && debugComponentAreasStr.equalsIgnoreCase("true");
- }
-
- /**
- * Paints the project onto the canvas and returns the list of components that failed to draw.
- *
- * @param g2d
- * @param project
- * @param drawOptions
- * @param filter
- * @param selectionRect
- * @param selectedComponents
- * @param lockedComponents
- * @param groupedComponents
- * @param controlPointSlot
- * @param componentSlot
- * @param dragInProgress
- * @return
- */
- public List> drawProject(Graphics2D g2d, Project project, Set drawOptions,
- IComponentFiler filter, Rectangle selectionRect, Collection> selectedComponents,
- Set> lockedComponents, Set> groupedComponents, List controlPointSlot,
- List> componentSlot, boolean dragInProgress) {
- failedComponents.clear();
- if (project == null) {
- return failedComponents;
- }
-
- double zoom = 1d;
- if (drawOptions.contains(DrawOption.ZOOM)) {
- zoom = zoomLevel;
- } else {
- zoom = 1 / Constants.PIXEL_SIZE;
- }
-
- G2DWrapper g2dWrapper = new G2DWrapper(g2d, zoom);
-
- if (drawOptions.contains(DrawOption.ANTIALIASING)) {
- g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
- g2d.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
- } else {
- g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_OFF);
- g2d.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_OFF);
- }
- if (ConfigurationManager.getInstance().readBoolean(IPlugInPort.HI_QUALITY_RENDER_KEY, false)) {
- g2d.setRenderingHint(RenderingHints.KEY_ALPHA_INTERPOLATION, RenderingHints.VALUE_ALPHA_INTERPOLATION_QUALITY);
- g2d.setRenderingHint(RenderingHints.KEY_COLOR_RENDERING, RenderingHints.VALUE_COLOR_RENDER_QUALITY);
- g2d.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
- g2d.setRenderingHint(RenderingHints.KEY_DITHERING, RenderingHints.VALUE_DITHER_ENABLE);
- g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
- // g2d.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL,
- // RenderingHints.VALUE_STROKE_PURE);
- } else {
- g2d.setRenderingHint(RenderingHints.KEY_ALPHA_INTERPOLATION, RenderingHints.VALUE_ALPHA_INTERPOLATION_SPEED);
- g2d.setRenderingHint(RenderingHints.KEY_COLOR_RENDERING, RenderingHints.VALUE_COLOR_RENDER_SPEED);
- g2d.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_SPEED);
- g2d.setRenderingHint(RenderingHints.KEY_DITHERING, RenderingHints.VALUE_DITHER_DISABLE);
- g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_NEAREST_NEIGHBOR);
- }
-
- // AffineTransform initialTx = g2d.getTransform();
- Dimension d = getCanvasDimensions(project, zoom, true);
-
- g2dWrapper.setColor(theme.getBgColor());
- g2dWrapper.fillRect(0, 0, d.width, d.height);
- g2d.clip(new Rectangle(new Point(0, 0), d));
-
- GridType gridType = GridType.LINES;
- if (drawOptions.contains(DrawOption.GRID) && gridType != GridType.NONE) {
- double zoomStep = project.getGridSpacing().convertToPixels() * zoom;
- if (gridType == GridType.CROSSHAIR) {
- g2d.setStroke(new BasicStroke(1f, BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER, 10f, new float[] {
- (float) zoomStep / 2, (float) zoomStep / 2}, (float) zoomStep / 4));
- } else if (gridType == GridType.DOT) {
- g2d.setStroke(new BasicStroke(1f, BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER, 10f, new float[] {1f,
- (float) zoomStep - 1}, 0f));
- }
-
- g2dWrapper.setColor(theme.getGridColor());
- for (double i = zoomStep; i < d.width; i += zoomStep) {
- g2dWrapper.drawLine((int) i, 0, (int) i, d.height - 1);
- }
- for (double j = zoomStep; j < d.height; j += zoomStep) {
- g2dWrapper.drawLine(0, (int) j, d.width - 1, (int) j);
- }
- }
-
- if (Math.abs(1.0 - zoom) > 1e-4) {
- g2dWrapper.scale(zoom, zoom);
- }
-
- // Composite mainComposite = g2d.getComposite();
- // Composite alphaComposite =
- // AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.5f);
-
- // g2dWrapper.resetTx();
-
- // componentAreaMap.clear();
- for (IDIYComponent> component : project.getComponents()) {
- // Do not draw the component if it's filtered out.
- if (filter != null && !filter.testComponent(component)) {
- continue;
- }
- ComponentState state = ComponentState.NORMAL;
- if (drawOptions.contains(DrawOption.SELECTION) && selectedComponents.contains(component)) {
- if (dragInProgress) {
- state = ComponentState.DRAGGING;
- } else {
- state = ComponentState.SELECTED;
- }
- }
- // Do not track the area if component is not invalidated and was
- // drawn in the same state.
- boolean trackArea = lastDrawnStateMap.get(component) != state;
-
- synchronized (g2d) {
- g2dWrapper.startedDrawingComponent();
- if (!trackArea) {
- g2dWrapper.stopTracking();
- }
- // Draw locked components in a new composite.
- if (lockedComponents.contains(component)) {
- g2d.setComposite(lockedComposite);
- }
- // Draw the component through the g2dWrapper.
- try {
- component.draw(g2dWrapper, state, drawOptions.contains(DrawOption.OUTLINE_MODE), project, g2dWrapper);
- } catch (Exception e) {
- LOG.error("Error drawing " + component.getName(), e);
- failedComponents.add(component);
- }
- Area area = g2dWrapper.finishedDrawingComponent();
- if (trackArea && area != null && !area.isEmpty()) {
- componentAreaMap.put(component, area);
- lastDrawnStateMap.put(component, state);
- }
- }
- }
-
- // Draw control points.
- if (drawOptions.contains(DrawOption.CONTROL_POINTS)) {
- // Draw unselected points first to make sure they are below.
- if (dragInProgress || drawOptions.contains(DrawOption.OUTLINE_MODE)) {
- for (IDIYComponent> component : project.getComponents()) {
- for (int i = 0; i < component.getControlPointCount(); i++) {
- VisibilityPolicy visibilityPolicy = component.getControlPointVisibilityPolicy(i);
- if ((groupedComponents.contains(component)
- && (visibilityPolicy == VisibilityPolicy.ALWAYS || (selectedComponents.contains(component) && visibilityPolicy == VisibilityPolicy.WHEN_SELECTED)) || (!groupedComponents
- .contains(component) && !selectedComponents.contains(component) && component
- .getControlPointVisibilityPolicy(i) == VisibilityPolicy.ALWAYS))) {
- g2dWrapper.setColor(CONTROL_POINT_COLOR);
- Point controlPoint = component.getControlPoint(i);
- int pointSize = CONTROL_POINT_SIZE - 2;
- g2dWrapper.fillOval(controlPoint.x - pointSize / 2, controlPoint.y - pointSize / 2, pointSize, pointSize);
- }
- }
- }
- }
- // Then draw the selected ones.
- for (IDIYComponent> component : selectedComponents) {
- for (int i = 0; i < component.getControlPointCount(); i++) {
- if (!groupedComponents.contains(component)
- && (component.getControlPointVisibilityPolicy(i) == VisibilityPolicy.WHEN_SELECTED || component
- .getControlPointVisibilityPolicy(i) == VisibilityPolicy.ALWAYS)) {
-
- Point controlPoint = component.getControlPoint(i);
- int pointSize = CONTROL_POINT_SIZE;
-
- g2dWrapper.setColor(SELECTED_CONTROL_POINT_COLOR.darker());
- g2dWrapper.fillOval(controlPoint.x - pointSize / 2, controlPoint.y - pointSize / 2, pointSize, pointSize);
- g2dWrapper.setColor(SELECTED_CONTROL_POINT_COLOR);
- g2dWrapper.fillOval(controlPoint.x - CONTROL_POINT_SIZE / 2 + 1, controlPoint.y - CONTROL_POINT_SIZE / 2
- + 1, CONTROL_POINT_SIZE - 2, CONTROL_POINT_SIZE - 2);
- }
- }
- }
- }
-
- // Draw component slot in a separate composite.
- if (componentSlot != null) {
- g2dWrapper.startedDrawingComponent();
- g2dWrapper.setComposite(slotComposite);
- for (IDIYComponent> component : componentSlot) {
- try {
-
- component.draw(g2dWrapper, ComponentState.NORMAL, drawOptions.contains(DrawOption.OUTLINE_MODE), project,
- g2dWrapper);
-
- } catch (Exception e) {
- LOG.error("Error drawing " + component.getName(), e);
- failedComponents.add(component);
- }
- }
- g2dWrapper.finishedDrawingComponent();
- }
-
- // Draw control points of the component in the slot.
- if (controlPointSlot != null) {
- for (Point point : controlPointSlot) {
- if (point != null) {
- g2dWrapper.setColor(SELECTED_CONTROL_POINT_COLOR.darker());
- g2dWrapper.fillOval(point.x - CONTROL_POINT_SIZE / 2, point.y - CONTROL_POINT_SIZE / 2, CONTROL_POINT_SIZE,
- CONTROL_POINT_SIZE);
- g2dWrapper.setColor(SELECTED_CONTROL_POINT_COLOR);
- g2dWrapper.fillOval(point.x - CONTROL_POINT_SIZE / 2 + 1, point.y - CONTROL_POINT_SIZE / 2 + 1,
- CONTROL_POINT_SIZE - 2, CONTROL_POINT_SIZE - 2);
- }
- }
- }
-
- // Go back to the original transformation and zoom in to draw the
- // selection rectangle and other similar elements.
- // g2d.setTransform(initialTx);
- // if ((drawOptions.contains(DrawOption.ZOOM)) && (Math.abs(1.0 -
- // zoomLevel) > 1e-4)) {
- // g2d.scale(zoomLevel, zoomLevel);
- // }
-
- // At the end draw selection rectangle if needed.
- if (drawOptions.contains(DrawOption.SELECTION) && (selectionRect != null)) {
- g2d.setColor(Color.white);
- g2d.draw(selectionRect);
- g2d.setColor(Color.black);
- g2d.setStroke(Constants.DASHED_STROKE);
- g2d.draw(selectionRect);
- }
-
- // Draw component area for test
- if (debugComponentAreas) {
- g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(1));
- g2d.setColor(Color.red);
- for (Area area : componentAreaMap.values()) {
- g2d.draw(area);
- }
- }
-
- return failedComponents;
- }
-
- 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) {
- componentAreaMap.remove(component);
- lastDrawnStateMap.remove(component);
- }
-
- public Area getComponentArea(IDIYComponent> component) {
- return componentAreaMap.get(component);
- }
-
- public void clearComponentAreaMap() {
- componentAreaMap.clear();
- lastDrawnStateMap.clear();
- }
-
- public List> findComponentsAt(Point point, Project project) {
- List> components = new ArrayList>();
- for (int i = 0; i < project.getComponents().size(); i++) {
- Area area = componentAreaMap.get(project.getComponents().get(i));
- if (area != null && area.contains(point)) {
- components.add(0, project.getComponents().get(i));
- }
- }
- return components;
- }
-
- public Dimension getCanvasDimensions(Project project, Double zoomLevel, boolean useZoom) {
- double width = project.getWidth().convertToPixels();
- double height = project.getHeight().convertToPixels();
- if (useZoom) {
- width *= zoomLevel;
- height *= zoomLevel;
- } else {
- width /= Constants.PIXEL_SIZE;
- height /= Constants.PIXEL_SIZE;
- }
- return new Dimension((int) width, (int) height);
- }
-
- public void fireZoomChanged() {
- messageDispatcher.dispatchMessage(EventType.ZOOM_CHANGED, zoomLevel);
- messageDispatcher.dispatchMessage(EventType.REPAINT);
- }
-
- public Theme getTheme() {
- return theme;
- }
-
- public void setTheme(Theme theme) {
- this.theme = theme;
- ConfigurationManager.getInstance().writeValue(IPlugInPort.THEME_KEY, theme);
- messageDispatcher.dispatchMessage(EventType.REPAINT);
- }
-}
+ public static final String ZOOM_KEY = "zoom";
+
+ public static String DEBUG_COMPONENT_AREAS = "org.diylc.debugComponentAreas";
+ public static String DEBUG_CONTINUITY_AREAS = "org.diylc.debugContinuityAreas";
+
+ public static Color CONTROL_POINT_COLOR = Color.blue;
+ public static Color SELECTED_CONTROL_POINT_COLOR = Color.green;
+
+ private Theme theme = (Theme) ConfigurationManager.getInstance().readObject(IPlugInPort.THEME_KEY,
+ Constants.DEFAULT_THEME);
+
+ // Keeps Area object of each drawn component.
+ private Map, ComponentArea> componentAreaMap;
+ // Maps components to the last state they are drawn in. Also, used to
+ // determine which components are invalidated when they are not in the map.
+ private Map, ComponentState> lastDrawnStateMap;
+
+ private Area continuityArea;
+
+ private Composite slotComposite = AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.3f);
+ private Composite lockedComposite = AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.3f);
+ private List> failedComponents = new ArrayList>();
+
+ private double zoomLevel = 1d;// ConfigurationManager.getInstance().readDouble(ZOOM_KEY,
+ // 1d);
+
+ private MessageDispatcher messageDispatcher;
+
+ private boolean debugComponentAreas;
+ private boolean debugContinuityAreas;
+
+ public DrawingManager(MessageDispatcher messageDispatcher) {
+ super();
+ this.messageDispatcher = messageDispatcher;
+ componentAreaMap = new HashMap, ComponentArea>();
+ lastDrawnStateMap = new HashMap, ComponentState>();
+ String debugComponentAreasStr = System.getProperty(DEBUG_COMPONENT_AREAS);
+ debugComponentAreas = debugComponentAreasStr != null && debugComponentAreasStr.equalsIgnoreCase("true");
+
+ String debugContinuityAreasStr = System.getProperty(DEBUG_CONTINUITY_AREAS);
+ debugContinuityAreas = debugContinuityAreasStr != null && debugContinuityAreasStr.equalsIgnoreCase("true");
+ }
+
+ /**
+ * Paints the project onto the canvas and returns the list of components that failed to draw.
+ *
+ * @param g2d
+ * @param project
+ * @param drawOptions
+ * @param filter
+ * @param selectionRect
+ * @param selectedComponents
+ * @param lockedComponents
+ * @param groupedComponents
+ * @param controlPointSlot
+ * @param componentSlot
+ * @param dragInProgress
+ * @return
+ */
+ public List> drawProject(Graphics2D g2d, Project project, Set drawOptions,
+ IComponentFiler filter, Rectangle selectionRect, Collection> selectedComponents,
+ Set> lockedComponents, Set> groupedComponents, List controlPointSlot,
+ List> componentSlot, boolean dragInProgress) {
+ failedComponents.clear();
+ if (project == null) {
+ return failedComponents;
+ }
+
+ double zoom = 1d;
+ if (drawOptions.contains(DrawOption.ZOOM)) {
+ zoom = zoomLevel;
+ } else {
+ zoom = 1 / Constants.PIXEL_SIZE;
+ }
+
+ G2DWrapper g2dWrapper = new G2DWrapper(g2d, zoom);
+
+ if (drawOptions.contains(DrawOption.ANTIALIASING)) {
+ g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
+ g2d.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
+ } else {
+ g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_OFF);
+ g2d.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_OFF);
+ }
+ if (ConfigurationManager.getInstance().readBoolean(IPlugInPort.HI_QUALITY_RENDER_KEY, false)) {
+ g2d.setRenderingHint(RenderingHints.KEY_ALPHA_INTERPOLATION, RenderingHints.VALUE_ALPHA_INTERPOLATION_QUALITY);
+ g2d.setRenderingHint(RenderingHints.KEY_COLOR_RENDERING, RenderingHints.VALUE_COLOR_RENDER_QUALITY);
+ g2d.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
+ g2d.setRenderingHint(RenderingHints.KEY_DITHERING, RenderingHints.VALUE_DITHER_ENABLE);
+ g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
+ // g2d.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL,
+ // RenderingHints.VALUE_STROKE_PURE);
+ } else {
+ g2d.setRenderingHint(RenderingHints.KEY_ALPHA_INTERPOLATION, RenderingHints.VALUE_ALPHA_INTERPOLATION_SPEED);
+ g2d.setRenderingHint(RenderingHints.KEY_COLOR_RENDERING, RenderingHints.VALUE_COLOR_RENDER_SPEED);
+ g2d.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_SPEED);
+ g2d.setRenderingHint(RenderingHints.KEY_DITHERING, RenderingHints.VALUE_DITHER_DISABLE);
+ g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_NEAREST_NEIGHBOR);
+ }
+
+ // AffineTransform initialTx = g2d.getTransform();
+ Dimension d = getCanvasDimensions(project, zoom, true);
+
+ g2dWrapper.setColor(theme.getBgColor());
+ g2dWrapper.fillRect(0, 0, d.width, d.height);
+ g2d.clip(new Rectangle(new Point(0, 0), d));
+
+ GridType gridType = GridType.LINES;
+ if (drawOptions.contains(DrawOption.GRID) && gridType != GridType.NONE) {
+ double zoomStep = project.getGridSpacing().convertToPixels() * zoom;
+ if (gridType == GridType.CROSSHAIR) {
+ g2d.setStroke(new BasicStroke(1f, BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER, 10f, new float[] {
+ (float) zoomStep / 2, (float) zoomStep / 2}, (float) zoomStep / 4));
+ } else if (gridType == GridType.DOT) {
+ g2d.setStroke(new BasicStroke(1f, BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER, 10f, new float[] {1f,
+ (float) zoomStep - 1}, 0f));
+ }
+
+ g2dWrapper.setColor(theme.getGridColor());
+ for (double i = zoomStep; i < d.width; i += zoomStep) {
+ g2dWrapper.drawLine((int) i, 0, (int) i, d.height - 1);
+ }
+ for (double j = zoomStep; j < d.height; j += zoomStep) {
+ g2dWrapper.drawLine(0, (int) j, d.width - 1, (int) j);
+ }
+ }
+
+ if (Math.abs(1.0 - zoom) > 1e-4) {
+ g2dWrapper.scale(zoom, zoom);
+ }
+
+ // Composite mainComposite = g2d.getComposite();
+ // Composite alphaComposite =
+ // AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.5f);
+
+ // g2dWrapper.resetTx();
+
+ // componentAreaMap.clear();
+ for (IDIYComponent> component : project.getComponents()) {
+ // Do not draw the component if it's filtered out.
+ if (filter != null && !filter.testComponent(component)) {
+ continue;
+ }
+ ComponentState state = ComponentState.NORMAL;
+ if (drawOptions.contains(DrawOption.SELECTION) && selectedComponents.contains(component)) {
+ if (dragInProgress) {
+ state = ComponentState.DRAGGING;
+ } else {
+ state = ComponentState.SELECTED;
+ }
+ }
+ // Do not track the area if component is not invalidated and was
+ // drawn in the same state.
+ boolean trackArea = lastDrawnStateMap.get(component) != state;
+
+ synchronized (g2d) {
+ g2dWrapper.startedDrawingComponent();
+ if (!trackArea) {
+ g2dWrapper.stopTracking();
+ }
+ // Draw locked components in a new composite.
+ if (lockedComponents.contains(component)) {
+ g2d.setComposite(lockedComposite);
+ }
+ // Draw the component through the g2dWrapper.
+ try {
+ component.draw(g2dWrapper, state, drawOptions.contains(DrawOption.OUTLINE_MODE), project, g2dWrapper);
+ } catch (Exception e) {
+ LOG.error("Error drawing " + component.getName(), e);
+ failedComponents.add(component);
+ }
+ ComponentArea area = g2dWrapper.finishedDrawingComponent();
+ if (trackArea && area != null && !area.getOutlineArea().isEmpty()) {
+ componentAreaMap.put(component, area);
+ lastDrawnStateMap.put(component, state);
+ }
+ }
+ }
+
+ // Draw control points.
+ if (drawOptions.contains(DrawOption.CONTROL_POINTS)) {
+ // Draw unselected points first to make sure they are below.
+ if (dragInProgress || drawOptions.contains(DrawOption.OUTLINE_MODE)) {
+ for (IDIYComponent> component : project.getComponents()) {
+ for (int i = 0; i < component.getControlPointCount(); i++) {
+ VisibilityPolicy visibilityPolicy = component.getControlPointVisibilityPolicy(i);
+ if ((groupedComponents.contains(component)
+ && (visibilityPolicy == VisibilityPolicy.ALWAYS || (selectedComponents.contains(component) && visibilityPolicy == VisibilityPolicy.WHEN_SELECTED)) || (!groupedComponents
+ .contains(component) && !selectedComponents.contains(component) && component
+ .getControlPointVisibilityPolicy(i) == VisibilityPolicy.ALWAYS))) {
+ g2dWrapper.setColor(CONTROL_POINT_COLOR);
+ Point controlPoint = component.getControlPoint(i);
+ int pointSize = CONTROL_POINT_SIZE - 2;
+ g2dWrapper.fillOval(controlPoint.x - pointSize / 2, controlPoint.y - pointSize / 2, pointSize, pointSize);
+ }
+ }
+ }
+ }
+ // Then draw the selected ones.
+ for (IDIYComponent> component : selectedComponents) {
+ for (int i = 0; i < component.getControlPointCount(); i++) {
+ if (!groupedComponents.contains(component)
+ && (component.getControlPointVisibilityPolicy(i) == VisibilityPolicy.WHEN_SELECTED || component
+ .getControlPointVisibilityPolicy(i) == VisibilityPolicy.ALWAYS)) {
+
+ Point controlPoint = component.getControlPoint(i);
+ int pointSize = CONTROL_POINT_SIZE;
+
+ g2dWrapper.setColor(SELECTED_CONTROL_POINT_COLOR.darker());
+ g2dWrapper.fillOval(controlPoint.x - pointSize / 2, controlPoint.y - pointSize / 2, pointSize, pointSize);
+ g2dWrapper.setColor(SELECTED_CONTROL_POINT_COLOR);
+ g2dWrapper.fillOval(controlPoint.x - CONTROL_POINT_SIZE / 2 + 1, controlPoint.y - CONTROL_POINT_SIZE / 2
+ + 1, CONTROL_POINT_SIZE - 2, CONTROL_POINT_SIZE - 2);
+ }
+ }
+ }
+ }
+
+ // Draw component slot in a separate composite.
+ if (componentSlot != null) {
+ g2dWrapper.startedDrawingComponent();
+ g2dWrapper.setComposite(slotComposite);
+ for (IDIYComponent> component : componentSlot) {
+ try {
+
+ component.draw(g2dWrapper, ComponentState.NORMAL, drawOptions.contains(DrawOption.OUTLINE_MODE), project,
+ g2dWrapper);
+
+ } catch (Exception e) {
+ LOG.error("Error drawing " + component.getName(), e);
+ failedComponents.add(component);
+ }
+ }
+ g2dWrapper.finishedDrawingComponent();
+ }
+
+ // Draw control points of the component in the slot.
+ if (controlPointSlot != null) {
+ for (Point point : controlPointSlot) {
+ if (point != null) {
+ g2dWrapper.setColor(SELECTED_CONTROL_POINT_COLOR.darker());
+ g2dWrapper.fillOval(point.x - CONTROL_POINT_SIZE / 2, point.y - CONTROL_POINT_SIZE / 2, CONTROL_POINT_SIZE,
+ CONTROL_POINT_SIZE);
+ g2dWrapper.setColor(SELECTED_CONTROL_POINT_COLOR);
+ g2dWrapper.fillOval(point.x - CONTROL_POINT_SIZE / 2 + 1, point.y - CONTROL_POINT_SIZE / 2 + 1,
+ CONTROL_POINT_SIZE - 2, CONTROL_POINT_SIZE - 2);
+ }
+ }
+ }
+
+ // Go back to the original transformation and zoom in to draw the
+ // selection rectangle and other similar elements.
+ // g2d.setTransform(initialTx);
+ // if ((drawOptions.contains(DrawOption.ZOOM)) && (Math.abs(1.0 -
+ // zoomLevel) > 1e-4)) {
+ // g2d.scale(zoomLevel, zoomLevel);
+ // }
+
+ // At the end draw selection rectangle if needed.
+ if (drawOptions.contains(DrawOption.SELECTION) && (selectionRect != null)) {
+ g2d.setColor(Color.white);
+ g2d.draw(selectionRect);
+ g2d.setColor(Color.black);
+ g2d.setStroke(Constants.DASHED_STROKE);
+ g2d.draw(selectionRect);
+ }
+
+ // Draw component area for test
+ if (debugComponentAreas) {
+ g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(1));
+ g2d.setColor(Color.red);
+ for (ComponentArea area : componentAreaMap.values()) {
+ g2d.draw(area.getOutlineArea());
+ }
+ }
+
+ // Draw continuity area for test
+ if (debugContinuityAreas) {
+ g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(1));
+ g2d.setColor(Color.green);
+ for (ComponentArea area : componentAreaMap.values()) {
+ for (Area a : area.getContinuityPositiveAreas())
+ g2d.draw(a);
+ }
+ g2d.setColor(Color.blue);
+ for (ComponentArea area : componentAreaMap.values()) {
+ for (Area a : area.getContinuityNegativeAreas())
+ g2d.draw(a);
+ }
+ }
+
+ if (continuityArea != null && (ConfigurationManager.getInstance().readBoolean(IPlugInPort.HIGHLIGHT_CONTINUITY_AREA, false)))
+ {
+ Composite oldComposite = g2d.getComposite();
+ g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.5f));
+ g2d.setColor(Color.green);
+ g2d.fill(continuityArea);
+ g2d.setComposite(oldComposite);
+ }
+
+ return failedComponents;
+ }
+
+ 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) {
+ componentAreaMap.remove(component);
+ lastDrawnStateMap.remove(component);
+ }
+
+ public ComponentArea getComponentArea(IDIYComponent> component) {
+ return componentAreaMap.get(component);
+ }
+
+ public void clearComponentAreaMap() {
+ componentAreaMap.clear();
+ lastDrawnStateMap.clear();
+ }
+
+ public List> findComponentsAt(Point point, Project project) {
+ List> components = new ArrayList>();
+ for (int i = 0; i < project.getComponents().size(); i++) {
+ ComponentArea area = componentAreaMap.get(project.getComponents().get(i));
+ if (area != null && area.getOutlineArea().contains(point)) {
+ components.add(0, project.getComponents().get(i));
+ }
+ }
+ return components;
+ }
+
+ public Dimension getCanvasDimensions(Project project, Double zoomLevel, boolean useZoom) {
+ double width = project.getWidth().convertToPixels();
+ double height = project.getHeight().convertToPixels();
+ if (useZoom) {
+ width *= zoomLevel;
+ height *= zoomLevel;
+ } else {
+ width /= Constants.PIXEL_SIZE;
+ height /= Constants.PIXEL_SIZE;
+ }
+ return new Dimension((int) width, (int) height);
+ }
+
+ public void fireZoomChanged() {
+ messageDispatcher.dispatchMessage(EventType.ZOOM_CHANGED, zoomLevel);
+ messageDispatcher.dispatchMessage(EventType.REPAINT);
+ }
+
+ public Theme getTheme() {
+ return theme;
+ }
+
+ public void setTheme(Theme theme) {
+ this.theme = theme;
+ ConfigurationManager.getInstance().writeValue(IPlugInPort.THEME_KEY, theme);
+ messageDispatcher.dispatchMessage(EventType.REPAINT);
+ }
+
+ @SuppressWarnings("unchecked")
+ public void findContinuityAreaAtPoint(Project project, Point p) {
+ // Find all individual continuity areas for all components
+ List preliminaryAreas = new ArrayList();
+ List checkBreakout = new ArrayList();
+ List connections = new ArrayList();
+ for (IDIYComponent> c : project.getComponents()) {
+ ComponentArea a = getComponentArea(c);
+
+ ComponentType type =
+ ComponentProcessor.getInstance().extractComponentTypeFrom((Class extends IDIYComponent>>) c.getClass());
+ if (type.isContinuity()) {
+ connections.add(new Connection(c.getControlPoint(0), c.getControlPoint(c.getControlPointCount() - 1)));
+ }
+
+ if (a == null || a.getOutlineArea() == null)
+ continue;
+ if (a.getContinuityPositiveAreas() != null)
+ for (Area a1 : a.getContinuityPositiveAreas()) {
+ preliminaryAreas.add(a1);
+ checkBreakout.add(false);
+ }
+ if (a.getContinuityNegativeAreas() != null) {
+ for (Area na : a.getContinuityNegativeAreas())
+ for (int i = 0; i < preliminaryAreas.size(); i++) {
+ Area a1 = preliminaryAreas.get(i);
+ if (a1.intersects(na.getBounds2D())) {
+ a1.subtract(na);
+ checkBreakout.set(i, true);
+ }
+ }
+ }
+ }
+
+ // Check if we need to break some areas out in case they are interrupted
+ List areas = new ArrayList();
+ for (int i = 0; i < preliminaryAreas.size(); i++) {
+ Area a = preliminaryAreas.get(i);
+ if (checkBreakout.get(i))
+ areas.addAll(tryBreakout(a));
+ else
+ areas.add(a);
+ }
+
+ crunchAreas(areas, connections);
+
+ for (Area a : areas) {
+ if (a.contains(p)) {
+ continuityArea = a;
+ return;
+ }
+ }
+
+ continuityArea = null;
+ }
+
+ private boolean crunchAreas(List areas, List connections) {
+ boolean isChanged = false;
+
+ List newAreas = new ArrayList();
+ List consumed = new ArrayList();
+ for (int i = 0; i < areas.size(); i++) {
+ consumed.add(false);
+ }
+ for (int i = 0; i < areas.size(); i++) {
+ for (int j = i + 1; j < areas.size(); j++) {
+ if (consumed.get(j))
+ continue;
+ Area a1 = areas.get(i);
+ Area a2 = areas.get(j);
+ Area intersection = new Area(a1);
+ intersection.intersect(a2);
+ // if the two areas intersect, make a union and consume the second area
+ if (!intersection.isEmpty()) {
+ a1.add(a2);
+ consumed.set(j, true);
+ } else { // maybe there's a connection between them
+ for (Connection p : connections) {
+ if ((a1.contains(p.pointA) && a2.contains(p.pointB)) || (a1.contains(p.pointB) && a2.contains(p.pointA))) {
+ a1.add(a2);
+ consumed.set(j, true);
+ break;
+ }
+ }
+ }
+ }
+ }
+ for (int i = 0; i < areas.size(); i++)
+ if (!consumed.get(i))
+ newAreas.add(areas.get(i));
+ else
+ isChanged = true;
+
+ if (isChanged) {
+ areas.clear();
+ areas.addAll(newAreas);
+ crunchAreas(areas, connections);
+ }
+
+ return isChanged;
+ }
+
+ private List tryBreakout(Area a) {
+ List toReturn = new ArrayList();
+ Path2D p = null;
+ PathIterator pathIterator = a.getPathIterator(null);
+ while (!pathIterator.isDone()) {
+ double[] coord = new double[6];
+ int type = pathIterator.currentSegment(coord);
+ switch (type) {
+ case PathIterator.SEG_MOVETO:
+ if (p != null) {
+ Area partArea = new Area(p);
+ toReturn.add(partArea);
+ }
+ p = new Path2D.Double();
+ p.moveTo(coord[0], coord[1]);
+ break;
+ case PathIterator.SEG_LINETO:
+ p.lineTo(coord[0], coord[1]);
+ break;
+ case PathIterator.SEG_CUBICTO:
+ p.curveTo(coord[0], coord[1], coord[2], coord[3], coord[4], coord[5]);
+ break;
+ case PathIterator.SEG_QUADTO:
+ p.quadTo(coord[0], coord[1], coord[2], coord[3]);
+ break;
+ }
+ pathIterator.next();
+ }
+ if (p != null) {
+ Area partArea = new Area(p);
+ toReturn.add(partArea);
+ }
+
+ return toReturn;
+ }
+
+ class Connection {
+
+ private Point pointA;
+ private Point pointB;
+
+ public Connection(Point pointA, Point pointB) {
+ super();
+ this.pointA = pointA;
+ this.pointB = pointB;
+ }
+
+ public Point getPointA() {
+ return pointA;
+ }
+
+ public Point getPointB() {
+ return pointB;
+ }
+ }
+}
diff --git a/diylc/diylc-core/src/org/diylc/presenter/G2DWrapper.java b/diylc/diylc-core/src/org/diylc/presenter/G2DWrapper.java
index 5697efbf..0d127147 100644
--- a/diylc/diylc-core/src/org/diylc/presenter/G2DWrapper.java
+++ b/diylc/diylc-core/src/org/diylc/presenter/G2DWrapper.java
@@ -1,719 +1,746 @@
/*
+ *
+ * DIY Layout Creator (DIYLC). Copyright (c) 2009-2018 held jointly by the individual authors.
+ *
+ * This file is part of DIYLC.
+ *
+ * DIYLC is free software: you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License as published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * DIYLC is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
+ * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
+ * Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with DIYLC. If not, see
+ * .
+ */
+package org.diylc.presenter;
- DIY Layout Creator (DIYLC).
- Copyright (c) 2009-2018 held jointly by the individual authors.
+import java.awt.BasicStroke;
+import java.awt.Color;
+import java.awt.Composite;
+import java.awt.Font;
+import java.awt.FontMetrics;
+import java.awt.Graphics;
+import java.awt.Graphics2D;
+import java.awt.GraphicsConfiguration;
+import java.awt.Image;
+import java.awt.Paint;
+import java.awt.Polygon;
+import java.awt.Rectangle;
+import java.awt.RenderingHints;
+import java.awt.Shape;
+import java.awt.Stroke;
+import java.awt.RenderingHints.Key;
+import java.awt.font.FontRenderContext;
+import java.awt.font.GlyphVector;
+import java.awt.geom.AffineTransform;
+import java.awt.geom.Arc2D;
+import java.awt.geom.Area;
+import java.awt.geom.CubicCurve2D;
+import java.awt.geom.Ellipse2D;
+import java.awt.geom.Line2D;
+import java.awt.geom.NoninvertibleTransformException;
+import java.awt.geom.PathIterator;
+import java.awt.geom.Point2D;
+import java.awt.geom.QuadCurve2D;
+import java.awt.geom.Rectangle2D;
+import java.awt.geom.RoundRectangle2D;
+import java.awt.image.BufferedImage;
+import java.awt.image.BufferedImageOp;
+import java.awt.image.ImageObserver;
+import java.awt.image.RenderedImage;
+import java.awt.image.renderable.RenderableImage;
+import java.text.AttributedCharacterIterator;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
- This file is part of DIYLC.
+import org.diylc.common.ObjectCache;
+import org.diylc.core.IDrawingObserver;
- DIYLC is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
+/**
+ * {@link Graphics2D} wrapper that keeps track of all drawing actions and creates an {@link Area}
+ * that corresponds to drawn objects. Before each component is drawn,
+ * {@link #startedDrawingComponent()} should be called. After the component is drawn, area may be
+ * retrieved using {@link #finishedDrawingComponent()}. Graphics configuration (color, font, etc) is
+ * reset between each two components.
+ *
+ * @author Branislav Stojkovic
+ */
+class G2DWrapper extends Graphics2D implements IDrawingObserver {
- DIYLC is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
+ public static int LINE_SENSITIVITY_MARGIN = 2;
+ public static int CURVE_SENSITIVITY = 6;
- You should have received a copy of the GNU General Public License
- along with DIYLC. If not, see .
+ private boolean drawingComponent = false;
+ private boolean trackingAllowed = true;
+ private boolean trackingContinuityAllowed = false;
+ private boolean trackingContinuityPositive = true;
-*/
-package org.diylc.presenter;
-
-import java.awt.BasicStroke;
-import java.awt.Color;
-import java.awt.Composite;
-import java.awt.Font;
-import java.awt.FontMetrics;
-import java.awt.Graphics;
-import java.awt.Graphics2D;
-import java.awt.GraphicsConfiguration;
-import java.awt.Image;
-import java.awt.Paint;
-import java.awt.Polygon;
-import java.awt.Rectangle;
-import java.awt.RenderingHints;
-import java.awt.Shape;
-import java.awt.Stroke;
-import java.awt.RenderingHints.Key;
-import java.awt.font.FontRenderContext;
-import java.awt.font.GlyphVector;
-import java.awt.geom.AffineTransform;
-import java.awt.geom.Arc2D;
-import java.awt.geom.Area;
-import java.awt.geom.CubicCurve2D;
-import java.awt.geom.Ellipse2D;
-import java.awt.geom.Line2D;
-import java.awt.geom.NoninvertibleTransformException;
-import java.awt.geom.PathIterator;
-import java.awt.geom.Point2D;
-import java.awt.geom.QuadCurve2D;
-import java.awt.geom.Rectangle2D;
-import java.awt.geom.RoundRectangle2D;
-import java.awt.image.BufferedImage;
-import java.awt.image.BufferedImageOp;
-import java.awt.image.ImageObserver;
-import java.awt.image.RenderedImage;
-import java.awt.image.renderable.RenderableImage;
-import java.text.AttributedCharacterIterator;
-import java.util.Map;
-
-import org.diylc.common.ObjectCache;
-import org.diylc.core.IDrawingObserver;
-
-/**
- * {@link Graphics2D} wrapper that keeps track of all drawing actions and creates an {@link Area}
- * that corresponds to drawn objects. Before each component is drawn,
- * {@link #startedDrawingComponent()} should be called. After the component is drawn, area may be
- * retrieved using {@link #finishedDrawingComponent()}. Graphics configuration (color, font, etc) is
- * reset between each two components.
- *
- * @author Branislav Stojkovic
- */
-class G2DWrapper extends Graphics2D implements IDrawingObserver {
-
- public static int LINE_SENSITIVITY_MARGIN = 2;
- public static int CURVE_SENSITIVITY = 6;
-
- private boolean drawingComponent = false;
- private boolean trackingAllowed = true;
-
- private Graphics2D canvasGraphics;
- private Stroke originalStroke;
- private Color originalColor;
- private Composite originalComposite;
- private AffineTransform originalTx;
- private Font originalFont;
- private AffineTransform currentTx;
- private AffineTransform initialTx;
- private Area currentArea;
- private Shape lastShape;
-
- private double zoom;
-
- /**
- * Creates a wrapper around specified {@link Graphics2D} object.
- *
- * @param canvasGraphics
- */
- public G2DWrapper(Graphics2D canvasGraphics, double zoom) {
- super();
- this.canvasGraphics = canvasGraphics;
- this.zoom = zoom;
- currentArea = new Area();
- currentTx = new AffineTransform();
- }
-
- /**
- * Clears out the current area and caches canvas settings.
- */
- public void startedDrawingComponent() {
- drawingComponent = true;
- currentArea = new Area();
- originalStroke = canvasGraphics.getStroke();
- originalColor = canvasGraphics.getColor();
- originalTx = canvasGraphics.getTransform();
- originalComposite = canvasGraphics.getComposite();
- originalFont = canvasGraphics.getFont();
- currentTx = new AffineTransform();
- initialTx = canvasGraphics.getTransform();
- lastShape = null;
- startTracking();
- }
-
- /**
- * Reverts {@link Graphics2D} settings and returns area drawn by component in the meantime.
- *
- * @return
- */
- public Area finishedDrawingComponent() {
- drawingComponent = false;
- canvasGraphics.setStroke(originalStroke);
- canvasGraphics.setColor(originalColor);
- canvasGraphics.setTransform(originalTx);
- canvasGraphics.setComposite(originalComposite);
- canvasGraphics.setFont(originalFont);
- return currentArea;
- }
-
- @Override
- public void startTracking() {
- this.trackingAllowed = true;
- }
-
- @Override
- public void stopTracking() {
- this.trackingAllowed = false;
- }
-
- /**
- * Appends shape interior to the current component area.
- *
- * @param s
- */
- private void appendShape(Shape s) {
- if (!drawingComponent || !trackingAllowed) {
- return;
- }
- Rectangle2D bounds = s.getBounds2D();
- // Only cache the shape if it's not 1D.
- if (bounds.getWidth() > 1 && bounds.getHeight() > 1) {
- Area area = new Area(s);
- area.transform(currentTx);
- currentArea.add(area);
- lastShape = s;
- }
- }
-
- /**
- * Appends shape outline to the current component area.
- *
- * @param s
- */
- private void appendShapeOutline(Shape s) {
- // Do not add shape outline if the same shape has been filled recently.
- if (!drawingComponent || !trackingAllowed || s.equals(lastShape)) {
- return;
- }
- lastShape = s;
- PathIterator pathIterator = s.getPathIterator(null);
- double thickness;
- if (getStroke() instanceof BasicStroke) {
- thickness = ((BasicStroke) getStroke()).getLineWidth() + 2 * LINE_SENSITIVITY_MARGIN;
- } else {
- thickness = 2 * LINE_SENSITIVITY_MARGIN;
- }
- Point2D prevPoint = null;
- while (!pathIterator.isDone()) {
- double[] coord = new double[6];
- int type = pathIterator.currentSegment(coord);
- switch (type) {
- case PathIterator.SEG_MOVETO:
- prevPoint = new Point2D.Double(coord[0], coord[1]);
- break;
- case PathIterator.SEG_LINETO:
- // Represent straight line with a rectangle.
- Point2D nextPoint = new Point2D.Double(coord[0], coord[1]);
- Double theta = Math.atan2(nextPoint.getY() - prevPoint.getY(), nextPoint.getX() - prevPoint.getX());
- double width =
- Math.sqrt(Math.pow(nextPoint.getX() - prevPoint.getX(), 2)
- + Math.pow(nextPoint.getY() - prevPoint.getY(), 2));
- double midX = (prevPoint.getX() + nextPoint.getX()) / 2;
- double midY = (prevPoint.getY() + nextPoint.getY()) / 2;
- Rectangle2D rect = new Rectangle2D.Double(midX - width / 2, midY - thickness / 2, width, thickness);
- Area area = new Area(rect);
- area.transform(AffineTransform.getRotateInstance(theta, midX, midY));
- // area.transform(currentTx);
- appendShape(area);
- // Set the prev point to line end
- prevPoint = nextPoint;
- break;
- case PathIterator.SEG_CUBICTO:
- CubicCurve2D cubicCurve =
- new CubicCurve2D.Double(prevPoint.getX(), prevPoint.getY(), coord[0], coord[1], coord[2], coord[3],
- coord[4], coord[5]);
- addCubicCurveArea(cubicCurve);
- prevPoint = new Point2D.Double(coord[4], coord[5]);
- break;
- case PathIterator.SEG_QUADTO:
- QuadCurve2D quadCurve =
- new QuadCurve2D.Double(prevPoint.getX(), prevPoint.getY(), coord[0], coord[1], coord[2], coord[3]);
- addQuadCurveArea(quadCurve);
- prevPoint = new Point2D.Double(coord[3], coord[3]);
- break;
- }
- pathIterator.next();
- }
- }
-
- /**
- * Adds a cubic curve to the component area. It uses subdivision to approximate the curve with a
- * series of straight lines.
- *
- * @param curve
- */
- private void addCubicCurveArea(CubicCurve2D curve) {
- // When end points are close enough, approximate the curve with a
- // straight line.
- if (curve.getFlatness() < CURVE_SENSITIVITY) {
- appendShapeOutline(new Line2D.Double(curve.getP1(), curve.getP2()));
- } else {
- CubicCurve2D leftSubcurve = new CubicCurve2D.Double();
- CubicCurve2D rightSubcurve = new CubicCurve2D.Double();
- curve.subdivide(leftSubcurve, rightSubcurve);
- addCubicCurveArea(leftSubcurve);
- addCubicCurveArea(rightSubcurve);
- }
- }
-
- /**
- * Adds a quad curve to the component area. It uses subdivision to approximate the curve with a
- * series of straight lines.
- *
- * @param curve
- */
- private void addQuadCurveArea(QuadCurve2D curve) {
- // When end points are close enough, approximate the curve with a
- // straight line.
- if (curve.getFlatness() < CURVE_SENSITIVITY) {
- appendShapeOutline(new Line2D.Double(curve.getP1(), curve.getP2()));
- } else {
- QuadCurve2D leftSubcurve = new QuadCurve2D.Double();
- QuadCurve2D rightSubcurve = new QuadCurve2D.Double();
- curve.subdivide(leftSubcurve, rightSubcurve);
- addQuadCurveArea(leftSubcurve);
- addQuadCurveArea(rightSubcurve);
- }
- }
-
- @Override
- public void addRenderingHints(Map, ?> hints) {
- canvasGraphics.addRenderingHints(hints);
- }
-
- @Override
- public void clip(Shape s) {
- canvasGraphics.clip(s);
- }
-
- @Override
- public void draw(Shape s) {
- canvasGraphics.draw(s);
- if (drawingComponent && trackingAllowed) {
- appendShapeOutline(s);
- }
- }
-
- @Override
- public void drawGlyphVector(GlyphVector g, float x, float y) {
- canvasGraphics.drawGlyphVector(g, x, y);
- }
-
- @Override
- public boolean drawImage(Image img, AffineTransform xform, ImageObserver obs) {
- // FIXME: process map
- return canvasGraphics.drawImage(img, xform, obs);
- }
-
- @Override
- public void drawImage(BufferedImage img, BufferedImageOp op, int x, int y) {
- canvasGraphics.drawImage(img, op, x, y);
- // FIXME: process map
- }
-
- @Override
- public void drawRenderableImage(RenderableImage img, AffineTransform xform) {
- canvasGraphics.drawRenderableImage(img, xform);
- // FIXME: process map
- }
-
- @Override
- public void drawRenderedImage(RenderedImage img, AffineTransform xform) {
- canvasGraphics.drawRenderedImage(img, xform);
- // FIXME: process map
- }
-
- @Override
- public void drawString(String str, int x, int y) {
- canvasGraphics.drawString(str, x, y);
- if (drawingComponent && trackingAllowed) {
- FontMetrics fontMetrics = canvasGraphics.getFontMetrics();
- Rectangle2D rect = fontMetrics.getStringBounds(str, canvasGraphics);
- Point2D point = new Point2D.Double(x, y);
- // currentTx.transform(point, point);
- Rectangle2D finalRec =
- new Rectangle2D.Double(rect.getX() + point.getX(), rect.getY() + point.getY(), rect.getWidth(),
- rect.getHeight());
- appendShape(finalRec);
- }
- }
-
- @Override
- public void drawString(String str, float x, float y) {
- canvasGraphics.drawString(str, x, y);
- if (drawingComponent && trackingAllowed) {
- FontMetrics fontMetrics = canvasGraphics.getFontMetrics();
- Rectangle2D rect = fontMetrics.getStringBounds(str, canvasGraphics);
- appendShape(new Rectangle2D.Double(rect.getX() + x, rect.getY() + y, rect.getWidth(), rect.getHeight()));
- }
- }
-
- @Override
- public void drawString(AttributedCharacterIterator iterator, int x, int y) {
- canvasGraphics.drawString(iterator, x, y);
- // FIXME: process map
- }
-
- @Override
- public void drawString(AttributedCharacterIterator iterator, float x, float y) {
- canvasGraphics.drawString(iterator, x, y);
- // FIXME: process map
- }
-
- @Override
- public void fill(Shape s) {
- canvasGraphics.fill(s);
- appendShape(s);
- }
-
- @Override
- public Color getBackground() {
- return canvasGraphics.getBackground();
- }
-
- @Override
- public Composite getComposite() {
- return canvasGraphics.getComposite();
- }
-
- @Override
- public GraphicsConfiguration getDeviceConfiguration() {
- return canvasGraphics.getDeviceConfiguration();
- }
-
- @Override
- public FontRenderContext getFontRenderContext() {
- return canvasGraphics.getFontRenderContext();
- }
-
- @Override
- public Paint getPaint() {
- return canvasGraphics.getPaint();
- }
-
- @Override
- public Object getRenderingHint(Key hintKey) {
- return canvasGraphics.getRenderingHint(hintKey);
- }
-
- @Override
- public RenderingHints getRenderingHints() {
- return canvasGraphics.getRenderingHints();
- }
-
- @Override
- public Stroke getStroke() {
- return canvasGraphics.getStroke();
- }
-
- @Override
- public AffineTransform getTransform() {
- return canvasGraphics.getTransform();
- }
-
- @Override
- public boolean hit(Rectangle rect, Shape s, boolean onStroke) {
- return canvasGraphics.hit(rect, s, onStroke);
- }
-
- @Override
- public void rotate(double theta) {
- canvasGraphics.rotate(theta);
- currentTx.rotate(theta);
- }
-
- @Override
- public void rotate(double theta, double x, double y) {
- canvasGraphics.rotate(theta, x, y);
- currentTx.rotate(theta, x, y);
- }
-
- @Override
- public void scale(double sx, double sy) {
- canvasGraphics.scale(sx, sy);
- currentTx.scale(sx, sy);
- }
-
- @Override
- public void setBackground(Color color) {
- canvasGraphics.setBackground(color);
- // FIXME: fix map
- }
-
- @Override
- public void setComposite(Composite comp) {
- canvasGraphics.setComposite(comp);
- // FIXME: check this.
- }
-
- @Override
- public void setPaint(Paint paint) {
- canvasGraphics.setPaint(paint);
- // FIXME: check this
- }
-
- @Override
- public void setRenderingHint(Key hintKey, Object hintValue) {
- canvasGraphics.setRenderingHint(hintKey, hintValue);
- // FIXME: check this
- }
-
- @Override
- public void setRenderingHints(Map, ?> hints) {
- canvasGraphics.setRenderingHints(hints);
- // FIXME: check this
- }
-
- @Override
- public void setStroke(Stroke s) {
- if (this.zoom > 1 && s.getClass() == BasicStroke.class) {
- BasicStroke bs = (BasicStroke) s;
- // make thin lines even thinner to compensate for zoom factor
- if (bs.getLineWidth() <= 2)
- s = ObjectCache.getInstance().fetchBasicStroke((float) (bs.getLineWidth() / zoom));
- }
- canvasGraphics.setStroke(s);
- }
-
- @Override
- public void setTransform(AffineTransform Tx) {
- canvasGraphics.setTransform(Tx);
- currentTx = new AffineTransform(Tx);
- try {
- // Invert the tx that was set before we started drawing the component.
- // We're left only component tx.
- AffineTransform inverseInitialTx = initialTx.createInverse();
- Point2D p = new Point2D.Double(currentTx.getTranslateX(), currentTx.getTranslateY());
- inverseInitialTx.transform(p, p);
- currentTx.concatenate(inverseInitialTx);
- double[] matrix = new double[6];
- currentTx.getMatrix(matrix);
- currentTx.setTransform(matrix[0], matrix[1], matrix[2], matrix[3], p.getX(), p.getY());
- } catch (NoninvertibleTransformException e) {
- }
- }
-
- @Override
- public void shear(double shx, double shy) {
- canvasGraphics.shear(shx, shy);
- currentTx.shear(shx, shy);
- }
-
- @Override
- public void transform(AffineTransform Tx) {
- canvasGraphics.transform(Tx);
- currentTx.concatenate(Tx);
- }
-
- @Override
- public void translate(int x, int y) {
- canvasGraphics.translate(x, y);
- currentTx.translate(x, y);
- }
-
- @Override
- public void translate(double tx, double ty) {
- canvasGraphics.translate(tx, ty);
- currentTx.translate(tx, ty);
- }
-
- @Override
- public void clearRect(int x, int y, int width, int height) {
- canvasGraphics.clearRect(x, y, width, height);
- }
-
- @Override
- public void clipRect(int x, int y, int width, int height) {
- canvasGraphics.clipRect(x, y, width, height);
- }
-
- @Override
- public void copyArea(int x, int y, int width, int height, int dx, int dy) {
- canvasGraphics.copyArea(x, y, width, height, dx, dy);
- }
-
- @Override
- public Graphics create() {
- return canvasGraphics.create();
- }
-
- @Override
- public void dispose() {
- canvasGraphics.dispose();
- }
-
- @Override
- public void drawArc(int x, int y, int width, int height, int startAngle, int arcAngle) {
- canvasGraphics.drawArc(x, y, width, height, startAngle, arcAngle);
- }
-
- @Override
- public boolean drawImage(Image img, int x, int y, ImageObserver observer) {
- boolean result = canvasGraphics.drawImage(img, x, y, observer);
- appendShape(new Rectangle2D.Double(x, y, img.getWidth(observer), img.getHeight(observer)));
- return result;
- }
-
- @Override
- public boolean drawImage(Image img, int x, int y, Color bgcolor, ImageObserver observer) {
- // FIXME: map
- return canvasGraphics.drawImage(img, x, y, bgcolor, observer);
- }
-
- @Override
- public boolean drawImage(Image img, int x, int y, int width, int height, ImageObserver observer) {
- // FIXME: map
- return canvasGraphics.drawImage(img, x, y, width, height, observer);
- }
-
- @Override
- public boolean drawImage(Image img, int x, int y, int width, int height, Color bgcolor, ImageObserver observer) {
- // FIXME: map
- return canvasGraphics.drawImage(img, x, y, width, height, bgcolor, observer);
- }
-
- @Override
- public boolean drawImage(Image img, int dx1, int dy1, int dx2, int dy2, int sx1, int sy1, int sx2, int sy2,
- ImageObserver observer) {
- // FIXME: map
- return canvasGraphics.drawImage(img, dx1, dy1, dx2, dy2, sx1, sy1, sx2, sy2, observer);
- }
-
- @Override
- public boolean drawImage(Image img, int dx1, int dy1, int dx2, int dy2, int sx1, int sy1, int sx2, int sy2,
- Color bgcolor, ImageObserver observer) {
- // FIXME: map
- return drawImage(img, dx1, dy1, dx2, dy2, sx1, sy1, sx2, sy2, bgcolor, observer);
- }
-
- @Override
- public void drawLine(int x1, int y1, int x2, int y2) {
- canvasGraphics.drawLine(x1, y1, x2, y2);
- if (drawingComponent && trackingAllowed) {
- appendShapeOutline(new Line2D.Double(x1, y1, x2, y2));
- }
- }
-
- @Override
- public void drawOval(int x, int y, int width, int height) {
- canvasGraphics.drawOval(x, y, width, height);
- if (drawingComponent && trackingAllowed) {
- appendShapeOutline(new Ellipse2D.Double(x, y, width, height));
- }
- }
-
- @Override
- public void drawPolygon(int[] points, int[] points2, int points3) {
- canvasGraphics.drawPolygon(points, points2, points3);
- if (drawingComponent && trackingAllowed) {
- appendShapeOutline(new Polygon(points, points2, points3));
- }
- }
-
- @Override
- public void drawPolyline(int[] points, int[] points2, int points3) {
- canvasGraphics.drawPolyline(points, points2, points3);
- }
-
- @Override
- public void drawRoundRect(int x, int y, int width, int height, int arcWidth, int arcHeight) {
- canvasGraphics.drawRoundRect(x, y, width, height, arcWidth, arcHeight);
- if (drawingComponent && trackingAllowed) {
- appendShapeOutline(new RoundRectangle2D.Double(x, y, width, height, arcWidth, arcHeight));
- }
- }
-
- @Override
- public void fillArc(int x, int y, int width, int height, int startAngle, int arcAngle) {
- canvasGraphics.fillArc(x, y, width, height, startAngle, arcAngle);
- if (drawingComponent && trackingAllowed) {
- appendShape(new Arc2D.Double(x, y, width, height, startAngle, arcAngle, Arc2D.PIE));
- }
- }
-
- @Override
- public void fillOval(int x, int y, int width, int height) {
- canvasGraphics.fillOval(x, y, width, height);
- if (drawingComponent && trackingAllowed) {
- appendShape(new Ellipse2D.Double(x, y, width, height));
- }
- }
-
- @Override
- public void fillPolygon(int[] points, int[] points2, int points3) {
- canvasGraphics.fillPolygon(points, points2, points3);
- if (drawingComponent && trackingAllowed) {
- appendShape(new Polygon(points, points2, points3));
- }
- }
-
- @Override
- public void drawRect(int x, int y, int width, int height) {
- canvasGraphics.drawRect(x, y, width, height);
- if (drawingComponent && trackingAllowed) {
- appendShapeOutline(new Rectangle(x, y, width, height));
- }
- }
-
- @Override
- public void fillRect(int x, int y, int width, int height) {
- canvasGraphics.fillRect(x, y, width, height);
- if (drawingComponent && trackingAllowed) {
- appendShape(new Rectangle(x, y, width, height));
- }
- }
-
- @Override
- public void fillRoundRect(int x, int y, int width, int height, int arcWidth, int arcHeight) {
- canvasGraphics.fillRoundRect(x, y, width, height, arcWidth, arcHeight);
- if (drawingComponent && trackingAllowed) {
- appendShape(new RoundRectangle2D.Double(x, y, width, height, arcWidth, arcHeight));
- }
- }
-
- @Override
- public Shape getClip() {
- return canvasGraphics.getClip();
- }
-
- @Override
- public Rectangle getClipBounds() {
- return canvasGraphics.getClipBounds();
- }
-
- @Override
- public Color getColor() {
- return canvasGraphics.getColor();
- }
-
- @Override
- public Font getFont() {
- return canvasGraphics.getFont();
- }
-
- @Override
- public FontMetrics getFontMetrics(Font f) {
- return canvasGraphics.getFontMetrics(f);
- }
-
- @Override
- public void setClip(Shape clip) {
- canvasGraphics.setClip(clip);
- }
-
- @Override
- public void setClip(int x, int y, int width, int height) {
- canvasGraphics.setClip(x, y, width, height);
- }
-
- @Override
- public void setColor(Color c) {
- canvasGraphics.setColor(c);
- }
-
- @Override
- public void setFont(Font font) {
- canvasGraphics.setFont(font);
- }
-
- @Override
- public void setPaintMode() {
- canvasGraphics.setPaintMode();
- }
-
- @Override
- public void setXORMode(Color c1) {
- canvasGraphics.setXORMode(c1);
- }
-}
+ private Graphics2D canvasGraphics;
+ private Stroke originalStroke;
+ private Color originalColor;
+ private Composite originalComposite;
+ private AffineTransform originalTx;
+ private Font originalFont;
+ private AffineTransform currentTx;
+ private AffineTransform initialTx;
+ private Area currentArea;
+ private List currentContinuityPositiveAreas;
+ private List currentContinuityNegativeAreas;
+ private Shape lastShape;
+
+ private double zoom;
+
+ /**
+ * Creates a wrapper around specified {@link Graphics2D} object.
+ *
+ * @param canvasGraphics
+ */
+ public G2DWrapper(Graphics2D canvasGraphics, double zoom) {
+ super();
+ this.canvasGraphics = canvasGraphics;
+ this.zoom = zoom;
+ currentArea = new Area();
+ currentContinuityPositiveAreas = new ArrayList();
+ currentContinuityNegativeAreas = new ArrayList();
+ currentTx = new AffineTransform();
+ }
+
+ /**
+ * Clears out the current area and caches canvas settings.
+ */
+ public void startedDrawingComponent() {
+ drawingComponent = true;
+ currentArea = new Area();
+ currentContinuityPositiveAreas = new ArrayList();
+ currentContinuityNegativeAreas = new ArrayList();
+ originalStroke = canvasGraphics.getStroke();
+ originalColor = canvasGraphics.getColor();
+ originalTx = canvasGraphics.getTransform();
+ originalComposite = canvasGraphics.getComposite();
+ originalFont = canvasGraphics.getFont();
+ currentTx = new AffineTransform();
+ initialTx = canvasGraphics.getTransform();
+ lastShape = null;
+ startTracking();
+ }
+
+ /**
+ * Reverts {@link Graphics2D} settings and returns area drawn by component in the meantime.
+ *
+ * @return
+ */
+ public ComponentArea finishedDrawingComponent() {
+ drawingComponent = false;
+ canvasGraphics.setStroke(originalStroke);
+ canvasGraphics.setColor(originalColor);
+ canvasGraphics.setTransform(originalTx);
+ canvasGraphics.setComposite(originalComposite);
+ canvasGraphics.setFont(originalFont);
+ return new ComponentArea(currentArea, currentContinuityPositiveAreas, currentContinuityNegativeAreas);
+ }
+
+ @Override
+ public void startTracking() {
+ this.trackingAllowed = true;
+ }
+
+ @Override
+ public void stopTracking() {
+ this.trackingAllowed = false;
+ }
+
+ @Override
+ public void startTrackingContinuityArea(boolean positive) {
+ this.trackingContinuityAllowed = true;
+ this.trackingContinuityPositive = positive;
+ }
+
+ @Override
+ public void stopTrackingContinuityArea() {
+ this.trackingContinuityAllowed = false;
+ }
+
+
+ /**
+ * Appends shape interior to the current component area.
+ *
+ * @param s
+ */
+ private void appendShape(Shape s) {
+ if (!drawingComponent || (!trackingAllowed && !trackingContinuityAllowed)) {
+ return;
+ }
+ Rectangle2D bounds = s.getBounds2D();
+ // Only cache the shape if it's not 1D.
+ if (bounds.getWidth() > 1 && bounds.getHeight() > 1) {
+ Area area = new Area(s);
+ area.transform(currentTx);
+
+ if (trackingAllowed)
+ currentArea.add(area);
+
+ if (trackingContinuityAllowed) {
+ if (trackingContinuityPositive)
+ currentContinuityPositiveAreas.add(area);
+ else
+ currentContinuityNegativeAreas.add(area);
+ }
+ lastShape = s;
+ }
+ }
+
+ /**
+ * Appends shape outline to the current component area.
+ *
+ * @param s
+ */
+ private void appendShapeOutline(Shape s) {
+ // Do not add shape outline if the same shape has been filled recently.
+ if (!drawingComponent || !trackingAllowed || s.equals(lastShape)) {
+ return;
+ }
+ lastShape = s;
+ PathIterator pathIterator = s.getPathIterator(null);
+ double thickness;
+ if (getStroke() instanceof BasicStroke) {
+ thickness = ((BasicStroke) getStroke()).getLineWidth() + 2 * LINE_SENSITIVITY_MARGIN;
+ } else {
+ thickness = 2 * LINE_SENSITIVITY_MARGIN;
+ }
+ Point2D prevPoint = null;
+ while (!pathIterator.isDone()) {
+ double[] coord = new double[6];
+ int type = pathIterator.currentSegment(coord);
+ switch (type) {
+ case PathIterator.SEG_MOVETO:
+ prevPoint = new Point2D.Double(coord[0], coord[1]);
+ break;
+ case PathIterator.SEG_LINETO:
+ // Represent straight line with a rectangle.
+ Point2D nextPoint = new Point2D.Double(coord[0], coord[1]);
+ Double theta = Math.atan2(nextPoint.getY() - prevPoint.getY(), nextPoint.getX() - prevPoint.getX());
+ double width =
+ Math.sqrt(Math.pow(nextPoint.getX() - prevPoint.getX(), 2)
+ + Math.pow(nextPoint.getY() - prevPoint.getY(), 2));
+ double midX = (prevPoint.getX() + nextPoint.getX()) / 2;
+ double midY = (prevPoint.getY() + nextPoint.getY()) / 2;
+ Rectangle2D rect = new Rectangle2D.Double(midX - width / 2, midY - thickness / 2, width, thickness);
+ Area area = new Area(rect);
+ area.transform(AffineTransform.getRotateInstance(theta, midX, midY));
+ // area.transform(currentTx);
+ appendShape(area);
+ // Set the prev point to line end
+ prevPoint = nextPoint;
+ break;
+ case PathIterator.SEG_CUBICTO:
+ CubicCurve2D cubicCurve =
+ new CubicCurve2D.Double(prevPoint.getX(), prevPoint.getY(), coord[0], coord[1], coord[2], coord[3],
+ coord[4], coord[5]);
+ addCubicCurveArea(cubicCurve);
+ prevPoint = new Point2D.Double(coord[4], coord[5]);
+ break;
+ case PathIterator.SEG_QUADTO:
+ QuadCurve2D quadCurve =
+ new QuadCurve2D.Double(prevPoint.getX(), prevPoint.getY(), coord[0], coord[1], coord[2], coord[3]);
+ addQuadCurveArea(quadCurve);
+ prevPoint = new Point2D.Double(coord[3], coord[3]);
+ break;
+ }
+ pathIterator.next();
+ }
+ }
+
+ /**
+ * Adds a cubic curve to the component area. It uses subdivision to approximate the curve with a
+ * series of straight lines.
+ *
+ * @param curve
+ */
+ private void addCubicCurveArea(CubicCurve2D curve) {
+ // When end points are close enough, approximate the curve with a
+ // straight line.
+ if (curve.getFlatness() < CURVE_SENSITIVITY) {
+ appendShapeOutline(new Line2D.Double(curve.getP1(), curve.getP2()));
+ } else {
+ CubicCurve2D leftSubcurve = new CubicCurve2D.Double();
+ CubicCurve2D rightSubcurve = new CubicCurve2D.Double();
+ curve.subdivide(leftSubcurve, rightSubcurve);
+ addCubicCurveArea(leftSubcurve);
+ addCubicCurveArea(rightSubcurve);
+ }
+ }
+
+ /**
+ * Adds a quad curve to the component area. It uses subdivision to approximate the curve with a
+ * series of straight lines.
+ *
+ * @param curve
+ */
+ private void addQuadCurveArea(QuadCurve2D curve) {
+ // When end points are close enough, approximate the curve with a
+ // straight line.
+ if (curve.getFlatness() < CURVE_SENSITIVITY) {
+ appendShapeOutline(new Line2D.Double(curve.getP1(), curve.getP2()));
+ } else {
+ QuadCurve2D leftSubcurve = new QuadCurve2D.Double();
+ QuadCurve2D rightSubcurve = new QuadCurve2D.Double();
+ curve.subdivide(leftSubcurve, rightSubcurve);
+ addQuadCurveArea(leftSubcurve);
+ addQuadCurveArea(rightSubcurve);
+ }
+ }
+
+ @Override
+ public void addRenderingHints(Map, ?> hints) {
+ canvasGraphics.addRenderingHints(hints);
+ }
+
+ @Override
+ public void clip(Shape s) {
+ canvasGraphics.clip(s);
+ }
+
+ @Override
+ public void draw(Shape s) {
+ canvasGraphics.draw(s);
+ if (drawingComponent && trackingAllowed) {
+ appendShapeOutline(s);
+ }
+ }
+
+ @Override
+ public void drawGlyphVector(GlyphVector g, float x, float y) {
+ canvasGraphics.drawGlyphVector(g, x, y);
+ }
+
+ @Override
+ public boolean drawImage(Image img, AffineTransform xform, ImageObserver obs) {
+ // FIXME: process map
+ return canvasGraphics.drawImage(img, xform, obs);
+ }
+
+ @Override
+ public void drawImage(BufferedImage img, BufferedImageOp op, int x, int y) {
+ canvasGraphics.drawImage(img, op, x, y);
+ // FIXME: process map
+ }
+
+ @Override
+ public void drawRenderableImage(RenderableImage img, AffineTransform xform) {
+ canvasGraphics.drawRenderableImage(img, xform);
+ // FIXME: process map
+ }
+
+ @Override
+ public void drawRenderedImage(RenderedImage img, AffineTransform xform) {
+ canvasGraphics.drawRenderedImage(img, xform);
+ // FIXME: process map
+ }
+
+ @Override
+ public void drawString(String str, int x, int y) {
+ canvasGraphics.drawString(str, x, y);
+ if (drawingComponent && trackingAllowed) {
+ FontMetrics fontMetrics = canvasGraphics.getFontMetrics();
+ Rectangle2D rect = fontMetrics.getStringBounds(str, canvasGraphics);
+ Point2D point = new Point2D.Double(x, y);
+ // currentTx.transform(point, point);
+ Rectangle2D finalRec =
+ new Rectangle2D.Double(rect.getX() + point.getX(), rect.getY() + point.getY(), rect.getWidth(),
+ rect.getHeight());
+ appendShape(finalRec);
+ }
+ }
+
+ @Override
+ public void drawString(String str, float x, float y) {
+ canvasGraphics.drawString(str, x, y);
+ if (drawingComponent && trackingAllowed) {
+ FontMetrics fontMetrics = canvasGraphics.getFontMetrics();
+ Rectangle2D rect = fontMetrics.getStringBounds(str, canvasGraphics);
+ appendShape(new Rectangle2D.Double(rect.getX() + x, rect.getY() + y, rect.getWidth(), rect.getHeight()));
+ }
+ }
+
+ @Override
+ public void drawString(AttributedCharacterIterator iterator, int x, int y) {
+ canvasGraphics.drawString(iterator, x, y);
+ // FIXME: process map
+ }
+
+ @Override
+ public void drawString(AttributedCharacterIterator iterator, float x, float y) {
+ canvasGraphics.drawString(iterator, x, y);
+ // FIXME: process map
+ }
+
+ @Override
+ public void fill(Shape s) {
+ canvasGraphics.fill(s);
+ appendShape(s);
+ }
+
+ @Override
+ public Color getBackground() {
+ return canvasGraphics.getBackground();
+ }
+
+ @Override
+ public Composite getComposite() {
+ return canvasGraphics.getComposite();
+ }
+
+ @Override
+ public GraphicsConfiguration getDeviceConfiguration() {
+ return canvasGraphics.getDeviceConfiguration();
+ }
+
+ @Override
+ public FontRenderContext getFontRenderContext() {
+ return canvasGraphics.getFontRenderContext();
+ }
+
+ @Override
+ public Paint getPaint() {
+ return canvasGraphics.getPaint();
+ }
+
+ @Override
+ public Object getRenderingHint(Key hintKey) {
+ return canvasGraphics.getRenderingHint(hintKey);
+ }
+
+ @Override
+ public RenderingHints getRenderingHints() {
+ return canvasGraphics.getRenderingHints();
+ }
+
+ @Override
+ public Stroke getStroke() {
+ return canvasGraphics.getStroke();
+ }
+
+ @Override
+ public AffineTransform getTransform() {
+ return canvasGraphics.getTransform();
+ }
+
+ @Override
+ public boolean hit(Rectangle rect, Shape s, boolean onStroke) {
+ return canvasGraphics.hit(rect, s, onStroke);
+ }
+
+ @Override
+ public void rotate(double theta) {
+ canvasGraphics.rotate(theta);
+ currentTx.rotate(theta);
+ }
+
+ @Override
+ public void rotate(double theta, double x, double y) {
+ canvasGraphics.rotate(theta, x, y);
+ currentTx.rotate(theta, x, y);
+ }
+
+ @Override
+ public void scale(double sx, double sy) {
+ canvasGraphics.scale(sx, sy);
+ currentTx.scale(sx, sy);
+ }
+
+ @Override
+ public void setBackground(Color color) {
+ canvasGraphics.setBackground(color);
+ // FIXME: fix map
+ }
+
+ @Override
+ public void setComposite(Composite comp) {
+ canvasGraphics.setComposite(comp);
+ // FIXME: check this.
+ }
+
+ @Override
+ public void setPaint(Paint paint) {
+ canvasGraphics.setPaint(paint);
+ // FIXME: check this
+ }
+
+ @Override
+ public void setRenderingHint(Key hintKey, Object hintValue) {
+ canvasGraphics.setRenderingHint(hintKey, hintValue);
+ // FIXME: check this
+ }
+
+ @Override
+ public void setRenderingHints(Map, ?> hints) {
+ canvasGraphics.setRenderingHints(hints);
+ // FIXME: check this
+ }
+
+ @Override
+ public void setStroke(Stroke s) {
+ if (this.zoom > 1 && s.getClass() == BasicStroke.class) {
+ BasicStroke bs = (BasicStroke) s;
+ // make thin lines even thinner to compensate for zoom factor
+ if (bs.getLineWidth() <= 2)
+ s = ObjectCache.getInstance().fetchBasicStroke((float) (bs.getLineWidth() / zoom));
+ }
+ canvasGraphics.setStroke(s);
+ }
+
+ @Override
+ public void setTransform(AffineTransform Tx) {
+ canvasGraphics.setTransform(Tx);
+ currentTx = new AffineTransform(Tx);
+ try {
+ // Invert the tx that was set before we started drawing the component.
+ // We're left only component tx.
+ AffineTransform inverseInitialTx = initialTx.createInverse();
+ Point2D p = new Point2D.Double(currentTx.getTranslateX(), currentTx.getTranslateY());
+ inverseInitialTx.transform(p, p);
+ currentTx.concatenate(inverseInitialTx);
+ double[] matrix = new double[6];
+ currentTx.getMatrix(matrix);
+ currentTx.setTransform(matrix[0], matrix[1], matrix[2], matrix[3], p.getX(), p.getY());
+ } catch (NoninvertibleTransformException e) {
+ }
+ }
+
+ @Override
+ public void shear(double shx, double shy) {
+ canvasGraphics.shear(shx, shy);
+ currentTx.shear(shx, shy);
+ }
+
+ @Override
+ public void transform(AffineTransform Tx) {
+ canvasGraphics.transform(Tx);
+ currentTx.concatenate(Tx);
+ }
+
+ @Override
+ public void translate(int x, int y) {
+ canvasGraphics.translate(x, y);
+ currentTx.translate(x, y);
+ }
+
+ @Override
+ public void translate(double tx, double ty) {
+ canvasGraphics.translate(tx, ty);
+ currentTx.translate(tx, ty);
+ }
+
+ @Override
+ public void clearRect(int x, int y, int width, int height) {
+ canvasGraphics.clearRect(x, y, width, height);
+ }
+
+ @Override
+ public void clipRect(int x, int y, int width, int height) {
+ canvasGraphics.clipRect(x, y, width, height);
+ }
+
+ @Override
+ public void copyArea(int x, int y, int width, int height, int dx, int dy) {
+ canvasGraphics.copyArea(x, y, width, height, dx, dy);
+ }
+
+ @Override
+ public Graphics create() {
+ return canvasGraphics.create();
+ }
+
+ @Override
+ public void dispose() {
+ canvasGraphics.dispose();
+ }
+
+ @Override
+ public void drawArc(int x, int y, int width, int height, int startAngle, int arcAngle) {
+ canvasGraphics.drawArc(x, y, width, height, startAngle, arcAngle);
+ }
+
+ @Override
+ public boolean drawImage(Image img, int x, int y, ImageObserver observer) {
+ boolean result = canvasGraphics.drawImage(img, x, y, observer);
+ appendShape(new Rectangle2D.Double(x, y, img.getWidth(observer), img.getHeight(observer)));
+ return result;
+ }
+
+ @Override
+ public boolean drawImage(Image img, int x, int y, Color bgcolor, ImageObserver observer) {
+ // FIXME: map
+ return canvasGraphics.drawImage(img, x, y, bgcolor, observer);
+ }
+
+ @Override
+ public boolean drawImage(Image img, int x, int y, int width, int height, ImageObserver observer) {
+ // FIXME: map
+ return canvasGraphics.drawImage(img, x, y, width, height, observer);
+ }
+
+ @Override
+ public boolean drawImage(Image img, int x, int y, int width, int height, Color bgcolor, ImageObserver observer) {
+ // FIXME: map
+ return canvasGraphics.drawImage(img, x, y, width, height, bgcolor, observer);
+ }
+
+ @Override
+ public boolean drawImage(Image img, int dx1, int dy1, int dx2, int dy2, int sx1, int sy1, int sx2, int sy2,
+ ImageObserver observer) {
+ // FIXME: map
+ return canvasGraphics.drawImage(img, dx1, dy1, dx2, dy2, sx1, sy1, sx2, sy2, observer);
+ }
+
+ @Override
+ public boolean drawImage(Image img, int dx1, int dy1, int dx2, int dy2, int sx1, int sy1, int sx2, int sy2,
+ Color bgcolor, ImageObserver observer) {
+ // FIXME: map
+ return drawImage(img, dx1, dy1, dx2, dy2, sx1, sy1, sx2, sy2, bgcolor, observer);
+ }
+
+ @Override
+ public void drawLine(int x1, int y1, int x2, int y2) {
+ canvasGraphics.drawLine(x1, y1, x2, y2);
+ if (drawingComponent && (trackingAllowed || trackingContinuityAllowed)) {
+ appendShapeOutline(new Line2D.Double(x1, y1, x2, y2));
+ }
+ }
+
+ @Override
+ public void drawOval(int x, int y, int width, int height) {
+ canvasGraphics.drawOval(x, y, width, height);
+ if (drawingComponent && (trackingAllowed || trackingContinuityAllowed)) {
+ appendShapeOutline(new Ellipse2D.Double(x, y, width, height));
+ }
+ }
+
+ @Override
+ public void drawPolygon(int[] points, int[] points2, int points3) {
+ canvasGraphics.drawPolygon(points, points2, points3);
+ if (drawingComponent && (trackingAllowed || trackingContinuityAllowed)) {
+ appendShapeOutline(new Polygon(points, points2, points3));
+ }
+ }
+
+ @Override
+ public void drawPolyline(int[] points, int[] points2, int points3) {
+ canvasGraphics.drawPolyline(points, points2, points3);
+ }
+
+ @Override
+ public void drawRoundRect(int x, int y, int width, int height, int arcWidth, int arcHeight) {
+ canvasGraphics.drawRoundRect(x, y, width, height, arcWidth, arcHeight);
+ if (drawingComponent && (trackingAllowed || trackingContinuityAllowed)) {
+ appendShapeOutline(new RoundRectangle2D.Double(x, y, width, height, arcWidth, arcHeight));
+ }
+ }
+
+ @Override
+ public void fillArc(int x, int y, int width, int height, int startAngle, int arcAngle) {
+ canvasGraphics.fillArc(x, y, width, height, startAngle, arcAngle);
+ if (drawingComponent && (trackingAllowed || trackingContinuityAllowed)) {
+ appendShape(new Arc2D.Double(x, y, width, height, startAngle, arcAngle, Arc2D.PIE));
+ }
+ }
+
+ @Override
+ public void fillOval(int x, int y, int width, int height) {
+ canvasGraphics.fillOval(x, y, width, height);
+ if (drawingComponent && (trackingAllowed || trackingContinuityAllowed)) {
+ appendShape(new Ellipse2D.Double(x, y, width, height));
+ }
+ }
+
+ @Override
+ public void fillPolygon(int[] points, int[] points2, int points3) {
+ canvasGraphics.fillPolygon(points, points2, points3);
+ if (drawingComponent && (trackingAllowed || trackingContinuityAllowed)) {
+ appendShape(new Polygon(points, points2, points3));
+ }
+ }
+
+ @Override
+ public void drawRect(int x, int y, int width, int height) {
+ canvasGraphics.drawRect(x, y, width, height);
+ if (drawingComponent && (trackingAllowed || trackingContinuityAllowed)) {
+ appendShapeOutline(new Rectangle(x, y, width, height));
+ }
+ }
+
+ @Override
+ public void fillRect(int x, int y, int width, int height) {
+ canvasGraphics.fillRect(x, y, width, height);
+ if (drawingComponent && (trackingAllowed || trackingContinuityAllowed)) {
+ appendShape(new Rectangle(x, y, width, height));
+ }
+ }
+
+ @Override
+ public void fillRoundRect(int x, int y, int width, int height, int arcWidth, int arcHeight) {
+ canvasGraphics.fillRoundRect(x, y, width, height, arcWidth, arcHeight);
+ if (drawingComponent && (trackingAllowed || trackingContinuityAllowed)) {
+ appendShape(new RoundRectangle2D.Double(x, y, width, height, arcWidth, arcHeight));
+ }
+ }
+
+ @Override
+ public Shape getClip() {
+ return canvasGraphics.getClip();
+ }
+
+ @Override
+ public Rectangle getClipBounds() {
+ return canvasGraphics.getClipBounds();
+ }
+
+ @Override
+ public Color getColor() {
+ return canvasGraphics.getColor();
+ }
+
+ @Override
+ public Font getFont() {
+ return canvasGraphics.getFont();
+ }
+
+ @Override
+ public FontMetrics getFontMetrics(Font f) {
+ return canvasGraphics.getFontMetrics(f);
+ }
+
+ @Override
+ public void setClip(Shape clip) {
+ canvasGraphics.setClip(clip);
+ }
+
+ @Override
+ public void setClip(int x, int y, int width, int height) {
+ canvasGraphics.setClip(x, y, width, height);
+ }
+
+ @Override
+ public void setColor(Color c) {
+ canvasGraphics.setColor(c);
+ }
+
+ @Override
+ public void setFont(Font font) {
+ canvasGraphics.setFont(font);
+ }
+
+ @Override
+ public void setPaintMode() {
+ canvasGraphics.setPaintMode();
+ }
+
+ @Override
+ public void setXORMode(Color c1) {
+ canvasGraphics.setXORMode(c1);
+ }
+}
diff --git a/diylc/diylc-core/src/org/diylc/presenter/InstantiationManager.java b/diylc/diylc-core/src/org/diylc/presenter/InstantiationManager.java
index 6b44885a..7ef31690 100644
--- a/diylc/diylc-core/src/org/diylc/presenter/InstantiationManager.java
+++ b/diylc/diylc-core/src/org/diylc/presenter/InstantiationManager.java
@@ -63,7 +63,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, null, KeywordPolicy.NEVER_SHOW, null);
+ false, null, KeywordPolicy.NEVER_SHOW, null, false);
public InstantiationManager() {}
diff --git a/diylc/diylc-core/src/org/diylc/presenter/Presenter.java b/diylc/diylc-core/src/org/diylc/presenter/Presenter.java
index eba2a4d8..d53ea4fc 100644
--- a/diylc/diylc-core/src/org/diylc/presenter/Presenter.java
+++ b/diylc/diylc-core/src/org/diylc/presenter/Presenter.java
@@ -21,63 +21,63 @@
*/
package org.diylc.presenter;
-import java.awt.Cursor;
-import java.awt.Dimension;
-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.awt.geom.Rectangle2D;
-import java.io.BufferedInputStream;
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.IOException;
-import java.lang.reflect.Modifier;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.Comparator;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
-import javax.swing.JOptionPane;
-
-import org.apache.log4j.Logger;
-import org.diylc.appframework.miscutils.ConfigurationManager;
-import org.diylc.appframework.miscutils.Utils;
-import org.diylc.appframework.simplemq.MessageDispatcher;
-import org.diylc.appframework.update.Version;
-import org.diylc.appframework.update.VersionNumber;
-import org.diylc.common.ComponentType;
-import org.diylc.common.DrawOption;
-import org.diylc.common.EventType;
-import org.diylc.common.IComponentFiler;
-import org.diylc.common.IComponentTransformer;
-import org.diylc.common.IKeyProcessor;
-import org.diylc.common.IPlugIn;
-import org.diylc.common.IPlugInPort;
-import org.diylc.common.PropertyWrapper;
-import org.diylc.core.ExpansionMode;
-import org.diylc.core.IDIYComponent;
-import org.diylc.core.IView;
-import org.diylc.core.Project;
-import org.diylc.core.Template;
-import org.diylc.core.Theme;
-import org.diylc.core.annotations.IAutoCreator;
-import org.diylc.core.measures.Size;
-import org.diylc.core.measures.SizeUnit;
-import org.diylc.utils.Constants;
-
-import com.thoughtworks.xstream.XStream;
-import com.thoughtworks.xstream.io.xml.DomDriver;
+import java.awt.Cursor;
+import java.awt.Dimension;
+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.awt.geom.Rectangle2D;
+import java.io.BufferedInputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.lang.reflect.Modifier;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import javax.swing.JOptionPane;
+
+import org.apache.log4j.Logger;
+import org.diylc.appframework.miscutils.ConfigurationManager;
+import org.diylc.appframework.miscutils.Utils;
+import org.diylc.appframework.simplemq.MessageDispatcher;
+import org.diylc.appframework.update.Version;
+import org.diylc.appframework.update.VersionNumber;
+import org.diylc.common.ComponentType;
+import org.diylc.common.DrawOption;
+import org.diylc.common.EventType;
+import org.diylc.common.IComponentFiler;
+import org.diylc.common.IComponentTransformer;
+import org.diylc.common.IKeyProcessor;
+import org.diylc.common.IPlugIn;
+import org.diylc.common.IPlugInPort;
+import org.diylc.common.PropertyWrapper;
+import org.diylc.core.ExpansionMode;
+import org.diylc.core.IDIYComponent;
+import org.diylc.core.IView;
+import org.diylc.core.Project;
+import org.diylc.core.Template;
+import org.diylc.core.Theme;
+import org.diylc.core.annotations.IAutoCreator;
+import org.diylc.core.measures.Size;
+import org.diylc.core.measures.SizeUnit;
+import org.diylc.utils.Constants;
+
+import com.thoughtworks.xstream.XStream;
+import com.thoughtworks.xstream.io.xml.DomDriver;
/**
* The main presenter class, contains core app logic and drawing routines.
@@ -132,7 +132,7 @@ public class Presenter implements IPlugInPort {
private ProjectFileManager projectFileManager;
private InstantiationManager instantiationManager;
- private Rectangle selectionRect;
+ private Rectangle selectionRect;
private final IView view;
@@ -148,7 +148,7 @@ public class Presenter implements IPlugInPort {
private Point previousDragPoint = null;
private Project preDragProject = null;
private int dragAction;
- private Point previousScaledPoint;
+ private Point previousScaledPoint;
public Presenter(IView view) {
super();
@@ -212,8 +212,8 @@ public class Presenter implements IPlugInPort {
}
for (IDIYComponent> component : currentProject.getComponents()) {
if (!isComponentLocked(component) && isComponentVisible(component)) {
- Area area = drawingManager.getComponentArea(component);
- if (area != null && area.contains(scaledPoint)) {
+ ComponentArea area = drawingManager.getComponentArea(component);
+ if (area != null && area.getOutlineArea() != null && area.getOutlineArea().contains(scaledPoint)) {
return Cursor.getPredefinedCursor(Cursor.HAND_CURSOR);
}
}
@@ -599,7 +599,10 @@ public class Presenter implements IPlugInPort {
messageDispatcher.dispatchMessage(EventType.PROJECT_MODIFIED, oldProject, currentProject.clone(), "Add "
+ componentTypeSlot.getName());
projectFileManager.notifyFileChange();
- }
+ }
+ } else if (ConfigurationManager.getInstance().readBoolean(HIGHLIGHT_CONTINUITY_AREA, false)) {
+ drawingManager.findContinuityAreaAtPoint(currentProject, scaledPoint);
+ messageDispatcher.dispatchMessage(EventType.REPAINT);
} else {
List> newSelection = new ArrayList>(selectedComponents);
List> components = findComponentsAtScaled(scaledPoint);
@@ -867,11 +870,11 @@ public class Presenter implements IPlugInPort {
Area totalArea = new Area();
for (IDIYComponent> c : selectedComponents) {
- Area compArea = drawingManager.getComponentArea(c);
- if (compArea != null)
- totalArea.add(compArea);
+ ComponentArea compArea = drawingManager.getComponentArea(c);
+ if (compArea != null && compArea.getOutlineArea() != null)
+ totalArea.add(compArea.getOutlineArea());
else
- LOG.info("Area is null");
+ LOG.debug("Area is null");
}
if (drawingManager.getZoomLevel() != 1 && applyZoom) {
totalArea
@@ -1397,8 +1400,8 @@ public class Presenter implements IPlugInPort {
List> newSelection = new ArrayList>();
for (IDIYComponent> component : currentProject.getComponents()) {
if (!isComponentLocked(component) && isComponentVisible(component)) {
- Area area = drawingManager.getComponentArea(component);
- if ((area != null) && (selectionRect != null) && area.intersects(selectionRect)) {
+ ComponentArea area = drawingManager.getComponentArea(component);
+ if ((area != null && area.getOutlineArea() != null) && (selectionRect != null) && area.getOutlineArea().intersects(selectionRect)) {
newSelection.addAll(findAllGroupedComponents(component));
}
}
@@ -1801,16 +1804,16 @@ public class Presenter implements IPlugInPort {
for (IDIYComponent> component : getCurrentProject().getComponents()) {
// Skip already selected components or ones that cannot be stuck to
// other components.
- Area area = drawingManager.getComponentArea(component);
- if (newSelection.contains(component) || !component.isControlPointSticky(0) || area == null)
+ ComponentArea area = drawingManager.getComponentArea(component);
+ if (newSelection.contains(component) || !component.isControlPointSticky(0) || area == null || area.getOutlineArea() == null)
continue;
boolean matches = false;
for (IDIYComponent> selectedComponent : this.selectedComponents) {
- Area selectedArea = drawingManager.getComponentArea(selectedComponent);
- if (selectedArea == null)
+ ComponentArea selectedArea = drawingManager.getComponentArea(selectedComponent);
+ if (selectedArea == null || selectedArea.getOutlineArea() == null)
continue;
- Area intersection = new Area(area);
- intersection.intersect(selectedArea);
+ Area intersection = new Area(area.getOutlineArea());
+ intersection.intersect(selectedArea.getOutlineArea());
if (!intersection.isEmpty()) {
matches = true;
break;
diff --git a/diylc/diylc-library/lib/diylc-core.jar b/diylc/diylc-library/lib/diylc-core.jar
index a5a4c34f..493dad85 100644
Binary files a/diylc/diylc-library/lib/diylc-core.jar and b/diylc/diylc-library/lib/diylc-core.jar differ
diff --git a/diylc/diylc-library/src/org/diylc/components/boards/TerminalStrip.java b/diylc/diylc-library/src/org/diylc/components/boards/TerminalStrip.java
index ea6e6f97..d1f64211 100644
--- a/diylc/diylc-library/src/org/diylc/components/boards/TerminalStrip.java
+++ b/diylc/diylc-library/src/org/diylc/components/boards/TerminalStrip.java
@@ -376,8 +376,10 @@ public class TerminalStrip extends AbstractTransparentComponent {
g2d.setColor(finalBorderColor);
g2d.draw(mainArea);
- g2d.setColor(outlineMode ? Constants.TRANSPARENT_COLOR : TERMINAL_COLOR);
- g2d.fill(terminalArea);
+ g2d.setColor(outlineMode ? Constants.TRANSPARENT_COLOR : TERMINAL_COLOR);
+ drawingObserver.startTrackingContinuityArea(true);
+ g2d.fill(terminalArea);
+ drawingObserver.stopTrackingContinuityArea();
Color finalTerminalBorderColor;
if (outlineMode) {
diff --git a/diylc/diylc-library/src/org/diylc/components/boards/TriPadBoard.java b/diylc/diylc-library/src/org/diylc/components/boards/TriPadBoard.java
index 3fee6f1b..ab77cd15 100644
--- a/diylc/diylc-library/src/org/diylc/components/boards/TriPadBoard.java
+++ b/diylc/diylc-library/src/org/diylc/components/boards/TriPadBoard.java
@@ -94,9 +94,11 @@ public class TriPadBoard extends AbstractBoard {
spacesToDraw = (remainingSpace - stripSize) / spacing;
}
- g2d.setColor(stripColor);
+ g2d.setColor(stripColor);
+ drawingObserver.startTrackingContinuityArea(true);
g2d.fillRect(p.x + spacing - stripSize / 2, p.y - stripSize / 2, spacing * (spacesToDraw - 1) + stripSize,
- stripSize);
+ stripSize);
+ drawingObserver.stopTrackingContinuityArea();
g2d.setColor(stripColor.darker());
g2d.drawRect(p.x + spacing - stripSize / 2, p.y - stripSize / 2, spacing * (spacesToDraw - 1) + stripSize,
@@ -130,9 +132,11 @@ public class TriPadBoard extends AbstractBoard {
spacesToDraw = (remainingSpace - stripSize) / spacing;
}
- g2d.setColor(stripColor);
+ g2d.setColor(stripColor);
+ drawingObserver.startTrackingContinuityArea(true);
g2d.fillRect(p.x - stripSize / 2, p.y + spacing - stripSize / 2, stripSize, spacing * (spacesToDraw - 1)
- + stripSize);
+ + stripSize);
+ drawingObserver.stopTrackingContinuityArea();
g2d.setColor(stripColor.darker());
g2d.drawRect(p.x - stripSize / 2, p.y + spacing - stripSize / 2, stripSize, spacing * (spacesToDraw - 1)
+ stripSize);
diff --git a/diylc/diylc-library/src/org/diylc/components/boards/VeroBoard.java b/diylc/diylc-library/src/org/diylc/components/boards/VeroBoard.java
index 392a34c5..18e32707 100644
--- a/diylc/diylc-library/src/org/diylc/components/boards/VeroBoard.java
+++ b/diylc/diylc-library/src/org/diylc/components/boards/VeroBoard.java
@@ -84,8 +84,10 @@ public class VeroBoard extends AbstractBoard {
while (p.y < secondPoint.y - spacing) {
p.x = firstPoint.x;
p.y += spacing;
- g2d.setColor(stripColor);
- g2d.fillRect(p.x + spacing / 2, p.y - stripSize / 2, secondPoint.x - spacing - p.x, stripSize);
+ g2d.setColor(stripColor);
+ drawingObserver.startTrackingContinuityArea(true);
+ g2d.fillRect(p.x + spacing / 2, p.y - stripSize / 2, secondPoint.x - spacing - p.x, stripSize);
+ drawingObserver.stopTrackingContinuityArea();
g2d.setColor(stripColor.darker());
g2d.drawRect(p.x + spacing / 2, p.y - stripSize / 2, secondPoint.x - spacing - p.x, stripSize);
while (p.x < secondPoint.x - spacing - holeSize) {
@@ -100,8 +102,10 @@ public class VeroBoard extends AbstractBoard {
while (p.x < secondPoint.x - spacing) {
p.x += spacing;
p.y = firstPoint.y;
- g2d.setColor(stripColor);
- g2d.fillRect(p.x - stripSize / 2, p.y + spacing / 2, stripSize, secondPoint.y - spacing - p.y);
+ g2d.setColor(stripColor);
+ drawingObserver.startTrackingContinuityArea(true);
+ g2d.fillRect(p.x - stripSize / 2, p.y + spacing / 2, stripSize, secondPoint.y - spacing - p.y);
+ drawingObserver.stopTrackingContinuityArea();
g2d.setColor(stripColor.darker());
g2d.drawRect(p.x - stripSize / 2, p.y + spacing / 2, stripSize, secondPoint.y - spacing - p.y);
while (p.y < secondPoint.y - spacing - holeSize) {
diff --git a/diylc/diylc-library/src/org/diylc/components/connectivity/CurvedTrace.java b/diylc/diylc-library/src/org/diylc/components/connectivity/CurvedTrace.java
index 9337c90e..9d5f8388 100644
--- a/diylc/diylc-library/src/org/diylc/components/connectivity/CurvedTrace.java
+++ b/diylc/diylc-library/src/org/diylc/components/connectivity/CurvedTrace.java
@@ -24,13 +24,14 @@ package org.diylc.components.connectivity;
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.geom.CubicCurve2D;
-
+
import org.diylc.common.SimpleComponentTransformer;
import org.diylc.common.ObjectCache;
import org.diylc.common.PCBLayer;
import org.diylc.components.AbstractCurvedComponent;
import org.diylc.core.ComponentState;
import org.diylc.core.IDIYComponent;
+import org.diylc.core.IDrawingObserver;
import org.diylc.core.annotations.BomPolicy;
import org.diylc.core.annotations.ComponentDescriptor;
import org.diylc.core.annotations.EditableProperty;
@@ -58,14 +59,16 @@ public class CurvedTrace extends AbstractCurvedComponent {
}
@Override
- protected void drawCurve(CubicCurve2D curve, Graphics2D g2d, ComponentState componentState) {
+ protected void drawCurve(CubicCurve2D curve, Graphics2D g2d, ComponentState componentState, IDrawingObserver drawingObserver) {
float thickness = (float) size.convertToPixels();
g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(thickness));
Color curveColor =
componentState == ComponentState.SELECTED || componentState == ComponentState.DRAGGING ? SELECTION_COLOR
: color;
- g2d.setColor(curveColor);
- g2d.draw(curve);
+ g2d.setColor(curveColor);
+ drawingObserver.startTrackingContinuityArea(true);
+ g2d.draw(curve);
+ drawingObserver.stopTrackingContinuityArea();
}
@EditableProperty(name = "Width")
diff --git a/diylc/diylc-library/src/org/diylc/components/connectivity/HookupWire.java b/diylc/diylc-library/src/org/diylc/components/connectivity/HookupWire.java
index 972e9322..b1d6dd9c 100644
--- a/diylc/diylc-library/src/org/diylc/components/connectivity/HookupWire.java
+++ b/diylc/diylc-library/src/org/diylc/components/connectivity/HookupWire.java
@@ -24,12 +24,13 @@ package org.diylc.components.connectivity;
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.geom.CubicCurve2D;
-
+
import org.diylc.common.ObjectCache;
import org.diylc.common.SimpleComponentTransformer;
import org.diylc.components.AbstractCurvedComponent;
import org.diylc.core.ComponentState;
import org.diylc.core.IDIYComponent;
+import org.diylc.core.IDrawingObserver;
import org.diylc.core.annotations.BomPolicy;
import org.diylc.core.annotations.ComponentDescriptor;
import org.diylc.core.annotations.EditableProperty;
@@ -38,7 +39,7 @@ import org.diylc.utils.Constants;
@ComponentDescriptor(name = "Hookup Wire", author = "Branislav Stojkovic", category = "Connectivity",
instanceNamePrefix = "W", description = "Flexible wire with two control points", zOrder = IDIYComponent.COMPONENT,
flexibleZOrder = true, bomPolicy = BomPolicy.NEVER_SHOW, autoEdit = false,
- transformer = SimpleComponentTransformer.class)
+ transformer = SimpleComponentTransformer.class, continuity = true)
public class HookupWire extends AbstractCurvedComponent {
private static final long serialVersionUID = 1L;
@@ -54,7 +55,7 @@ public class HookupWire extends AbstractCurvedComponent {
}
@Override
- protected void drawCurve(CubicCurve2D curve, Graphics2D g2d, ComponentState componentState) {
+ protected void drawCurve(CubicCurve2D curve, Graphics2D g2d, ComponentState componentState, IDrawingObserver drawingObserver) {
int thickness =
(int) (Math.pow(Math.E, -1.12436 - 0.11594 * gauge.getValue()) * Constants.PIXELS_PER_INCH * (1 + 2 * INSULATION_THICKNESS_PCT));
Color curveColor =
diff --git a/diylc/diylc-library/src/org/diylc/components/connectivity/Jumper.java b/diylc/diylc-library/src/org/diylc/components/connectivity/Jumper.java
index 8e59b0a8..95670911 100644
--- a/diylc/diylc-library/src/org/diylc/components/connectivity/Jumper.java
+++ b/diylc/diylc-library/src/org/diylc/components/connectivity/Jumper.java
@@ -40,7 +40,7 @@ import org.diylc.core.measures.Size;
@ComponentDescriptor(name = "Jumper", author = "Branislav Stojkovic", category = "Connectivity",
creationMethod = CreationMethod.POINT_BY_POINT, instanceNamePrefix = "J", description = "",
zOrder = IDIYComponent.COMPONENT, bomPolicy = BomPolicy.NEVER_SHOW, autoEdit = false,
- transformer = SimpleComponentTransformer.class)
+ transformer = SimpleComponentTransformer.class, continuity = true)
public class Jumper extends AbstractLeadedComponent {
private static final long serialVersionUID = 1L;
diff --git a/diylc/diylc-library/src/org/diylc/components/connectivity/TraceCut.java b/diylc/diylc-library/src/org/diylc/components/connectivity/TraceCut.java
index 9222254f..415533f3 100644
--- a/diylc/diylc-library/src/org/diylc/components/connectivity/TraceCut.java
+++ b/diylc/diylc-library/src/org/diylc/components/connectivity/TraceCut.java
@@ -77,16 +77,20 @@ public class TraceCut extends AbstractComponent {
if (getCutBetweenHoles()) {
int holeSpacing = getClosestOdd(getHoleSpacing().convertToPixels());
g2d.setColor(componentState == ComponentState.SELECTED || componentState == ComponentState.DRAGGING ? SELECTION_COLOR
- : boardColor);
- g2d.fillRect(point.x - holeSpacing / 2 - cutWidth / 2, point.y - size / 2 - 1, cutWidth, size + 2);
+ : boardColor);
+ drawingObserver.startTrackingContinuityArea(false);
+ g2d.fillRect(point.x - holeSpacing / 2 - cutWidth / 2, point.y - size / 2 - 1, cutWidth, size + 2);
+ drawingObserver.stopTrackingContinuityArea();
} else {
g2d.setColor(componentState == ComponentState.SELECTED || componentState == ComponentState.DRAGGING ? SELECTION_COLOR
- : boardColor);
- g2d.fillRoundRect(point.x - size / 2, point.y - size / 2, size, size, size, size);
+ : boardColor);
+ drawingObserver.startTrackingContinuityArea(false);
+ g2d.fillRoundRect(point.x - size / 2, point.y - size / 2, size, size, size, size);
+ drawingObserver.stopTrackingContinuityArea();
g2d.setColor(Constants.CANVAS_COLOR);
- int holeSize = getClosestOdd((int) HOLE_SIZE.convertToPixels());
- g2d.fillOval(point.x - holeSize / 2, point.y - holeSize / 2, holeSize, holeSize);
+ int holeSize = getClosestOdd((int) HOLE_SIZE.convertToPixels());
+ g2d.fillOval(point.x - holeSize / 2, point.y - holeSize / 2, holeSize, holeSize);
g2d.setColor(boardColor.darker());
g2d.drawOval(point.x - holeSize / 2, point.y - holeSize / 2, holeSize, holeSize);
}
diff --git a/diylc/diylc-swing/DIYLCStarter.launch b/diylc/diylc-swing/DIYLCStarter.launch
index 6d1af050..e44ede70 100644
--- a/diylc/diylc-swing/DIYLCStarter.launch
+++ b/diylc/diylc-swing/DIYLCStarter.launch
@@ -11,5 +11,5 @@
-
+
diff --git a/diylc/diylc-swing/lib/diylc-core.jar b/diylc/diylc-swing/lib/diylc-core.jar
index a5a4c34f..493dad85 100644
Binary files a/diylc/diylc-swing/lib/diylc-core.jar and b/diylc/diylc-swing/lib/diylc-core.jar differ
diff --git a/diylc/diylc-swing/library/main.jar b/diylc/diylc-swing/library/main.jar
index 52047902..a2e31ed0 100644
Binary files a/diylc/diylc-swing/library/main.jar and b/diylc/diylc-swing/library/main.jar differ
diff --git a/diylc/diylc-swing/src/org/diylc/swing/plugins/config/ConfigPlugin.java b/diylc/diylc-swing/src/org/diylc/swing/plugins/config/ConfigPlugin.java
index 70f44385..d939a0cf 100644
--- a/diylc/diylc-swing/src/org/diylc/swing/plugins/config/ConfigPlugin.java
+++ b/diylc/diylc-swing/src/org/diylc/swing/plugins/config/ConfigPlugin.java
@@ -99,7 +99,10 @@ public class ConfigPlugin implements IPlugIn {
CONFIG_MENU);
swingUI.injectMenuAction(
ActionFactory.getInstance()
- .createConfigAction(plugInPort, "Sticky Points", IPlugInPort.STICKY_POINTS_KEY, true), CONFIG_MENU);
+ .createConfigAction(plugInPort, "Sticky Points", IPlugInPort.STICKY_POINTS_KEY, true), CONFIG_MENU);
+ swingUI.injectMenuAction(
+ ActionFactory.getInstance()
+ .createConfigAction(plugInPort, "Highlighted Connected Areas", IPlugInPort.HIGHLIGHT_CONTINUITY_AREA, false), CONFIG_MENU);
File themeDir = new File("themes");
if (themeDir.exists()) {
diff --git a/diylc/diylc-swing/update.xml b/diylc/diylc-swing/update.xml
index 36ce7f7f..dc43667b 100644
--- a/diylc/diylc-swing/update.xml
+++ b/diylc/diylc-swing/update.xml
@@ -1874,6 +1874,10 @@
2018-12-11 00:00:00.000 CET
+
+ NEW_FEATURE
+ Highlight connected areas through copper traces, leads, jumpers, etc...
+
NEW_FEATURE
Holding "shift" key switches mouse wheel scrolling function from vertical to horizontal