diff --git a/ diy-layout-creator --username bancika@gmail.com/DIYLC/src/org/diylc/presenter/Presenter.java b/ diy-layout-creator --username bancika@gmail.com/DIYLC/src/org/diylc/presenter/Presenter.java index ed184ecb..daf4acd6 100644 --- a/ diy-layout-creator --username bancika@gmail.com/DIYLC/src/org/diylc/presenter/Presenter.java +++ b/ diy-layout-creator --username bancika@gmail.com/DIYLC/src/org/diylc/presenter/Presenter.java @@ -1,13 +1,10 @@ package org.diylc.presenter; -import java.awt.BasicStroke; -import java.awt.Color; import java.awt.Cursor; 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.Point2D; import java.io.FileInputStream; @@ -41,7 +38,6 @@ import org.diylc.common.IComponentFiler; import org.diylc.common.IPlugIn; import org.diylc.common.IPlugInPort; import org.diylc.common.PropertyWrapper; -import org.diylc.core.ComponentState; import org.diylc.core.IDIYComponent; import org.diylc.core.Project; import org.diylc.core.measures.SizeUnit; @@ -70,13 +66,9 @@ public class Presenter implements IPlugInPort { public static final String DEFAULTS_KEY = "default."; public static final String METRIC_KEY = "metric"; - public static final int CONTROL_POINT_SIZE = 5; public static final int ICON_SIZE = 32; - public static boolean ENABLE_ANTIALIASING = true; - public static boolean DEBUG_COMPONENT_AREAS = false; private double zoomLevel = 1; - private Map, Area> componentAreaMap; private Project currentProject; private String currentFileName = null; private boolean modified = false; @@ -93,6 +85,7 @@ public class Presenter implements IPlugInPort { // Utilities private Cloner cloner; private XStream xStream = new XStream(new DomDriver()); + private ProjectPainter projectPainter; private Rectangle selectionRect; @@ -117,12 +110,12 @@ public class Presenter implements IPlugInPort { public Presenter(IView view) { super(); this.view = view; - componentAreaMap = new HashMap, Area>(); plugIns = new ArrayList(); messageDispatcher = new MessageDispatcher(); selectedComponents = new ComponentSelection(); currentProject = new Project(); cloner = new Cloner(); + projectPainter = new ProjectPainter(); // lockedLayers = EnumSet.noneOf(ComponentLayer.class); // visibleLayers = EnumSet.allOf(ComponentLayer.class); @@ -162,10 +155,8 @@ public class Presenter implements IPlugInPort { if (componentSlot == null) { // Scale point to remove zoom factor. Point2D scaledPoint = scalePoint(point); - for (Map.Entry, Area> entry : componentAreaMap.entrySet()) { - if (entry.getValue().contains(scaledPoint)) { - return Cursor.getPredefinedCursor(Cursor.HAND_CURSOR); - } + if (projectPainter.isCursorOverArea(scaledPoint)) { + return Cursor.getPredefinedCursor(Cursor.HAND_CURSOR); } if (controlPointMap != null && !controlPointMap.isEmpty()) { return Cursor.getPredefinedCursor(Cursor.HAND_CURSOR); @@ -310,113 +301,14 @@ public class Presenter implements IPlugInPort { if (currentProject == null) { return; } - G2DWrapper g2dWrapper = new G2DWrapper(g2d); - - if (drawOptions.contains(DrawOption.ANTIALIASING) && ENABLE_ANTIALIASING) { - g2d - .setRenderingHint(RenderingHints.KEY_ANTIALIASING, - RenderingHints.VALUE_ANTIALIAS_ON); - } - - // AffineTransform initialTx = g2d.getTransform(); - Dimension d = getCanvasDimensions(drawOptions.contains(DrawOption.ZOOM)); - - g2dWrapper.setColor(Constants.CANVAS_COLOR); - g2dWrapper.fillRect(0, 0, d.width, d.height); - - if (drawOptions.contains(DrawOption.GRID)) { - double zoomStep = currentProject.getGridSpacing().convertToPixels() * zoomLevel; - - g2dWrapper.setColor(Constants.GRID_COLOR); - 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 ((drawOptions.contains(DrawOption.ZOOM)) && (Math.abs(1.0 - zoomLevel) > 1e-4)) { - g2dWrapper.scale(zoomLevel, zoomLevel); - } - - // Composite mainComposite = g2d.getComposite(); - // Composite alphaComposite = - // AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.5f); - - // g2dWrapper.resetTx(); - - List> components = getCurrentProject().getComponents(); - componentAreaMap.clear(); - if (components != null) { - for (IDIYComponent component : components) { - // Do not draw the component if it's filtered out. - if (filter != null && !filter.testComponent(component)) { - continue; - } - g2dWrapper.startedDrawingComponent(); - ComponentState state = ComponentState.NORMAL; - if (drawOptions.contains(DrawOption.SELECTION) - && selectedComponents.contains(component)) { - if (dragInProgress) { - state = ComponentState.DRAGGING; - } else { - state = ComponentState.SELECTED; - } - } - // Draw the component through the g2dWrapper. - component.draw(g2dWrapper, state, currentProject, g2dWrapper); - componentAreaMap.put(component, g2dWrapper.finishedDrawingComponent()); - } - // Draw control points. - for (IDIYComponent component : components) { - if (drawOptions.contains(DrawOption.CONTROL_POINTS)) { - for (int i = 0; i < component.getControlPointCount(); i++) { - Point controlPoint = component.getControlPoint(i); - try { - if (shouldShowControlPointsFor(component)) { - g2dWrapper.setColor(Constants.CONTROL_POINT_COLOR); - g2dWrapper.setStroke(new BasicStroke(2)); - // g2d.drawOval(controlPoint.x - 2, - // controlPoint.y - 2, 4, 4); - g2dWrapper.fillOval(controlPoint.x - CONTROL_POINT_SIZE / 2, - controlPoint.y - CONTROL_POINT_SIZE / 2, - CONTROL_POINT_SIZE, CONTROL_POINT_SIZE); - } - } catch (Exception e) { - LOG.error("Could not obtain control points for component of type " - + component.getClass().getName()); - } - } - } - } - } - - // 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.dashedStroke); - g2d.draw(selectionRect); - } - - // Draw component area for test - if (DEBUG_COMPONENT_AREAS) { - g2d.setStroke(new BasicStroke()); - g2d.setColor(Color.red); - for (Area area : componentAreaMap.values()) { - g2d.draw(area); + Set> drawControlPoints = new HashSet>(); + for (IDIYComponent component : currentProject.getComponents()) { + if (shouldShowControlPointsFor(component)) { + drawControlPoints.add(component); } } + projectPainter.draw(g2d, currentProject, drawOptions, filter, selectionRect, + selectedComponents, drawControlPoints, dragInProgress, zoomLevel); } @Override @@ -446,16 +338,7 @@ public class Presenter implements IPlugInPort { * @return */ private List> findComponentsAt(Point point) { - List> components = new ArrayList>(); - for (Map.Entry, Area> entry : componentAreaMap.entrySet()) { - if (entry.getValue().contains(point)) { - components.add(entry.getKey()); - } - } - // Sort by z-order. - Collections.sort(components, ComparatorFactory.getInstance().getComponentZOrderComparator( - currentProject.getComponents())); - return components; + return projectPainter.findComponentsAt(point, currentProject); } @Override @@ -515,7 +398,7 @@ public class Presenter implements IPlugInPort { if (selectedComponents.contains(component) && componentType.isStretchable() && findAllGroupedComponents(component).size() == 1) { try { - if (scaledPoint.distance(controlPoint) < CONTROL_POINT_SIZE) { + if (scaledPoint.distance(controlPoint) < ProjectPainter.CONTROL_POINT_SIZE) { Set indices = new HashSet(); if (componentType.isStretchable()) { indices.add(pointIndex); @@ -565,11 +448,6 @@ public class Presenter implements IPlugInPort { messageDispatcher.dispatchMessage(EventType.REPAINT); } - @Override - public Area getComponentArea(IDIYComponent component) { - return componentAreaMap.get(component); - } - @Override public VersionNumber getCurrentVersionNumber() { return CURRENT_VERSION; @@ -664,7 +542,7 @@ public class Presenter implements IPlugInPort { Point secondPoint = entry.getKey().getControlPoint(j); // If they are close enough we can consider them // matched. - if (firstPoint.distance(secondPoint) < CONTROL_POINT_SIZE) { + if (firstPoint.distance(secondPoint) < ProjectPainter.CONTROL_POINT_SIZE) { componentMatches = true; break; } @@ -722,6 +600,7 @@ public class Presenter implements IPlugInPort { // Update all points. for (Map.Entry, Set> entry : controlPointMap.entrySet()) { IDIYComponent c = entry.getKey(); + projectPainter.invalidateComponent(c); for (Integer index : entry.getValue()) { Point p = new Point(c.getControlPoint(index)); p.translate(dx, dy); @@ -732,7 +611,8 @@ public class Presenter implements IPlugInPort { } else if (selectedComponents.isEmpty()) { // If there's no selection, the only thing to do is update the // selection rectangle and refresh. - Rectangle oldSelectionRect = selectionRect == null ? null : new Rectangle(selectionRect); + Rectangle oldSelectionRect = selectionRect == null ? null + : new Rectangle(selectionRect); this.selectionRect = Utils.createRectangle(scaledPoint, previousDragPoint); repaint = !selectionRect.equals(oldSelectionRect); // messageDispatcher.dispatchMessage(EventType.SELECTION_RECT_CHANGED, @@ -772,7 +652,7 @@ public class Presenter implements IPlugInPort { } selectedComponents.clear(); for (IDIYComponent component : currentProject.getComponents()) { - Area area = componentAreaMap.get(component); + Area area = projectPainter.getComponentArea(component); if ((area != null) && (selectionRect != null) && area.intersects(selectionRect)) { selectedComponents.addAll(findAllGroupedComponents(component)); } @@ -970,7 +850,7 @@ public class Presenter implements IPlugInPort { boolean metric = ConfigurationManager.getInstance().readBoolean(METRIC_KEY, true); Area area = new Area(); for (IDIYComponent component : selectedComponents) { - Area componentArea = componentAreaMap.get(component); + Area componentArea = projectPainter.getComponentArea(component); if (componentArea != null) { area.add(componentArea); } @@ -1114,6 +994,7 @@ public class Presenter implements IPlugInPort { Project oldProject = cloner.deepClone(currentProject); try { for (IDIYComponent component : selectedComponents) { + projectPainter.invalidateComponent(component); for (PropertyWrapper property : properties) { property.writeTo(component); } diff --git a/ diy-layout-creator --username bancika@gmail.com/DIYLC/src/org/diylc/presenter/ProjectPainter.java b/ diy-layout-creator --username bancika@gmail.com/DIYLC/src/org/diylc/presenter/ProjectPainter.java new file mode 100644 index 00000000..172826bb --- /dev/null +++ b/ diy-layout-creator --username bancika@gmail.com/DIYLC/src/org/diylc/presenter/ProjectPainter.java @@ -0,0 +1,218 @@ +package org.diylc.presenter; + +import java.awt.BasicStroke; +import java.awt.Color; +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.Point2D; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import org.apache.log4j.Logger; +import org.diylc.common.ComponentSelection; +import org.diylc.common.DrawOption; +import org.diylc.common.IComponentFiler; +import org.diylc.core.ComponentState; +import org.diylc.core.IDIYComponent; +import org.diylc.core.Project; +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 ProjectPainter { + + private static final Logger LOG = Logger.getLogger(ProjectPainter.class); + + public static final int CONTROL_POINT_SIZE = 5; + public static boolean ENABLE_ANTIALIASING = true; + public static boolean DEBUG_COMPONENT_AREAS = false; + + // 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; + + public ProjectPainter() { + super(); + componentAreaMap = new HashMap, Area>(); + lastDrawnStateMap = new HashMap, ComponentState>(); + } + + public void draw(Graphics2D g2d, Project project, Set drawOptions, + IComponentFiler filter, Rectangle selectionRect, ComponentSelection selectedComponents, + Set> drawControlPoints, boolean dragInProgress, double zoomLevel) { + if (project == null) { + return; + } + G2DWrapper g2dWrapper = new G2DWrapper(g2d); + + if (drawOptions.contains(DrawOption.ANTIALIASING) && ENABLE_ANTIALIASING) { + g2d + .setRenderingHint(RenderingHints.KEY_ANTIALIASING, + RenderingHints.VALUE_ANTIALIAS_ON); + } + + // AffineTransform initialTx = g2d.getTransform(); + Dimension d = getCanvasDimensions(project, zoomLevel, drawOptions.contains(DrawOption.ZOOM)); + + g2dWrapper.setColor(Constants.CANVAS_COLOR); + g2dWrapper.fillRect(0, 0, d.width, d.height); + + if (drawOptions.contains(DrawOption.GRID)) { + double zoomStep = project.getGridSpacing().convertToPixels() * zoomLevel; + + g2dWrapper.setColor(Constants.GRID_COLOR); + 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 ((drawOptions.contains(DrawOption.ZOOM)) && (Math.abs(1.0 - zoomLevel) > 1e-4)) { + g2dWrapper.scale(zoomLevel, zoomLevel); + } + + // Composite mainComposite = g2d.getComposite(); + // Composite alphaComposite = + // AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.5f); + + // g2dWrapper.resetTx(); + + List> components = project.getComponents(); + // componentAreaMap.clear(); + if (components != null) { + for (IDIYComponent component : components) { + // 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; + g2dWrapper.startedDrawingComponent(); + if (!trackArea) { + g2dWrapper.stopTracking(); + } + // Draw the component through the g2dWrapper. + component.draw(g2dWrapper, state, project, g2dWrapper); + Area area = g2dWrapper.finishedDrawingComponent(); + if (trackArea) { + componentAreaMap.put(component, area); + lastDrawnStateMap.put(component, state); + } + } + // Draw control points. + for (IDIYComponent component : components) { + if (drawOptions.contains(DrawOption.CONTROL_POINTS)) { + for (int i = 0; i < component.getControlPointCount(); i++) { + Point controlPoint = component.getControlPoint(i); + try { + if (drawControlPoints.contains(component)) { + g2dWrapper.setColor(Constants.CONTROL_POINT_COLOR); + g2dWrapper.setStroke(new BasicStroke(2)); + // g2d.drawOval(controlPoint.x - 2, + // controlPoint.y - 2, 4, 4); + g2dWrapper.fillOval(controlPoint.x - CONTROL_POINT_SIZE / 2, + controlPoint.y - CONTROL_POINT_SIZE / 2, + CONTROL_POINT_SIZE, CONTROL_POINT_SIZE); + } + } catch (Exception e) { + LOG.error("Could not obtain control points for component of type " + + component.getClass().getName()); + } + } + } + } + } + + // 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.dashedStroke); + g2d.draw(selectionRect); + } + + // Draw component area for test + if (DEBUG_COMPONENT_AREAS) { + g2d.setStroke(new BasicStroke()); + g2d.setColor(Color.red); + for (Area area : componentAreaMap.values()) { + g2d.draw(area); + } + } + } + + public void invalidateComponent(IDIYComponent component) { + lastDrawnStateMap.remove(component); + } + + public Area getComponentArea(IDIYComponent component) { + return componentAreaMap.get(component); + } + + public boolean isCursorOverArea(Point2D cursorPosition) { + for (Map.Entry, Area> entry : componentAreaMap.entrySet()) { + if (entry.getValue().contains(cursorPosition)) { + return true; + } + } + return false; + } + + public List> findComponentsAt(Point point, Project project) { + List> components = new ArrayList>(); + for (Map.Entry, Area> entry : componentAreaMap.entrySet()) { + if (entry.getValue().contains(point)) { + components.add(entry.getKey()); + } + } + // Sort by z-order. + Collections.sort(components, ComparatorFactory.getInstance().getComponentZOrderComparator( + project.getComponents())); + return components; + } + + public Dimension getCanvasDimensions(Project project, Double zoomLevel, boolean useZoom) { + double width = project.getWidth().convertToPixels(); + int height = project.getHeight().convertToPixels(); + if (useZoom) { + width *= zoomLevel; + height *= zoomLevel; + } + return new Dimension((int) width, (int) height); + } +}