diff --git a/diylc/diylc-core/src/org/diylc/common/EventType.java b/diylc/diylc-core/src/org/diylc/common/EventType.java index 97ea9c62..9d2b8944 100644 --- a/diylc/diylc-core/src/org/diylc/common/EventType.java +++ b/diylc/diylc-core/src/org/diylc/common/EventType.java @@ -72,6 +72,11 @@ public enum EventType { * layers. All layers not included are considered unlocked. */ LAYER_STATE_CHANGED, + /** + * Called when a layer visibility is changed. The first parameter is a set of indices of hidden + * layers. All layers not included are considered visible. + */ + LAYER_VISIBILITY_CHANGED, /** * Called to update the status message. New status message is passed as a first parameter. */ diff --git a/diylc/diylc-core/src/org/diylc/common/IPlugInPort.java b/diylc/diylc-core/src/org/diylc/common/IPlugInPort.java index afff6d31..530047ad 100644 --- a/diylc/diylc-core/src/org/diylc/common/IPlugInPort.java +++ b/diylc/diylc-core/src/org/diylc/common/IPlugInPort.java @@ -253,6 +253,15 @@ public interface IPlugInPort extends ISelectionProcessor, IMouseProcessor, IKeyP * @param locked */ void setLayerLocked(int layerZOrder, boolean locked); + + /** + * Shows or hides the specified layer. All components within +- 0.5 range will be affected by + * the change as well. + * + * @param layerZOrder + * @param visible + */ + void setLayerVisibility(int layerZOrder, boolean visible); /** * @return selection size expressed in both inches or centimeters, respectively diff --git a/diylc/diylc-core/src/org/diylc/core/Project.java b/diylc/diylc-core/src/org/diylc/core/Project.java index 4678e239..13cac682 100644 --- a/diylc/diylc-core/src/org/diylc/core/Project.java +++ b/diylc/diylc-core/src/org/diylc/core/Project.java @@ -45,12 +45,14 @@ public class Project implements Serializable { private List> components; private Set>> groups; private Set lockedLayers; + private Set hiddenLayers; private Font font = DEFAULT_FONT; public Project() { components = new ArrayList>(); groups = new HashSet>>(); lockedLayers = new HashSet(); + hiddenLayers = new HashSet(); title = DEFAULT_TITLE; author = System.getProperty("user.name"); width = DEFAULT_WIDTH; @@ -134,6 +136,12 @@ public class Project implements Serializable { public Set getLockedLayers() { return lockedLayers; } + + public Set getHiddenLayers() { + if (hiddenLayers == null) + hiddenLayers = new HashSet(); + return hiddenLayers; + } public VersionNumber getFileVersion() { return fileVersion; @@ -261,6 +269,7 @@ public class Project implements Serializable { project.setHeight(this.getHeight()); project.setWidth(this.getWidth()); project.getLockedLayers().addAll(this.getLockedLayers()); + project.getHiddenLayers().addAll(this.getHiddenLayers()); Map, IDIYComponent> cloneMap = new HashMap, IDIYComponent>(); diff --git a/diylc/diylc-core/src/org/diylc/presenter/Presenter.java b/diylc/diylc-core/src/org/diylc/presenter/Presenter.java index 98a805da..5896599c 100644 --- a/diylc/diylc-core/src/org/diylc/presenter/Presenter.java +++ b/diylc/diylc-core/src/org/diylc/presenter/Presenter.java @@ -189,7 +189,7 @@ public class Presenter implements IPlugInPort { return Cursor.getPredefinedCursor(Cursor.HAND_CURSOR); } for (IDIYComponent component : currentProject.getComponents()) { - if (!isComponentLocked(component)) { + if (!isComponentLocked(component) && isComponentVisible(component)) { Area area = drawingManager.getComponentArea(component); if (area != null && area.contains(scaledPoint)) { return Cursor.getPredefinedCursor(Cursor.HAND_CURSOR); @@ -219,6 +219,7 @@ public class Presenter implements IPlugInPort { messageDispatcher.dispatchMessage(EventType.PROJECT_LOADED, project, freshStart); messageDispatcher.dispatchMessage(EventType.REPAINT); messageDispatcher.dispatchMessage(EventType.LAYER_STATE_CHANGED, currentProject.getLockedLayers()); + messageDispatcher.dispatchMessage(EventType.LAYER_VISIBILITY_CHANGED, currentProject.getHiddenLayers()); } @Override @@ -374,9 +375,16 @@ public class Presenter implements IPlugInPort { return autoCreators; } + @SuppressWarnings({"unchecked"}) + private boolean isComponentVisible(IDIYComponent component) { + ComponentType componentType = + ComponentProcessor.getInstance().extractComponentTypeFrom( + (Class>) component.getClass()); + return !currentProject.getHiddenLayers().contains((int) Math.round(componentType.getZOrder())); + } @Override - public void draw(Graphics2D g2d, Set drawOptions, IComponentFiler filter) { + public void draw(Graphics2D g2d, Set drawOptions, final IComponentFiler filter) { if (currentProject == null) { return; } @@ -387,6 +395,16 @@ public class Presenter implements IPlugInPort { groupedComponents.add(component); } } + + // Concatenate the specified filter with our own filter that removes hidden layers + IComponentFiler newFiler = new IComponentFiler() { + + @Override + public boolean testComponent(IDIYComponent component) { + return (filter == null || filter.testComponent(component)) && isComponentVisible(component); + } + }; + // Don't draw the component in the slot if both control points // match. List> componentSlotToDraw; @@ -402,7 +420,7 @@ public class Presenter implements IPlugInPort { g2d, currentProject, drawOptions, - filter, + newFiler, selectionRect, selectedComponents, getLockedComponents(), @@ -433,7 +451,8 @@ public class Presenter implements IPlugInPort { List> components = drawingManager.findComponentsAt(point, currentProject); Iterator> iterator = components.iterator(); while (iterator.hasNext()) { - if (isComponentLocked(iterator.next())) { + IDIYComponent component = iterator.next(); + if (isComponentLocked(component) || !isComponentVisible(component)) { iterator.remove(); } } @@ -530,8 +549,8 @@ public class Presenter implements IPlugInPort { List> newSelection = new ArrayList>(); for (IDIYComponent component : componentSlot) { addComponent(component, true); - // Select the new component if it's not locked. - if (!isComponentLocked(component)) { + // Select the new component if it's not locked and invisible. + if (!isComponentLocked(component) && isComponentVisible(component)) { newSelection.add(component); } } @@ -933,7 +952,7 @@ public class Presenter implements IPlugInPort { // Do not process a control point if it's already in the map and // if it's locked. if ((!controlPointMap.containsKey(component) || !controlPointMap.get(component).contains(i)) - && !isComponentLocked(component)) { + && !isComponentLocked(component) && isComponentVisible(component)) { if (component.isControlPointSticky(i)) { boolean componentMatches = false; for (Map.Entry, Set> entry : controlPointMap.entrySet()) { @@ -1315,7 +1334,7 @@ public class Presenter implements IPlugInPort { } List> newSelection = new ArrayList>(); for (IDIYComponent component : currentProject.getComponents()) { - if (!isComponentLocked(component)) { + if (!isComponentLocked(component) && isComponentVisible(component)) { Area area = drawingManager.getComponentArea(component); if ((area != null) && (selectionRect != null) && area.intersects(selectionRect)) { newSelection.addAll(findAllGroupedComponents(component)); @@ -1438,6 +1457,19 @@ public class Presenter implements IPlugInPort { messageDispatcher.dispatchMessage(EventType.LAYER_STATE_CHANGED, currentProject.getLockedLayers()); } + @Override + public void setLayerVisibility(int layerZOrder, boolean visible) { + LOG.info(String.format("setLayerVisibility(%s, %s)", layerZOrder, visible)); + if (visible) { + currentProject.getHiddenLayers().remove(layerZOrder); + } else { + currentProject.getHiddenLayers().add(layerZOrder); + } + updateSelection(EMPTY_SELECTION); + messageDispatcher.dispatchMessage(EventType.REPAINT); + messageDispatcher.dispatchMessage(EventType.LAYER_VISIBILITY_CHANGED, currentProject.getHiddenLayers()); + } + @SuppressWarnings("unchecked") @Override public void sendSelectionToBack() { @@ -1711,7 +1743,7 @@ public class Presenter implements IPlugInPort { if (selectedComponents.isEmpty()) { return null; } - Rectangle2D rect = getSelectionBounds(); + Rectangle2D rect = getSelectionBounds(); double width = rect.getWidth(); double height = rect.getHeight(); diff --git a/diylc/diylc-swing/src/org/diylc/swing/plugins/layers/LayersMenuPlugin.java b/diylc/diylc-swing/src/org/diylc/swing/plugins/layers/LayersMenuPlugin.java index 7ea346a6..49098694 100644 --- a/diylc/diylc-swing/src/org/diylc/swing/plugins/layers/LayersMenuPlugin.java +++ b/diylc/diylc-swing/src/org/diylc/swing/plugins/layers/LayersMenuPlugin.java @@ -22,10 +22,12 @@ public class LayersMenuPlugin implements IPlugIn { private IPlugInPort plugInPort; private Map lockActionMap; + private Map visibleActionMap; private Map selectAllActionMap; public LayersMenuPlugin(ISwingUI swingUI) { lockActionMap = new HashMap(); + visibleActionMap = new HashMap(); selectAllActionMap = new HashMap(); for (Layer layer : Layer.values()) { final int zOrder = layer.getZOrder(); @@ -36,11 +38,24 @@ public class LayersMenuPlugin implements IPlugIn { @Override public void actionPerformed(ActionEvent e) { LayersMenuPlugin.this.plugInPort.setLayerLocked(zOrder, (Boolean) getValue(Action.SELECTED_KEY)); - selectAllActionMap.get(zOrder).setEnabled(!(Boolean) getValue(Action.SELECTED_KEY)); +// selectAllActionMap.get(zOrder).setEnabled(!(Boolean) getValue(Action.SELECTED_KEY)); } }; lockAction.putValue(IView.CHECK_BOX_MENU_ITEM, true); lockActionMap.put(layer, lockAction); + + AbstractAction visibleAction = new AbstractAction("Visible") { + + private static final long serialVersionUID = 1L; + + @Override + public void actionPerformed(ActionEvent e) { + LayersMenuPlugin.this.plugInPort.setLayerVisibility(zOrder, getValue(Action.SELECTED_KEY) == null ? true : (Boolean) getValue(Action.SELECTED_KEY)); +// selectAllActionMap.get(zOrder).setEnabled(!(Boolean) getValue(Action.SELECTED_KEY)); + } + }; + visibleAction.putValue(IView.CHECK_BOX_MENU_ITEM, true); + visibleActionMap.put(layer, visibleAction); AbstractAction selectAllAction = new AbstractAction("Select All") { @@ -54,6 +69,7 @@ public class LayersMenuPlugin implements IPlugIn { selectAllActionMap.put(zOrder, selectAllAction); swingUI.injectSubmenu(layer.title, null, LOCK_LAYERS_TITLE); + swingUI.injectMenuAction(visibleAction, layer.title); swingUI.injectMenuAction(lockAction, layer.title); swingUI.injectMenuAction(selectAllAction, layer.title); } @@ -66,7 +82,7 @@ public class LayersMenuPlugin implements IPlugIn { @Override public EnumSet getSubscribedEventTypes() { - return EnumSet.of(EventType.LAYER_STATE_CHANGED); + return EnumSet.of(EventType.LAYER_STATE_CHANGED, EventType.LAYER_VISIBILITY_CHANGED); } @SuppressWarnings("unchecked") @@ -77,7 +93,12 @@ public class LayersMenuPlugin implements IPlugIn { for (Layer layer : Layer.values()) { lockActionMap.get(layer).putValue(Action.SELECTED_KEY, lockedLayers.contains(layer.getZOrder())); } - } + } else if (eventType == EventType.LAYER_VISIBILITY_CHANGED) { + Set hiddenLayers = (Set) params[0]; + for (Layer layer : Layer.values()) { + visibleActionMap.get(layer).putValue(Action.SELECTED_KEY, !hiddenLayers.contains(layer.getZOrder())); + } + } } static enum Layer { diff --git a/diylc/diylc-swing/update.xml b/diylc/diylc-swing/update.xml index 123498ba..1900ce36 100644 --- a/diylc/diylc-swing/update.xml +++ b/diylc/diylc-swing/update.xml @@ -1701,7 +1701,11 @@ 2017-04-20 20:00:00.000 CET - + + + NEW_FEATURE + Show and hide each individual layer + NEW_FEATURE Red ticks on both rulers mark selection bounds, blue tick tracks cursor position