1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50 package com.touchgraph.graphlayout.interaction;
51
52 import java.awt.Point;
53 import java.awt.event.*;
54
55 import javax.swing.JScrollBar;
56
57 import com.touchgraph.graphlayout.*;
58
59 /*** HVScroll: Allows for scrolling horizontaly+vertically. This can be
60 * done in all sorts of ways, for instance by using the scrollbars, or by
61 * dragging.
62 *
63 * <p>
64 * This code is more complex then it would seem it should be, because scrolling
65 * has to be independent of the screen being warped by lenses. HVScroll needs
66 * to use the tgLensSet object because the offset is recorded in real coordinates, while
67 * the user interacts with the drawn coordinates.
68 *
69 * @author Alexander Shapiro
70 * @version 1.21 $Id: HVScroll.java,v 1.1.1.1 2004/02/06 08:44:07 keesj Exp $
71 */
72 public class HVScroll implements GraphListener {
73
74 private DScrollbar horizontalSB;
75 private DScrollbar verticalSB;
76
77 HVLens hvLens;
78 HVDragUI hvDragUI;
79 HVScrollToCenterUI hvScrollToCenterUI;
80 public boolean scrolling;
81
82 private boolean adjustmentIsInternal;
83 private TGPanel tgPanel;
84 private TGLensSet tgLensSet;
85
86 TGPoint2D offset;
87
88
89
90 /*** Constructor with a TGPanel <tt>tgp</tt> and TGLensSet <tt>tgls</tt>.
91 */
92 public HVScroll(TGPanel tgp, TGLensSet tgls) {
93 tgPanel=tgp;
94 tgLensSet=tgls;
95
96 offset=new TGPoint2D(0,0);
97 scrolling = false;
98 adjustmentIsInternal = false;
99
100 horizontalSB = new DScrollbar(JScrollBar.HORIZONTAL, 0, 100, -1000, 1100);
101 horizontalSB.setBlockIncrement(100);
102 horizontalSB.setUnitIncrement(20);
103
104 horizontalSB.addAdjustmentListener(new horizAdjustmentListener());
105
106 verticalSB = new DScrollbar(JScrollBar.VERTICAL, 0, 100, -1000, 1100);
107 verticalSB.setBlockIncrement(100);
108 verticalSB.setUnitIncrement(20);
109
110 verticalSB.addAdjustmentListener(new vertAdjustmentListener());
111
112 hvLens=new HVLens();
113 hvDragUI = new HVDragUI();
114 hvScrollToCenterUI = new HVScrollToCenterUI();
115
116 tgPanel.addGraphListener(this);
117 }
118
119 public JScrollBar getHorizontalSB() { return horizontalSB; }
120
121 public JScrollBar getVerticalSB() { return verticalSB; }
122
123 public HVDragUI getHVDragUI() { return hvDragUI; }
124
125 public HVLens getLens() { return hvLens; }
126
127 public TGAbstractClickUI getHVScrollToCenterUI() { return hvScrollToCenterUI; }
128
129 public TGPoint2D getTopLeftDraw() {
130 TGPoint2D tld = tgPanel.getTopLeftDraw();
131 tld.setLocation(tld.x-tgPanel.getSize().width/4,tld.y-tgPanel.getSize().height/4);
132 return tld;
133 }
134
135 public TGPoint2D getBottomRightDraw() {
136 TGPoint2D brd = tgPanel.getBottomRightDraw();
137 brd.setLocation(brd.x+tgPanel.getSize().width/4,brd.y+tgPanel.getSize().height/4);
138 return brd;
139 }
140
141 public TGPoint2D getDrawCenter() {
142 return new TGPoint2D(tgPanel.getSize().width/2,tgPanel.getSize().height/2);
143 }
144
145 public void graphMoved() {
146 if (tgPanel.getDragNode()==null && tgPanel.getSize().height>0) {
147 TGPoint2D drawCenter = getDrawCenter();
148
149 TGPoint2D tld = getTopLeftDraw();
150 TGPoint2D brd = getBottomRightDraw();
151
152 double newH = (-(tld.x-drawCenter.x)/(brd.x-tld.x)*2000-1000);
153 double newV = (-(tld.y-drawCenter.y)/(brd.y-tld.y)*2000-1000);
154
155 boolean beyondBorder;
156 beyondBorder = true;
157
158 if(newH<horizontalSB.getMaximum() && newH>horizontalSB.getMinimum() &&
159 newV<verticalSB.getMaximum() && newV>verticalSB.getMinimum() ) beyondBorder=false;
160
161 adjustmentIsInternal = true;
162 horizontalSB.setDValue(newH);
163 verticalSB.setDValue(newV);
164 adjustmentIsInternal = false;
165
166 if (beyondBorder) {
167 adjustHOffset();
168 adjustVOffset();
169 tgPanel.repaint();
170 }
171 }
172 }
173
174 public void graphReset() {
175 horizontalSB.setDValue(0);
176 verticalSB.setDValue(0);
177
178 adjustHOffset();
179 adjustVOffset();
180 }
181
182 class DScrollbar extends JScrollBar {
183 private double doubleValue;
184
185 DScrollbar(int orient, int val, int vis, int min, int max){
186 super(orient, val, vis, min, max);
187 doubleValue=val;
188 }
189 public void setValue(int v) { doubleValue = v; super.setValue(v); }
190 public void setIValue(int v) { super.setValue(v); }
191 public void setDValue(double v) {
192 doubleValue = Math.max(getMinimum(),Math.min(getMaximum(),v));
193 setIValue((int) v);
194 }
195 public double getDValue() { return doubleValue;}
196 }
197
198 private void adjustHOffset() {
199
200 for(int iterate=0;iterate<3;iterate++) {
201 TGPoint2D center= tgPanel.getCenter();
202 TGPoint2D tld = getTopLeftDraw();
203 TGPoint2D brd = getBottomRightDraw();
204
205 double newx = ((horizontalSB.getDValue()+1000.0)/2000)*(brd.x-tld.x)+tld.x;
206 double newy = tgPanel.getSize().height/2;
207 TGPoint2D newCenter = tgLensSet.convDrawToReal(newx,newy);
208
209 offset.setX(offset.x+(newCenter.x-center.x));
210 offset.setY(offset.y+(newCenter.y-center.y));
211
212 tgPanel.processGraphMove();
213 }
214 }
215
216 private void adjustVOffset() {
217 for(int iterate=0;iterate<10;iterate++) {
218 TGPoint2D center= tgPanel.getCenter();
219 TGPoint2D tld = getTopLeftDraw();
220 TGPoint2D brd = getBottomRightDraw();
221
222 double newx = tgPanel.getSize().width/2;
223 double newy = ((verticalSB.getDValue()+1000.0)/2000)*(brd.y-tld.y)+tld.y;
224
225 TGPoint2D newCenter = tgLensSet.convDrawToReal(newx,newy);
226
227 offset.setX(offset.x+(newCenter.x-center.x));
228 offset.setY(offset.y+(newCenter.y-center.y));
229
230 tgPanel.processGraphMove();
231 }
232 }
233
234 private class horizAdjustmentListener implements AdjustmentListener {
235 public void adjustmentValueChanged(AdjustmentEvent e) {
236 if(!adjustmentIsInternal) {
237 adjustHOffset();
238 tgPanel.repaintAfterMove();
239 }
240 }
241 }
242
243 private class vertAdjustmentListener implements AdjustmentListener {
244 public void adjustmentValueChanged(AdjustmentEvent e) {
245 if(!adjustmentIsInternal) {
246 adjustVOffset();
247 tgPanel.repaintAfterMove();
248 }
249 }
250 }
251
252
253 class HVLens extends TGAbstractLens {
254 protected void applyLens(TGPoint2D p) {
255 p.x=p.x-offset.x;
256 p.y=p.y-offset.y;
257 }
258
259 protected void undoLens(TGPoint2D p) {
260 p.x=p.x+offset.x;
261 p.y=p.y+offset.y;
262 }
263 }
264
265 public void setOffset(Point p) {
266 offset.setLocation(p.x,p.y);
267 tgPanel.processGraphMove();
268 graphMoved();
269 }
270
271 public Point getOffset() {
272 return new Point((int) offset.x,(int) offset.y);
273 }
274
275 public void scrollAtoB(TGPoint2D drawFrom, TGPoint2D drawTo) {
276 TGPoint2D from = tgLensSet.convDrawToReal(drawFrom);
277 TGPoint2D to = tgLensSet.convDrawToReal(drawTo);
278 offset.setX(offset.x+(from.x-to.x));
279 offset.setY(offset.y+(from.y-to.y));
280 }
281
282 public void scrollToCenter(final Node n) {
283 final TGPoint2D drawFrom =new TGPoint2D(n.drawx,n.drawy);
284 final TGPoint2D drawTo = getDrawCenter();
285 scrollAtoB(drawFrom,drawTo);
286 }
287
288 public void slowScrollToCenter(final Node n) {
289 final TGPoint2D drawFrom =new TGPoint2D(n.drawx,n.drawy);
290 final TGPoint2D drawTo = getDrawCenter();
291 scrolling = true;
292 Thread scrollThread = new Thread() {
293 public void run() {
294 double fx= drawFrom.x;
295 double fy= drawFrom.y;
296 double tx= drawTo.x;
297 double ty= drawTo.y;
298 int scrollSteps = (int) Math.sqrt((fx-tx)*(fx-tx)+(fy-ty)*(fy-ty))/10 + 1;
299
300 for(int i=0;i< scrollSteps-1;i++) {
301
302
303
304 double fromPcnt = ((double) scrollSteps-i)/scrollSteps;
305 double toPcnt = ((double) scrollSteps-1-i)/scrollSteps;
306
307 double midfx = fx*fromPcnt+tx*(1-fromPcnt);
308 double midfy = fy*fromPcnt+ty*(1-fromPcnt);
309 double midtx = fx*toPcnt+tx*(1-toPcnt);
310 double midty = fy*toPcnt+ty*(1-toPcnt);
311
312 scrollAtoB(new TGPoint2D(midfx,midfy), new TGPoint2D(midtx,midty));
313 tgPanel.repaintAfterMove();
314 try {
315 Thread.sleep(50);
316 } catch (InterruptedException ex) { }
317 }
318 scrollAtoB(new TGPoint2D(n.drawx,n.drawy),getDrawCenter());
319 tgPanel.repaintAfterMove();
320 HVScroll.this.scrolling = false;
321 }
322 };
323 scrollThread.start();
324 }
325
326 class HVScrollToCenterUI extends TGAbstractClickUI {
327 public void mouseClicked(MouseEvent e) {
328 Node mouseOverN=tgPanel.getMouseOverN();
329 if(!scrolling && mouseOverN!=null)
330 slowScrollToCenter(mouseOverN);
331 }
332 }
333
334 class HVDragUI extends TGAbstractDragUI{
335 TGPoint2D lastMousePos;
336 HVDragUI() { super(HVScroll.this.tgPanel); }
337
338 public void preActivate() {}
339 public void preDeactivate() {}
340
341 public void mousePressed(MouseEvent e) {
342 lastMousePos = new TGPoint2D(e.getX(), e.getY());
343 }
344 public void mouseReleased(MouseEvent e) {}
345 public void mouseDragged(MouseEvent e) {
346 if(!scrolling) scrollAtoB(lastMousePos, new TGPoint2D(e.getX(), e.getY()));
347 lastMousePos.setLocation(e.getX(),e.getY());
348 this.tgPanel.repaintAfterMove();
349 }
350 }
351
352 }