001: /*
002: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
003: *
004: * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
005: *
006: * The contents of this file are subject to the terms of either the GNU
007: * General Public License Version 2 only ("GPL") or the Common
008: * Development and Distribution License("CDDL") (collectively, the
009: * "License"). You may not use this file except in compliance with the
010: * License. You can obtain a copy of the License at
011: * http://www.netbeans.org/cddl-gplv2.html
012: * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
013: * specific language governing permissions and limitations under the
014: * License. When distributing the software, include this License Header
015: * Notice in each file and include the License file at
016: * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
017: * particular file as subject to the "Classpath" exception as provided
018: * by Sun in the GPL Version 2 section of the License file that
019: * accompanied this code. If applicable, add the following below the
020: * License Header, with the fields enclosed by brackets [] replaced by
021: * your own identifying information:
022: * "Portions Copyrighted [year] [name of copyright owner]"
023: *
024: * Contributor(s):
025: *
026: * The Original Software is NetBeans. The Initial Developer of the Original
027: * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
028: * Microsystems, Inc. All Rights Reserved.
029: *
030: * If you wish your version of this file to be governed by only the CDDL
031: * or only the GPL Version 2, indicate your decision by adding
032: * "[Contributor] elects to include this software in this distribution
033: * under the [CDDL or GPL Version 2] license." If you do not indicate a
034: * single choice of license, a recipient has the option to distribute
035: * your version of this file under either the CDDL, the GPL Version 2 or
036: * to extend the choice of license to its licensees as provided above.
037: * However, if you add GPL Version 2 code and therefore, elected the GPL
038: * Version 2 license, then the option applies only if the new code is
039: * made subject to such option by the copyright holder.
040: */package org.netbeans.modules.mobility.svgcore.composer;
041:
042: import com.sun.perseus.j2d.Transform;
043: import java.awt.Color;
044: import java.awt.Graphics;
045: import java.awt.Rectangle;
046: import org.w3c.dom.svg.SVGRect;
047:
048: /**
049: *
050: * @author Pavel Benes
051: */
052: public final class SVGObjectOutline {
053: private static final int ROUND_CORNER_SIZE = 3;
054: private static final int DIAMOND_CORNER_SIZE = 3;
055: public static final int SELECTOR_OVERLAP = ROUND_CORNER_SIZE + 2;
056:
057: private static final float HANDLE_DIST = 30;
058: public static final Color SELECTOR_BODY = Color.RED;
059: private static final Color SELECTOR_OUTLINE = Color.WHITE;
060: private static final Color COLOR_HIGHLIGHT = new Color(0, 0, 0, 64);
061: private static final int ROTATE_CORNER_INDEX = 1;
062: private static final int SKEW_CORNER_INDEX = 3;
063:
064: private final SVGObject m_svgObject;
065: private final float[][] m_coords = new float[4][2];
066: private short m_tickerCopy;
067:
068: public SVGObjectOutline(SVGObject svgObject) {
069: assert svgObject != null : "The SVGObject reference cannot be null";
070: m_svgObject = svgObject;
071: setDirty();
072: }
073:
074: public float[][] getCoords() {
075: checkObject();
076: return m_coords;
077: }
078:
079: public void setDirty() {
080: m_tickerCopy = -1;
081: }
082:
083: public static void drawOutline(Graphics g, int xOff, int yOff,
084: float[][] coords) {
085: for (int i = 0; i < 4; i++) {
086: int j = (i + 1) % 4;
087: g.drawLine(Math.round(coords[i][0]) + xOff, Math
088: .round(coords[i][1])
089: + yOff, Math.round(coords[j][0]) + xOff, Math
090: .round(coords[j][1])
091: + yOff);
092: }
093: }
094:
095: public void draw(Graphics g, int xOff, int yOff, Color color,
096: boolean drawCorners) {
097: checkObject();
098:
099: g.setColor(color);
100:
101: drawOutline(g, xOff, yOff, m_coords);
102:
103: if (drawCorners) {
104: for (int i = 0; i < 4; i++) {
105: if (i == ROTATE_CORNER_INDEX) {
106: GraphicUtils.drawRoundSelectorCorner(g,
107: SELECTOR_OUTLINE, SELECTOR_BODY,
108: (int) m_coords[i][0] + xOff,
109: (int) m_coords[i][1] + yOff,
110: ROUND_CORNER_SIZE);
111: } else if (i == SKEW_CORNER_INDEX) {
112: GraphicUtils.drawDiamondSelectorCorner(g,
113: SELECTOR_OUTLINE, SELECTOR_BODY,
114: (int) m_coords[i][0] + xOff,
115: (int) m_coords[i][1] + yOff,
116: DIAMOND_CORNER_SIZE);
117: } else {
118: drawRectSelectorCorner(g, (int) m_coords[i][0]
119: + xOff, (int) m_coords[i][1] + yOff);
120: }
121: }
122: }
123: }
124:
125: public void highlight(Graphics g, int xOff, int yOff, Color color) {
126: checkObject();
127:
128: g.setColor(color);
129: int[] xPoints = new int[4];
130: int[] yPoints = new int[4];
131:
132: for (int i = 0; i < 4; i++) {
133: xPoints[i] = Math.round(xOff + m_coords[i][0]);
134: yPoints[i] = Math.round(yOff + m_coords[i][1]);
135: }
136: g.fillPolygon(xPoints, yPoints, 4);
137: }
138:
139: public void highlight(Graphics g, int xOff, int yOff) {
140: highlight(g, xOff, yOff, COLOR_HIGHLIGHT);
141: }
142:
143: public static Rectangle getShapeBoundingBox(float[][] points) {
144: float min_x, max_x, min_y, max_y;
145: min_x = max_x = points[0][0];
146: min_y = max_y = points[0][1];
147:
148: for (int i = 1; i < points.length; i++) {
149: float x = points[i][0];
150: float y = points[i][1];
151:
152: if (x < min_x) {
153: min_x = x;
154: } else if (x > max_x) {
155: max_x = x;
156: }
157: if (y < min_y) {
158: min_y = y;
159: } else if (y > max_y) {
160: max_y = y;
161: }
162: }
163: return new Rectangle(Math.round(min_x), Math.round(min_y), Math
164: .round(max_x - min_x), Math.round(max_y - min_y));
165: }
166:
167: public Rectangle getScreenBoundingBox() {
168: checkObject();
169: return getShapeBoundingBox(m_coords);
170: }
171:
172: public float[] getRotatePivotPoint() {
173: return getCenter();
174: }
175:
176: public float[] getScalePivotPoint() {
177: return getCenter();
178: }
179:
180: public float[] getCenter() {
181: checkObject();
182: float sx = 0, sy = 0;
183:
184: for (int i = 0; i < m_coords.length; i++) {
185: sx += m_coords[i][0];
186: sy += m_coords[i][1];
187: }
188: return new float[] { sx / 4, sy / 4 };
189: }
190:
191: public boolean isAtRotateHandlePoint(float x, float y) {
192: checkObject();
193: float[] pt = m_coords[ROTATE_CORNER_INDEX];
194:
195: if (GraphicUtils.areNear(x, y, pt[0], pt[1], HANDLE_DIST)) {
196: return true;
197: }
198: return false;
199: }
200:
201: public boolean isAtScaleHandlePoint(float x, float y) {
202: checkObject();
203: for (int i = 0; i < 4; i++) {
204: if (i != ROTATE_CORNER_INDEX && i != SKEW_CORNER_INDEX) {
205: if (GraphicUtils.areNear(x, y, m_coords[i][0],
206: m_coords[i][1], HANDLE_DIST)) {
207: return true;
208: }
209: }
210: }
211:
212: return false;
213: }
214:
215: public boolean isAtSkewHandlePoint(float x, float y) {
216: checkObject();
217: float[] pt = m_coords[SKEW_CORNER_INDEX];
218:
219: if (GraphicUtils.areNear(x, y, pt[0], pt[1], HANDLE_DIST)) {
220: return true;
221: }
222:
223: return false;
224: }
225:
226: private static void drawRectSelectorCorner(Graphics g, int x, int y) {
227: g.setColor(SELECTOR_BODY);
228: g.fillRect(x - 2, y - 2, 5, 5);
229: g.setColor(SELECTOR_OUTLINE);
230: g.drawRect(x - 3, y - 3, 6, 6);
231: }
232:
233: private synchronized void checkObject() {
234: assert m_svgObject != null : "SVGObject reference cannot be null";
235: short ticker = m_svgObject.getScreenManager().getChangeTicker();
236:
237: if (ticker != m_tickerCopy) {
238: transformRectangle(m_svgObject.getSafeBBox(),
239: (Transform) m_svgObject.getSVGElement()
240: .getScreenCTM(), m_coords);
241: m_tickerCopy = ticker;
242: }
243: }
244:
245: public static float[][] transformRectangle(SVGRect rect,
246: Transform txf, float[][] coords) {
247: float x = rect.getX(), y = rect.getY(), w = rect.getWidth(), h = rect
248: .getHeight();
249:
250: float[][] points = new float[][] { { x, y }, { x + w, y },
251: { x + w, y + h }, { x, y + h } };
252: assert coords.length == 4;
253: for (int i = 0; i < 4; i++) {
254: txf.transformPoint(points[i], coords[i]);
255: }
256: return coords;
257: }
258: }
|