| /******************************************************************************* |
| * <copyright> |
| * |
| * Copyright (c) 2013, 2013 SAP AG. |
| * All rights reserved. This program and the accompanying materials |
| * are made available under the terms of the Eclipse Public License v1.0 |
| * which accompanies this distribution, and is available at |
| * http://www.eclipse.org/legal/epl-v10.html |
| * |
| * Contributors: |
| * SAP AG - initial API, implementation and documentation |
| * |
| * </copyright> |
| * |
| *******************************************************************************/ |
| package org.eclipse.fmc.blockdiagram.editor.algorithm.node; |
| |
| import org.eclipse.fmc.blockdiagram.editor.util.StyleUtil; |
| import org.eclipse.fmc.blockdiagram.editor.util.FMCUtil; |
| import org.eclipse.graphiti.mm.GraphicsAlgorithmContainer; |
| import org.eclipse.graphiti.mm.algorithms.GraphicsAlgorithm; |
| import org.eclipse.graphiti.mm.algorithms.RoundedRectangle; |
| import org.eclipse.graphiti.mm.pictograms.ContainerShape; |
| import org.eclipse.graphiti.mm.pictograms.Diagram; |
| import org.eclipse.graphiti.mm.pictograms.Shape; |
| |
| /** |
| * This storage algorithm class represents the standard rectangular shape with |
| * rounded corners for storages. |
| * |
| * @author Heiko Witteborg |
| * |
| */ |
| public class RectangleStorageAlgorithm extends AbstractRectangleAlgorithm |
| implements StorageAlgorithm { |
| |
| // ---------------------------------------- |
| // ----------- Graphics Node -------------- |
| |
| public static final int STORAGE_MINIMUM_WIDTH = 15; |
| public static final int STORAGE_MINIMUM_HEIGHT = 15; |
| public static final int STORAGE_DEFAULT_WIDTH = 60; |
| public static final int STORAGE_DEFAULT_HEIGHT = 40; |
| public static final int STORAGE_DEFAULT_LINEWIDTH = 3; |
| |
| @Override |
| /* |
| * (non-Javadoc) |
| * |
| * @see |
| * org.eclipse.fmc.blockdiagram.editor.node.GraphicsNode#createGraphics(org.eclipse |
| * .graphiti.mm.pictograms.Diagram, |
| * org.eclipse.graphiti.mm.GraphicsAlgorithmContainer, int, int, int, int) |
| */ |
| public GraphicsAlgorithm createGraphics(Diagram diagram, |
| GraphicsAlgorithmContainer container, int x, int y, int width, |
| int height) { |
| int w = width; // width < STORAGE_MINIMUM_CORNER_WIDTH * 2 ? |
| // STORAGE_MINIMUM_CORNER_WIDTH * 2 : width; |
| int h = height; // height < STORAGE_MINIMUM_CORNER_WIDTH * 2 ? |
| // STORAGE_MINIMUM_CORNER_WIDTH * 2 : height; |
| int cornerWidth = (w < h) ? w : h; |
| RoundedRectangle rec = ga.createRoundedRectangle(container, |
| cornerWidth, cornerWidth); |
| ga.setLocationAndSize(rec, x, y, w, h); |
| rec.setLineWidth(3); |
| rec.setTransparency(null); |
| rec.setStyle(StyleUtil.getStyle(diagram, StyleUtil.SHAPE)); |
| |
| // Create anchors |
| if (container instanceof GraphicsAlgorithm) { |
| ContainerShape containerShape = this.getContainerShape(rec); |
| pe.createChopboxAnchor(containerShape); |
| createBoxAnchorSet(containerShape); |
| } |
| return rec; |
| } |
| |
| @Override |
| /* |
| * (non-Javadoc) |
| * |
| * @see org.eclipse.fmc.blockdiagram.editor.node.GraphicsNode#getMinimumHeight() |
| */ |
| public int getMinimumHeight() { |
| return STORAGE_MINIMUM_HEIGHT; |
| } |
| |
| @Override |
| /* |
| * (non-Javadoc) |
| * |
| * @see org.eclipse.fmc.blockdiagram.editor.node.GraphicsNode#getMinimumWidth() |
| */ |
| public int getMinimumWidth() { |
| return STORAGE_MINIMUM_WIDTH; |
| } |
| |
| @Override |
| /* |
| * (non-Javadoc) |
| * |
| * @see org.eclipse.fmc.blockdiagram.editor.node.GraphicsNode#getDefaultHeight() |
| */ |
| public int getDefaultHeight() { |
| return STORAGE_DEFAULT_HEIGHT; |
| } |
| |
| @Override |
| /* |
| * (non-Javadoc) |
| * |
| * @see org.eclipse.fmc.blockdiagram.editor.node.GraphicsNode#getDefaultWidth() |
| */ |
| public int getDefaultWidth() { |
| return STORAGE_DEFAULT_WIDTH; |
| } |
| |
| @Override |
| /* |
| * (non-Javadoc) |
| * |
| * @see org.eclipse.fmc.blockdiagram.editor.node.GraphicsNode#getDefaultLineWidth() |
| */ |
| public int getDefaultLineWidth() { |
| return STORAGE_DEFAULT_LINEWIDTH; |
| } |
| |
| // ---------------------------------------- |
| // ----------- Resizable Node ------------- |
| |
| @Override |
| /* |
| * (non-Javadoc) |
| * |
| * @see |
| * org.eclipse.fmc.blockdiagram.editor.graphicsalgorithms.FMCNodeAlgorithm#resize |
| * (org.eclipse.graphiti.mm.algorithms.GraphicsAlgorithm, int, int, int, |
| * int) |
| */ |
| public void resize(GraphicsAlgorithm algorithm, int x, int y, int width, |
| int height) { |
| ContainerShape container = this.getContainerShape(algorithm); |
| |
| ga.setLocationAndSize(algorithm, x, y, width, height); |
| |
| // update rounded corner width and height |
| RoundedRectangle rec = (RoundedRectangle) algorithm; |
| int cornerWidth = (width < height) ? width : height; |
| rec.setCornerHeight(cornerWidth); |
| rec.setCornerWidth(cornerWidth); |
| |
| relocateText(algorithm); |
| |
| // adapt first level container (relative anchors + invisible shape) |
| createBoxAnchorSet(container); |
| } |
| |
| // ---------------------------------------- |
| // ----------- Anchored Node -------------- |
| |
| @Override |
| /* |
| * (non-Javadoc) |
| * |
| * @see |
| * org.eclipse.fmc.blockdiagram.editor.node.AbstractNode#addBoxAnchorSet(org.eclipse |
| * .graphiti.mm.pictograms.ContainerShape) |
| */ |
| protected void addBoxAnchorSet(Shape shape) { |
| int radius, numOfAnchorsForStraightSections; |
| |
| GraphicsAlgorithm firstLevelRectangle = shape.getGraphicsAlgorithm(); // graphics |
| // = |
| // Rectangle |
| GraphicsAlgorithm secondLevelRectangle = firstLevelRectangle |
| .getGraphicsAlgorithmChildren().get(0); // graphics = Rectangle |
| |
| // adapt anchors when drawing background part (front part) |
| double gapForStraightSections, offsetMultiInstance = 0.0d; |
| if (firstLevelRectangle.getWidth() != secondLevelRectangle.getWidth()) { |
| // Remove anchors created when drawing the main part |
| FMCUtil.removeObsoleteAnchors(shape); |
| offsetMultiInstance = MULTI_INSTANCE_GAP; |
| } |
| |
| if (secondLevelRectangle.getWidth() > secondLevelRectangle.getHeight()) { |
| // case width > height |
| // A |
| // ___________ |
| // / \ |
| // D | | B |
| // \ ___________ / |
| // |
| // C |
| |
| // add anchors for A+C |
| radius = secondLevelRectangle.getHeight() / 2; |
| numOfAnchorsForStraightSections = (secondLevelRectangle.getWidth() - 2 * radius) |
| / AnchoredNode.DEFAULT_ANCHOR_GAP; |
| double relativeOffsetXForA = (((double) radius + offsetMultiInstance) / firstLevelRectangle |
| .getWidth()); |
| double relativeOffsetXForC = ((double) radius) |
| / firstLevelRectangle.getWidth(); |
| double relativeOffsetYForA = 0.0d; |
| double relativeOffsetYForC = 1.0d - (((double) AnchoredNode.DEFAULT_ANCHOR_DIAMETER) / firstLevelRectangle |
| .getHeight()); |
| gapForStraightSections = (1.0d - relativeOffsetXForA - relativeOffsetXForC) |
| / numOfAnchorsForStraightSections; |
| for (int i = 0; i <= numOfAnchorsForStraightSections; i++) { |
| createBoxAnchor(shape, relativeOffsetXForA + i |
| * gapForStraightSections, relativeOffsetYForA, |
| AnchoredNode.DEFAULT_ANCHOR_GAP, |
| AnchoredNode.DEFAULT_ANCHOR_DIAMETER); |
| createBoxAnchor(shape, relativeOffsetXForC + i |
| * gapForStraightSections, relativeOffsetYForC, |
| AnchoredNode.DEFAULT_ANCHOR_GAP, |
| AnchoredNode.DEFAULT_ANCHOR_DIAMETER); |
| } |
| |
| // add anchors for B+D |
| double relativeOffsetXForB = (((double) firstLevelRectangle |
| .getWidth()) - AnchoredNode.DEFAULT_ANCHOR_DIAMETER) |
| / firstLevelRectangle.getWidth(); |
| double relativeOffsetXForD = 0.0d; |
| double relativeOffsetYForB = (((double) radius) - (AnchoredNode.DEFAULT_ANCHOR_DIAMETER / 2)) |
| / firstLevelRectangle.getHeight(); |
| double relativeOffsetYForD = (((double) radius) |
| - (AnchoredNode.DEFAULT_ANCHOR_DIAMETER / 2) + offsetMultiInstance) |
| / firstLevelRectangle.getHeight(); |
| createBoxAnchor(shape, relativeOffsetXForD, relativeOffsetYForD, |
| AnchoredNode.DEFAULT_ANCHOR_DIAMETER, |
| AnchoredNode.DEFAULT_ANCHOR_DIAMETER); |
| createBoxAnchor(shape, relativeOffsetXForB, relativeOffsetYForB, |
| AnchoredNode.DEFAULT_ANCHOR_DIAMETER, |
| AnchoredNode.DEFAULT_ANCHOR_DIAMETER); |
| |
| } else { |
| // case width < height |
| // A |
| // ___ |
| // / \ |
| // | | |
| // D | | B |
| // | | |
| // \___/ |
| // |
| // C |
| |
| // add anchors for B+D |
| radius = secondLevelRectangle.getWidth() / 2; |
| numOfAnchorsForStraightSections = (secondLevelRectangle.getHeight() - 2 * radius) |
| / AnchoredNode.DEFAULT_ANCHOR_GAP; |
| double relativeOffsetYForB = ((double) radius) |
| / firstLevelRectangle.getHeight(); |
| double relativeOffsetYForD = ((double) radius + offsetMultiInstance) |
| / firstLevelRectangle.getHeight(); |
| double relativeOffsetXForB = 1.0d - (((double) AnchoredNode.DEFAULT_ANCHOR_DIAMETER) / firstLevelRectangle |
| .getWidth()); |
| double relativeOffsetXForD = 0.0d; |
| |
| gapForStraightSections = (1.0d - relativeOffsetYForB - relativeOffsetYForD) |
| / numOfAnchorsForStraightSections; |
| for (int i = 0; i <= numOfAnchorsForStraightSections; i++) { |
| createBoxAnchor(shape, relativeOffsetXForD, relativeOffsetYForD |
| + i * gapForStraightSections, |
| AnchoredNode.DEFAULT_ANCHOR_DIAMETER, |
| AnchoredNode.DEFAULT_ANCHOR_GAP); |
| createBoxAnchor(shape, relativeOffsetXForB, relativeOffsetYForB |
| + i * gapForStraightSections, |
| AnchoredNode.DEFAULT_ANCHOR_DIAMETER, |
| AnchoredNode.DEFAULT_ANCHOR_GAP); |
| } |
| |
| // add anchors for A+C |
| double relativeOffsetXForA = (((double) radius) |
| - (AnchoredNode.DEFAULT_ANCHOR_DIAMETER / 2) + offsetMultiInstance) |
| / firstLevelRectangle.getWidth(); |
| double relativeOffsetXForC = (((double) radius) - (AnchoredNode.DEFAULT_ANCHOR_DIAMETER / 2)) |
| / firstLevelRectangle.getWidth(); |
| double relativeOffsetYForA = 0.0d; |
| double relativeOffsetYForC = (((double) firstLevelRectangle |
| .getHeight()) - AnchoredNode.DEFAULT_ANCHOR_DIAMETER) |
| / firstLevelRectangle.getHeight(); |
| createBoxAnchor(shape, relativeOffsetXForA, relativeOffsetYForA, |
| AnchoredNode.DEFAULT_ANCHOR_DIAMETER, |
| AnchoredNode.DEFAULT_ANCHOR_DIAMETER); |
| createBoxAnchor(shape, relativeOffsetXForC, relativeOffsetYForC, |
| AnchoredNode.DEFAULT_ANCHOR_DIAMETER, |
| AnchoredNode.DEFAULT_ANCHOR_DIAMETER); |
| } |
| |
| } |
| |
| } |