Project

General

Profile

Download (5.96 KB) Statistics
| Branch: | Tag: | Revision:
1
/*******************************************************************************
2
 * Copyright (c) 2005, 2010 IBM Corporation and others.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     IBM Corporation - initial API and implementation
10
 *******************************************************************************/
11

    
12
package org.eclipse.draw2d;
13

    
14
import org.eclipse.draw2d.geometry.Point;
15
import org.eclipse.draw2d.geometry.PointList;
16

    
17
/**
18
 * Animates the routing of a connection. The animator will capture the effects
19
 * of the connection's router, and the play back the placement of the routing,
20
 * interpolating the intermediate routes.
21
 * <P>
22
 * To use a routing animator, hook it as a routing listener for the connection
23
 * whose points are to be animated, by calling
24
 * {@link PolylineConnection#addRoutingListener(RoutingListener)}. An animator
25
 * is active only when the Animation utility is activated.
26
 * 
27
 * @since 3.2
28
 */
29
public class RoutingAnimator extends Animator implements RoutingListener {
30

    
31
	static final RoutingAnimator INSTANCE = new RoutingAnimator();
32

    
33
	/**
34
	 * Constructs a routing animator for use with one or more connections. The
35
	 * default instance ({@link #getDefault()} can be used on any number of
36
	 * connections.
37
	 * 
38
	 * @since 3.2
39
	 */
40
	protected RoutingAnimator() {
41
	}
42

    
43
	/**
44
	 * Overridden to sync initial and final states.
45
	 * 
46
	 * @see Animator#playbackStarting(IFigure)
47
	 */
48
	public void playbackStarting(IFigure connection) {
49
		reconcileStates((Connection) connection);
50
	}
51

    
52
	/**
53
	 * Returns the current state of the connection. Currently, this is a copy of
54
	 * the list of points. However this Object could change in future releases
55
	 * and should not be considered API.
56
	 * 
57
	 * @see Animator#getCurrentState(IFigure)
58
	 */
59
	protected Object getCurrentState(IFigure connection) {
60
		return ((Connection) connection).getPoints().getCopy();
61
	}
62

    
63
	/**
64
	 * Returns the default instance.
65
	 * 
66
	 * @return the default instance
67
	 * @since 3.2
68
	 */
69
	public static RoutingAnimator getDefault() {
70
		return INSTANCE;
71
	}
72

    
73
	/**
74
	 * Hooks invalidate for animation purposes.
75
	 * 
76
	 * @see RoutingListener#invalidate(Connection)
77
	 */
78
	public final void invalidate(Connection conn) {
79
		if (Animation.isInitialRecording())
80
			Animation.hookAnimator(conn, this);
81
	}
82

    
83
	/**
84
	 * Plays back the interpolated state.
85
	 * 
86
	 * @see Animator#playback(IFigure)
87
	 */
88
	protected boolean playback(IFigure figure) {
89
		Connection conn = (Connection) figure;
90

    
91
		PointList list1 = (PointList) Animation.getInitialState(this, conn);
92
		PointList list2 = (PointList) Animation.getFinalState(this, conn);
93
		if (list1 == null) {
94
			conn.setVisible(false);
95
			return true;
96
		}
97

    
98
		float progress = Animation.getProgress();
99
		if (list1.size() == list2.size()) {
100
			Point pt1 = new Point(), pt2 = new Point();
101
			PointList points = conn.getPoints();
102
			points.removeAllPoints();
103
			for (int i = 0; i < list1.size(); i++) {
104
				list1.getPoint(pt2, i);
105
				list2.getPoint(pt1, i);
106
				pt1.x = Math.round(pt1.x * progress + (1 - progress) * pt2.x);
107
				pt1.y = Math.round(pt1.y * progress + (1 - progress) * pt2.y);
108
				points.addPoint(pt1);
109
			}
110
			conn.setPoints(points);
111
		}
112
		return true;
113
	}
114

    
115
	/**
116
	 * Hooks post routing for animation purposes.
117
	 * 
118
	 * @see RoutingListener#postRoute(Connection)
119
	 */
120
	public final void postRoute(Connection connection) {
121
		if (Animation.isFinalRecording())
122
			Animation.hookNeedsCapture(connection, this);
123
	}
124

    
125
	private void reconcileStates(Connection conn) {
126
		PointList points1 = (PointList) Animation.getInitialState(this, conn);
127
		PointList points2 = (PointList) Animation.getFinalState(this, conn);
128

    
129
		if (points1 != null && points1.size() != points2.size()) {
130
			Point p = new Point(), q = new Point();
131

    
132
			int size1 = points1.size() - 1;
133
			int size2 = points2.size() - 1;
134

    
135
			int i1 = size1;
136
			int i2 = size2;
137

    
138
			double current1 = 1.0;
139
			double current2 = 1.0;
140

    
141
			double prev1 = 1.0;
142
			double prev2 = 1.0;
143

    
144
			while (i1 > 0 || i2 > 0) {
145
				if (Math.abs(current1 - current2) < 0.1 && i1 > 0 && i2 > 0) {
146
					// Both points are the same, use them and go on;
147
					prev1 = current1;
148
					prev2 = current2;
149
					i1--;
150
					i2--;
151
					current1 = (double) i1 / size1;
152
					current2 = (double) i2 / size2;
153
				} else if (current1 < current2) {
154
					// 2 needs to catch up
155
					// current1 < current2 < prev1
156
					points1.getPoint(p, i1);
157
					points1.getPoint(q, i1 + 1);
158

    
159
					p.x = (int) (((q.x * (current2 - current1) + p.x
160
							* (prev1 - current2)) / (prev1 - current1)));
161
					p.y = (int) (((q.y * (current2 - current1) + p.y
162
							* (prev1 - current2)) / (prev1 - current1)));
163

    
164
					points1.insertPoint(p, i1 + 1);
165

    
166
					prev1 = prev2 = current2;
167
					i2--;
168
					current2 = (double) i2 / size2;
169

    
170
				} else {
171
					// 1 needs to catch up
172
					// current2< current1 < prev2
173

    
174
					points2.getPoint(p, i2);
175
					points2.getPoint(q, i2 + 1);
176

    
177
					p.x = (int) (((q.x * (current1 - current2) + p.x
178
							* (prev2 - current1)) / (prev2 - current2)));
179
					p.y = (int) (((q.y * (current1 - current2) + p.y
180
							* (prev2 - current1)) / (prev2 - current2)));
181

    
182
					points2.insertPoint(p, i2 + 1);
183

    
184
					prev2 = prev1 = current1;
185
					i1--;
186
					current1 = (double) i1 / size1;
187
				}
188
			}
189
		}
190
	}
191

    
192
	/**
193
	 * This callback is unused. Reserved for possible future use.
194
	 * 
195
	 * @see RoutingListener#remove(Connection)
196
	 */
197
	public final void remove(Connection connection) {
198
	}
199

    
200
	/**
201
	 * Hooks route to intercept routing during animation playback.
202
	 * 
203
	 * @see RoutingListener#route(Connection)
204
	 */
205
	public final boolean route(Connection conn) {
206
		return Animation.isAnimating() && Animation.hookPlayback(conn, this);
207
	}
208

    
209
	/**
210
	 * This callback is unused. Reserved for possible future use.
211
	 * 
212
	 * @see RoutingListener#setConstraint(Connection, Object)
213
	 */
214
	public final void setConstraint(Connection connection, Object constraint) {
215
	}
216

    
217
}
(132-132/171)