1 /**
2  * Copyright (c) 2007-2010, Gaudenz Alder, David Benson
3  */
4 package com.mxgraph.swing.view;
5 
6 import java.awt.Dimension;
7 import java.awt.Image;
8 import java.awt.Rectangle;
9 import java.awt.Shape;
10 import java.awt.image.ImageObserver;
11 
12 import com.mxgraph.canvas.mxGraphics2DCanvas;
13 import com.mxgraph.shape.mxBasicShape;
14 import com.mxgraph.shape.mxIShape;
15 import com.mxgraph.swing.mxGraphComponent;
16 import com.mxgraph.util.mxConstants;
17 import com.mxgraph.util.mxPoint;
18 import com.mxgraph.util.mxUtils;
19 import com.mxgraph.view.mxCellState;
20 
21 public class mxInteractiveCanvas extends mxGraphics2DCanvas
22 {
23 	/**
24 	 *
25 	 */
26 	protected ImageObserver imageObserver = null;
27 
28 	/**
29 	 *
30 	 */
mxInteractiveCanvas()31 	public mxInteractiveCanvas()
32 	{
33 		this(null);
34 	}
35 
36 	/**
37 	 *
38 	 */
mxInteractiveCanvas(ImageObserver imageObserver)39 	public mxInteractiveCanvas(ImageObserver imageObserver)
40 	{
41 		setImageObserver(imageObserver);
42 	}
43 
44 	/**
45 	 *
46 	 */
setImageObserver(ImageObserver value)47 	public void setImageObserver(ImageObserver value)
48 	{
49 		imageObserver = value;
50 	}
51 
52 	/**
53 	 *
54 	 */
getImageObserver()55 	public ImageObserver getImageObserver()
56 	{
57 		return imageObserver;
58 	}
59 
60 	/**
61 	 * Overrides graphics call to use image observer.
62 	 */
drawImageImpl(Image image, int x, int y)63 	protected void drawImageImpl(Image image, int x, int y)
64 	{
65 		g.drawImage(image, x, y, imageObserver);
66 	}
67 
68 	/**
69 	 * Returns the size for the given image.
70 	 */
getImageSize(Image image)71 	protected Dimension getImageSize(Image image)
72 	{
73 		return new Dimension(image.getWidth(imageObserver),
74 				image.getHeight(imageObserver));
75 	}
76 
77 	/**
78 	 *
79 	 */
contains(mxGraphComponent graphComponent, Rectangle rect, mxCellState state)80 	public boolean contains(mxGraphComponent graphComponent, Rectangle rect,
81 			mxCellState state)
82 	{
83 		return state != null && state.getX() >= rect.x
84 				&& state.getY() >= rect.y
85 				&& state.getX() + state.getWidth() <= rect.x + rect.width
86 				&& state.getY() + state.getHeight() <= rect.y + rect.height;
87 	}
88 
89 	/**
90 	 *
91 	 */
intersects(mxGraphComponent graphComponent, Rectangle rect, mxCellState state)92 	public boolean intersects(mxGraphComponent graphComponent, Rectangle rect,
93 			mxCellState state)
94 	{
95 		if (state != null)
96 		{
97 			// Checks if the label intersects
98 			if (state.getLabelBounds() != null
99 					&& state.getLabelBounds().getRectangle().intersects(rect))
100 			{
101 				return true;
102 			}
103 
104 			int pointCount = state.getAbsolutePointCount();
105 
106 			// Checks if the segments of the edge intersect
107 			if (pointCount > 0)
108 			{
109 				rect = (Rectangle) rect.clone();
110 				int tolerance = graphComponent.getTolerance();
111 				rect.grow(tolerance, tolerance);
112 
113 				Shape realShape = null;
114 
115 				// FIXME: Check if this should be used for all shapes
116 				if (mxUtils.getString(state.getStyle(),
117 						mxConstants.STYLE_SHAPE, "").equals(
118 						mxConstants.SHAPE_ARROW))
119 				{
120 					mxIShape shape = getShape(state.getStyle());
121 
122 					if (shape instanceof mxBasicShape)
123 					{
124 						realShape = ((mxBasicShape) shape).createShape(this,
125 								state);
126 					}
127 				}
128 
129 				if (realShape != null && realShape.intersects(rect))
130 				{
131 					return true;
132 				}
133 				else
134 				{
135 					mxPoint p0 = state.getAbsolutePoint(0);
136 
137 					for (int i = 0; i < pointCount; i++)
138 					{
139 						mxPoint p1 = state.getAbsolutePoint(i);
140 
141 						if (rect.intersectsLine(p0.getX(), p0.getY(),
142 								p1.getX(), p1.getY()))
143 						{
144 							return true;
145 						}
146 
147 						p0 = p1;
148 					}
149 				}
150 			}
151 			else
152 			{
153 				// Checks if the bounds of the shape intersect
154 				return state.getRectangle().intersects(rect);
155 			}
156 		}
157 
158 		return false;
159 	}
160 
161 	/**
162 	 * Returns true if the given point is inside the content area of the given
163 	 * swimlane. (The content area of swimlanes is transparent to events.) This
164 	 * implementation does not check if the given state is a swimlane, it is
165 	 * assumed that the caller has checked this before using this method.
166 	 */
hitSwimlaneContent(mxGraphComponent graphComponent, mxCellState swimlane, int x, int y)167 	public boolean hitSwimlaneContent(mxGraphComponent graphComponent,
168 			mxCellState swimlane, int x, int y)
169 	{
170 		if (swimlane != null)
171 		{
172 			int start = (int) Math.max(2, Math.round(mxUtils.getInt(
173 					swimlane.getStyle(), mxConstants.STYLE_STARTSIZE,
174 					mxConstants.DEFAULT_STARTSIZE)
175 					* graphComponent.getGraph().getView().getScale()));
176 			Rectangle rect = swimlane.getRectangle();
177 
178 			if (mxUtils.isTrue(swimlane.getStyle(),
179 					mxConstants.STYLE_HORIZONTAL, true))
180 			{
181 				rect.y += start;
182 				rect.height -= start;
183 			}
184 			else
185 			{
186 				rect.x += start;
187 				rect.width -= start;
188 			}
189 
190 			return rect.contains(x, y);
191 		}
192 
193 		return false;
194 	}
195 
196 }
197