1ec85fadecd4fc4fcd625454ab31c2478a7eb050
[deliverable/tracecompass.git] / org.eclipse.linuxtools.tmf.ui / src / org / eclipse / linuxtools / tmf / ui / views / uml2sd / ScrollView.java
1 /**********************************************************************
2 * Copyright (c) 2005, 2008 IBM Corporation and others.
3 * Copyright (c) 2011, 2012 Ericsson.
4 *
5 * All rights reserved. This program and the accompanying materials
6 * are made available under the terms of the Eclipse Public License v1.0
7 * which accompanies this distribution, and is available at
8 * http://www.eclipse.org/legal/epl-v10.html
9 *
10 * Contributors:
11 * IBM - Initial API and implementation
12 * Bernd Hufmann - Updated for TMF
13 **********************************************************************/
14 package org.eclipse.linuxtools.tmf.ui.views.uml2sd;
15
16 import java.util.Timer;
17 import java.util.TimerTask;
18
19 import org.eclipse.linuxtools.tmf.ui.views.uml2sd.util.SDMessages;
20 import org.eclipse.swt.SWT;
21 import org.eclipse.swt.events.ControlListener;
22 import org.eclipse.swt.events.FocusEvent;
23 import org.eclipse.swt.events.FocusListener;
24 import org.eclipse.swt.events.KeyEvent;
25 import org.eclipse.swt.events.KeyListener;
26 import org.eclipse.swt.events.MouseEvent;
27 import org.eclipse.swt.events.MouseListener;
28 import org.eclipse.swt.events.MouseMoveListener;
29 import org.eclipse.swt.events.MouseTrackListener;
30 import org.eclipse.swt.events.PaintEvent;
31 import org.eclipse.swt.events.PaintListener;
32 import org.eclipse.swt.events.SelectionEvent;
33 import org.eclipse.swt.events.SelectionListener;
34 import org.eclipse.swt.events.TypedEvent;
35 import org.eclipse.swt.graphics.Color;
36 import org.eclipse.swt.graphics.Cursor;
37 import org.eclipse.swt.graphics.GC;
38 import org.eclipse.swt.graphics.ImageData;
39 import org.eclipse.swt.graphics.PaletteData;
40 import org.eclipse.swt.graphics.Point;
41 import org.eclipse.swt.graphics.RGB;
42 import org.eclipse.swt.graphics.Rectangle;
43 import org.eclipse.swt.widgets.Button;
44 import org.eclipse.swt.widgets.Canvas;
45 import org.eclipse.swt.widgets.Composite;
46 import org.eclipse.swt.widgets.Control;
47 import org.eclipse.swt.widgets.Display;
48 import org.eclipse.swt.widgets.Layout;
49 import org.eclipse.swt.widgets.ScrollBar;
50 import org.eclipse.swt.widgets.Scrollable;
51 import org.eclipse.swt.widgets.Shell;
52
53 /**
54 * ScrollView widget provides a scrolling area with on-demand scroll bars.
55 * Overview scrollable panel can be used (@see setOverviewEnabled()).
56 *
57 * @author Eric Miravete
58 * @version 1.0
59 */
60 public class ScrollView extends Composite {
61
62 // ------------------------------------------------------------------------
63 // Attributes
64 // ------------------------------------------------------------------------
65
66 // Value for scroll bar mode, default is AUTO
67 /**
68 * Scroll bar mode AUTO
69 */
70 public static final int AUTO = 0;
71 /**
72 * Scroll bar mode ALWAYS_ON
73 */
74 public static final int ALWAYS_ON = 1;
75 /**
76 * Scroll bar mode ALWAYS_OFF
77 */
78 public static final int ALWAYS_OFF = 2;
79 /**
80 * Bit mask for visible vertical scroll bar
81 */
82 public static final int VBAR = 0x01;
83 /**
84 * Bit mask for visible horizontal scroll bar
85 */
86 public static final int HBAR = 0x02;
87 /**
88 * Value of the contents height property.
89 */
90 protected int fContentsHeight = 0;
91 /**
92 * Value of the contents width property.
93 */
94 protected int fContentsWidth = 0;
95 /**
96 * Value of the contents x coordinate property
97 */
98 protected int fContentsX = 0;
99 /**
100 * Value of the contents y coordinate property
101 */
102 protected int fContentsY = 0;
103 /**
104 * Scroll bar mode of horizontal scroll bar.
105 */
106 protected int fHorScrollbarMode = AUTO;
107 /**
108 * Scroll bar mode of vertical scroll bar.
109 */
110 protected int fVertScrollbarMode = AUTO;
111 /**
112 * Increment for the horizontal scroll bar.
113 */
114 protected int fHorScrollbarIncrement = 10;
115 /**
116 * Increment for the vertical scroll bar.
117 */
118 protected int fVertScrollbarIncrement = 10;
119 /**
120 * Flag whether auto scroll is enabled or not.
121 */
122 protected boolean fAutoScrollEnabled = true;
123 /**
124 * Value of the auto scroll period.
125 */
126 protected int fAutoScrollPeriod = 75;
127 /**
128 * The local paint listener reference.
129 */
130 protected PaintListener fLocalPaintListener = null;
131 /**
132 * The local mouse move listener reference.
133 */
134 protected MouseMoveListener fLocalMouseMoveListener = null;
135 /**
136 * The local mouse listener reference.
137 */
138 protected MouseListener fLocalMouseListener = null;
139 /**
140 * The local control listener reference.
141 */
142 protected ControlListener fLocalControlListener = null;
143 /**
144 * The local key listener reference.
145 */
146 protected KeyListener fLocalKeyListener = null;
147 // Canvas for vertical/horizontal Scroll Bar only ... because new ScrollBar() does works.
148 /**
149 * Canvas for horizontal scroll bar.
150 */
151 protected Canvas fHorScrollBar;
152 /**
153 * Canvas for vertical scroll bar.
154 */
155 protected Canvas fVertScrollBar;
156 /**
157 * Canvas for the view control.
158 */
159 protected Canvas fViewControl;
160 /**
161 * Control used in the bottom right corner @see setCornerControl() and @see setOverviewEnabled(true)
162 */
163 protected Control fCornerControl;
164 /**
165 * Size of overview widget.
166 */
167 protected int fOverviewSize = 100; // default size for overview
168 /**
169 * Timer for auto_scroll feature
170 */
171 protected AutoScroll fAutoScroll = null;
172 /**
173 * TimerTask for auto_scroll feature !=null when auto scroll is running
174 */
175 protected Timer fAutoScrollTimer = null;
176 /**
177 * where mouse down appear on contents area (x coordinate)
178 */
179 protected int fMouseDownX = -1;
180 /**
181 * where mouse down appear on contents area (y coordinate)
182 */
183 protected int fMousDownY = -1;
184
185
186 // ------------------------------------------------------------------------
187 // Constructors
188 // ------------------------------------------------------------------------
189
190 /**
191 * Create a ScrollView, child of composite c. Both scroll bar have the mode AUTO. Auto scroll feature is enabled
192 * using a delay of 250ms. Overview feature is not enabled by default (use setOverviewEnabled()).
193 *
194 * @param c The parent composite
195 * @param style The SWT style bits @see SWT
196 */
197 public ScrollView(Composite c, int style) {
198 this(c, style, true);
199 }
200
201 /**
202 * Create a ScrollView, child of composite c. Both scroll bar have the mode AUTO. Auto scroll feature is enabled
203 * using a delay of 250ms. Overview feature is not enabled by default (use setOverviewEnabled()).
204 *
205 * @param c The parent composite.
206 * @param style The SWT style bits @see SWT
207 * @param mouseWheel Flag to force scrollView to handles mouse wheel
208 */
209 public ScrollView(Composite c, int style, boolean mouseWheel) {
210 super(c, SWT.NONE); // style&(~(SWT.H_SCROLL|SWT.V_SCROLL)));
211
212 fHorScrollBar = new Canvas(this, SWT.H_SCROLL);
213 if (mouseWheel) {
214 // force scroll bar to get mouse wheel, those scrollbar will be hidden
215 fViewControl = new Canvas(this, style | SWT.H_SCROLL | SWT.V_SCROLL);
216 } else {
217 fViewControl = new Canvas(this, style);
218 }
219 fViewControl.setBackground(getBackground());
220 // hide scroll bar as their are replaced by fHorScrollBar and fVertScrollBar.
221 if (mouseWheel) {
222 fViewControl.getVerticalBar().setVisible(false);
223 fViewControl.getHorizontalBar().setVisible(false);
224 }
225 fVertScrollBar = new Canvas(this, SWT.V_SCROLL);
226 // make fVerScrollBar able to receive mouse wheel
227 // does not help as we can't set a MouseListener on fVerScrollBar.getVerticalBar()
228 // to set focus on viewcontrol_
229 // fVerScrollBar.addKeyListener( new KeyAdapter() {});
230
231 setLayout(new SVLayout());
232
233 fLocalPaintListener = new PaintListener() {
234 @Override
235 public void paintControl(PaintEvent event) {
236 // use clipping, to reduce cost of paint.
237 Rectangle r = event.gc.getClipping();
238 int cx = viewToContentsX(r.x);
239 int cy = viewToContentsY(r.y);
240 drawContents(event.gc, cx, cy, r.width, r.height);
241 }
242 };
243 fViewControl.addPaintListener(fLocalPaintListener);
244
245 fLocalMouseMoveListener = new MouseMoveListener() {
246 @Override
247 public void mouseMove(MouseEvent e) {
248 int ox = e.x, oy = e.y;
249 e.x = viewToContentsX(e.x);
250 e.y = viewToContentsY(e.y);
251 contentsMouseMoveEvent(e);
252 e.x = ox;
253 e.y = oy;
254 }
255 };
256
257 fViewControl.addMouseMoveListener(fLocalMouseMoveListener);
258
259 MouseTrackListener localMouseTrackListener = new MouseTrackListener() {
260 @Override
261 public void mouseEnter(MouseEvent e) {
262 int ox = e.x, oy = e.y;
263 e.x = viewToContentsX(e.x);
264 e.y = viewToContentsY(e.y);
265 contentsMouseEnter(e);
266 e.x = ox;
267 e.y = oy;
268 }
269
270 @Override
271 public void mouseHover(MouseEvent e) {
272 int ox = e.x, oy = e.y;
273 e.x = viewToContentsX(e.x);
274 e.y = viewToContentsY(e.y);
275 contentsMouseHover(e);
276 e.x = ox;
277 e.y = oy;
278 }
279
280 @Override
281 public void mouseExit(MouseEvent e) {
282 int ox = e.x, oy = e.y;
283 e.x = viewToContentsX(e.x);
284 e.y = viewToContentsY(e.y);
285 contentsMouseExit(e);
286 e.x = ox;
287 e.y = oy;
288 }
289
290 };
291
292 fViewControl.addMouseTrackListener(localMouseTrackListener);
293
294 fLocalMouseListener = new MouseListener() {
295 @Override
296 public void mouseDoubleClick(MouseEvent e) {
297 int ox = e.x, oy = e.y;
298 e.x = viewToContentsX(e.x);
299 e.y = viewToContentsY(e.y);
300 contentsMouseDoubleClickEvent(e);
301 e.x = ox;
302 e.y = oy;
303 }
304
305 @Override
306 public void mouseDown(MouseEvent e) {
307 int ox = e.x, oy = e.y;
308 e.x = fMouseDownX = viewToContentsX(e.x);
309 e.y = fMousDownY = viewToContentsY(e.y);
310 contentsMouseDownEvent(e);
311 e.x = ox;
312 e.y = oy;
313 }
314
315 @Override
316 public void mouseUp(MouseEvent e) {
317 int ox = e.x, oy = e.y;
318 e.x = viewToContentsX(e.x);
319 e.y = viewToContentsY(e.y);
320 contentsMouseUpEvent(e);
321 e.x = ox;
322 e.y = oy;
323 // here because class extenting me can catch mouse Up and want to scroll...
324 fMouseDownX = fMousDownY = -1;
325 }
326 };
327 fViewControl.addMouseListener(fLocalMouseListener);
328
329 fLocalKeyListener = new KeyListener() {
330 @Override
331 public void keyPressed(KeyEvent e) {
332 keyPressedEvent(e);
333 }
334
335 @Override
336 public void keyReleased(KeyEvent e) {
337 keyReleasedEvent(e);
338 }
339 };
340
341 fViewControl.addKeyListener(fLocalKeyListener);
342
343 getVerticalBar().addSelectionListener(new SelectionListener() {
344 @Override
345 public void widgetSelected(SelectionEvent e) {
346 setContentsPos(fContentsX, getVerticalBar().getSelection());
347 // need to change "hidden" vertical bar value ?
348 // force focus on fViewControl so we got future mouse wheel's scroll events
349 if (!fViewControl.isFocusControl()) {
350 fViewControl.setFocus();
351 }
352 }
353
354 @Override
355 public void widgetDefaultSelected(SelectionEvent e) {
356 }
357 });
358
359 if (fViewControl.getVerticalBar() != null) {
360 // add fViewControl hidden scrollbar listener to get mouse wheel ...
361 fViewControl.getVerticalBar().addSelectionListener(new SelectionListener() {
362 @Override
363 public void widgetSelected(SelectionEvent e) {
364 ScrollBar b = fViewControl.getVerticalBar();
365 setContentsPos(fContentsX, b.getSelection());
366 // change "real" vertical bar selection too
367 getVerticalBar().setSelection(b.getSelection());
368 }
369
370 @Override
371 public void widgetDefaultSelected(SelectionEvent e) {
372 }
373 });
374 }
375 getHorizontalBar().addSelectionListener(new SelectionListener() {
376 @Override
377 public void widgetSelected(SelectionEvent e) {
378 setContentsPos(getHorizontalBar().getSelection(), fContentsY);
379 // need to change "real" horizontal bar too ?
380 // force focus on fViewControl so we got future mouse wheel's scroll events
381 if (!fViewControl.isFocusControl()) {
382 fViewControl.setFocus();
383 }
384 }
385
386 @Override
387 public void widgetDefaultSelected(SelectionEvent e) {
388 }
389 });
390 if (fViewControl.getHorizontalBar() != null) {
391 fViewControl.getHorizontalBar().addSelectionListener(new SelectionListener() {
392 @Override
393 public void widgetSelected(SelectionEvent e) {
394 ScrollBar b = fViewControl.getHorizontalBar();
395 setContentsPos(b.getSelection(), fContentsY);
396 // change "real" vertical bar selection too
397 getHorizontalBar().setSelection(b.getSelection());
398 }
399
400 @Override
401 public void widgetDefaultSelected(SelectionEvent e) {
402 }
403 });
404 }
405 }
406
407 // ------------------------------------------------------------------------
408 // Methods
409 // ------------------------------------------------------------------------
410
411 /*
412 * (non-Javadoc)
413 * @see org.eclipse.swt.widgets.Composite#setFocus()
414 */
415 @Override
416 public boolean setFocus() {
417 return fViewControl.forceFocus();
418 }
419
420 /*
421 * (non-Javadoc)
422 * @see org.eclipse.swt.widgets.Control#setCursor(org.eclipse.swt.graphics.Cursor)
423 */
424 @Override
425 public void setCursor(Cursor cursor) {
426 fViewControl.setCursor(cursor);
427 }
428
429 /*
430 * Dispose controls used in scroll view
431 *
432 * (non-Javadoc)
433 * @see org.eclipse.swt.widgets.Widget#dispose()
434 */
435 @Override
436 public void dispose() {
437 if (fAutoScroll != null) {
438 fAutoScroll.cancel();
439 fAutoScroll = null;
440 }
441 if (fViewControl != null) {
442 fViewControl.dispose();
443 }
444 fViewControl = null;
445 if (fVertScrollBar != null) {
446 fVertScrollBar.dispose();
447 }
448 fVertScrollBar = null;
449 if (fHorScrollBar != null) {
450 fHorScrollBar.dispose();
451 }
452 fHorScrollBar = null;
453 if (fCornerControl != null) {
454 Object data = fCornerControl.getData();
455 if (data instanceof Overview) {
456 ((Overview) data).dispose();
457 }
458 fCornerControl.dispose();
459 fCornerControl = null;
460 }
461 super.dispose();
462 }
463
464 /*
465 * (non-Javadoc)
466 * @see org.eclipse.swt.widgets.Composite#getClientArea()
467 */
468 @Override
469 public Rectangle getClientArea() {
470 return fViewControl.getClientArea();
471 }
472
473 /*
474 * (non-Javadoc)
475 * @see org.eclipse.swt.widgets.Control#setBackground(org.eclipse.swt.graphics.Color)
476 */
477 @Override
478 public void setBackground(Color c) {
479 super.setBackground(c);
480 fViewControl.setBackground(c);
481 }
482
483 /*
484 * (non-Javadoc)
485 * @see org.eclipse.swt.widgets.Control#setToolTipText(java.lang.String)
486 */
487 @Override
488 public void setToolTipText(String text) {
489 fViewControl.setToolTipText(text);
490 }
491
492 /**
493 * Draw overview area, @see setOverviewEnabled. By default draw a rectangle corresponding to the visible area of
494 * scroll view. You can redefine this method to draw the contents as drawContents does... ...in an other magnify
495 * factor.
496 *
497 * @param gc GC to used to draw.
498 * @param r Rectangle corresponding to the client area of overview.
499 */
500 protected void drawOverview(GC gc, Rectangle r) {
501 int x = (int) (r.width * fContentsX / (float) fContentsWidth);
502 int y = (int) (r.height * fContentsY / (float) fContentsHeight);
503 int vw = getVisibleWidth();
504 int vh = getVisibleHeight();
505 int w = r.width - 1;
506 if (fContentsWidth > vw) {
507 w = (int) (r.width * vw / (float) fContentsWidth);
508 }
509 int h = r.height - 1;
510 if (fContentsHeight > vh) {
511 h = (int) (r.height * vh / (float) fContentsHeight);
512 }
513
514 gc.setForeground(getForeground());
515 // too small rectangle ?
516 if (w < 5 || h < 5) {
517 // use a cross ...
518 gc.drawLine(x, 0, x, r.height);
519 gc.drawLine(0, y, r.width, y);
520 } else {
521 gc.drawRectangle(x, y, w, h);
522 }
523 }
524
525 /**
526 * Remove the local Listener and add the new listener.
527 *
528 * @param nlistener the new listener
529 */
530 public void replaceControlListener(ControlListener nlistener) {
531 if (fLocalControlListener != null) {
532 removeControlListener(fLocalControlListener);
533 fLocalControlListener = null;
534 }
535 addControlListener(nlistener);
536 }
537
538 /**
539 * Remove the local Listener and add the new listener.
540 *
541 * @param nlistener the new listener
542 */
543 public void replaceKeyListener(KeyListener nlistener) {
544 if (fLocalKeyListener != null) {
545 removeKeyListener(fLocalKeyListener);
546 fLocalKeyListener = null;
547 }
548 addKeyListener(nlistener);
549 }
550
551 /**
552 * Remove the local Listener and add the new listener.
553 *
554 * @param nlistener the new listener
555 */
556 public void replaceMouseListener(MouseListener nlistener) {
557 if (fLocalMouseListener != null) {
558 removeMouseListener(fLocalMouseListener);
559 fLocalMouseListener = null;
560 }
561 fViewControl.addMouseListener(nlistener);
562 }
563
564 /**
565 * Remove the local Listener and add the new listener.
566 *
567 * @param nlistener the new listener
568 */
569 public void replaceMouseMoveListener(MouseMoveListener nlistener) {
570 if (fLocalMouseMoveListener != null) {
571 removeMouseMoveListener(fLocalMouseMoveListener);
572 fLocalMouseMoveListener = null;
573 }
574 fViewControl.addMouseMoveListener(nlistener);
575 }
576
577 /**
578 * Remove the local Listener and add the new listener.
579 *
580 * @param nlistener the new listener
581 */
582 public void replacePaintListener(PaintListener nlistener) {
583 if (fLocalPaintListener != null) {
584 removePaintListener(fLocalPaintListener);
585 fLocalPaintListener = null;
586 }
587 fViewControl.addPaintListener(nlistener);
588 }
589
590 /**
591 * Access method for the contentsHeight property.
592 *
593 * @return the current value of the contentsHeight property
594 */
595 public int getContentsHeight() {
596 return fContentsHeight;
597 }
598
599 /**
600 * Access method for the contentsWidth property.
601 *
602 * @return the current value of the contentsWidth property
603 */
604 public int getContentsWidth() {
605 return fContentsWidth;
606 }
607
608 /**
609 * Access method for the contentsX property.
610 *
611 * @return the current value of the contentsX property
612 */
613 public int getContentsX() {
614 return fContentsX;
615 }
616
617 /**
618 * Access method for the contentsY property.
619 *
620 * @return the current value of the contentsY property
621 */
622 public int getContentsY() {
623 return fContentsY;
624 }
625
626 /**
627 * Determines if the dragAutoScroll property is true.
628 *
629 * @return <code>true<code> if the dragAutoScroll property is true
630 */
631 public boolean isDragAutoScroll() {
632 return fAutoScrollEnabled;
633 }
634
635 /**
636 * Sets the value of the dragAutoScroll property.
637 *
638 * @param aDragAutoScroll the new value of the dragAutoScroll property
639 */
640 public void setDragAutoScroll(boolean aDragAutoScroll) {
641 fAutoScrollEnabled = aDragAutoScroll;
642 if (!fAutoScrollEnabled && (fAutoScroll != null)) {
643 fAutoScroll.cancel();
644 fAutoScroll = null;
645 }
646 }
647
648 /**
649 * Change delay (in millisec) used for auto scroll feature.
650 *
651 * @param period new period between to auto scroll
652 */
653 public void setDragAutoScrollPeriod(int period) {
654 fAutoScrollPeriod = Math.max(0, period);
655 }
656
657 /**
658 * Return auto scroll period.
659 *
660 * @return The period
661 */
662 public int getDragAutoScrollPeriod() {
663 return fAutoScrollPeriod;
664 }
665
666 /**
667 * Access method for the hScrollBarMode property.
668 *
669 * @return the current value of the hScrollBarMode property
670 */
671 public int getHScrollBarMode() {
672 return fHorScrollbarMode;
673 }
674
675 /**
676 * Sets the value of the hScrollBarMode property.
677 *
678 * @param aHScrollBarMode the new value of the hScrollBarMode property
679 */
680 public void setHScrollBarMode(int aHScrollBarMode) {
681 fHorScrollbarMode = aHScrollBarMode;
682 }
683
684 /**
685 * Access method for the vScrollBarMode property.
686 *
687 * @return the current value of the vScrollBarMode property
688 */
689 public int getVScrollBarMode() {
690 return fVertScrollbarMode;
691 }
692
693 /**
694 * Sets the value of the vScrollBarMode property.
695 *
696 * @param aVScrollBarMode the new value of the vScrollBarMode property
697 */
698 public void setVScrollBarMode(int aVScrollBarMode) {
699 fVertScrollbarMode = aVScrollBarMode;
700 }
701
702 /**
703 * Return horizontal scroll bar increment, default:1
704 *
705 * @return The increment
706 */
707 public int getHScrollBarIncrement() {
708 return fHorScrollbarIncrement;
709 }
710
711 /**
712 * Return vertical scroll bar increment, default:1
713 *
714 * @return The increment
715 */
716 public int getVScrollBarIncrement() {
717 return fVertScrollbarIncrement;
718 }
719
720 /**
721 * Change horizontal scroll bar increment, minimum:1. Page increment is
722 * always set to visible width.
723 *
724 * @param inc
725 * Increment value to set
726 */
727 public void setHScrollBarIncrement(int inc) {
728 fHorScrollbarIncrement = Math.max(1, inc);
729 }
730
731 /**
732 * Change vertical scroll bar increment, minimum:1. Page increment is always
733 * set to visible height.
734 *
735 * @param inc
736 * Increment value to set
737 */
738 public void setVScrollBarIncrement(int inc) {
739 fVertScrollbarIncrement = Math.max(1, inc);
740 }
741
742 /**
743 * Enable or disable overview feature. Enabling overview, dispose and replace existing corner control by a button.
744 * Clicking in it open overview, move mouse cursor holding button to move scroll view and release button to hide
745 * overview. Tip: hold control and/or shift key while moving mouse when overview is open made fine scroll.
746 *
747 * @param value true to engage overview feature
748 */
749 public void setOverviewEnabled(boolean value) {
750 if (isOverviewEnabled() == value) {
751 return;
752 }
753
754 Control cc = null;
755 if (value) {
756 Button b = new Button(this, SWT.NONE);
757 b.setText("+"); //$NON-NLS-1$
758 Overview ovr = new Overview();
759 ovr.useControl(b);
760 b.setData(ovr);
761 cc = b;
762 b.setToolTipText(SDMessages._78);
763 }
764 setCornerControl(cc);
765 }
766
767 /**
768 * Change overview size (at ratio 1:1), default is 100
769 *
770 * @param size
771 * The new size
772 */
773 public void setOverviewSize(int size) {
774 fOverviewSize = Math.abs(size);
775 }
776
777 /**
778 * Returns whether the overview is enabled or not.
779 *
780 * @return true is overview feature is enabled
781 */
782 public boolean isOverviewEnabled() {
783 if (fCornerControl instanceof Button) {
784 Object data = ((Button) fCornerControl).getData();
785 // overview alreay
786 if (data instanceof Overview) {
787 return true;
788 }
789 }
790 return false;
791 }
792
793 /**
794 * Returns the overview size at ratio 1:1.
795 *
796 * @return current overview size at ratio 1:1
797 */
798 public int getOverviewSize() {
799 return fOverviewSize;
800 }
801
802 /**
803 * Returns control used to display view (might not be this object). Use this control to add/remove listener on the
804 * draw area.
805 *
806 * @return control used to display view (might not be this object).
807 */
808 public Control getViewControl() {
809 return fViewControl;
810 }
811
812 /**
813 * Called when the mouse enter the ScrollView area
814 *
815 * @param e
816 * Mouse event
817 */
818 protected void contentsMouseExit(MouseEvent e) {
819 }
820
821 /**
822 * Called when the mouse enter the ScrollView area after and system defined
823 * time
824 *
825 * @param e
826 * Mouse event
827 */
828 protected void contentsMouseHover(MouseEvent e) {
829 }
830
831 /**
832 * Called when the mouse enter the ScrollView area
833 *
834 * @param e
835 * Mouse event
836 */
837 protected void contentsMouseEnter(MouseEvent e) {
838 }
839
840 /**
841 * Called when user double on contents area.
842 *
843 * @param e
844 * Mouse event
845 */
846 protected void contentsMouseDoubleClickEvent(MouseEvent e) {
847 }
848
849 /**
850 * Called when mouse is on contents area and button is pressed.
851 *
852 * @param e
853 * Mouse event
854 */
855 protected void contentsMouseDownEvent(MouseEvent e) {
856 fMouseDownX = e.x;
857 fMousDownY = e.y;
858 }
859
860 /**
861 * TimerTask for auto scroll feature.
862 */
863 protected static class AutoScroll extends TimerTask {
864
865 /** X delta */
866 public int deltaX;
867
868 /** Y delta */
869 public int deltaY;
870
871 /** ScrollView object */
872 public ScrollView scrollView;
873
874 /**
875 * Constructor.
876 *
877 * @param sv
878 * ScrollView object to use
879 * @param dx
880 * X delta
881 * @param dy
882 * Y delta
883 */
884 public AutoScroll(ScrollView sv, int dx, int dy) {
885 scrollView = sv;
886 deltaX = dx;
887 deltaY = dy;
888 }
889
890 @Override
891 public void run() {
892 Display.getDefault().asyncExec(new Runnable() {
893 @Override
894 public void run() {
895 scrollView.scrollBy(deltaX, deltaY);
896 }
897 });
898 }
899 }
900
901 /**
902 * Called when mouse is on contents area and mode.
903 *
904 * @param event
905 * Mouse event
906 */
907 protected void contentsMouseMoveEvent(MouseEvent event) {
908 if ((event.stateMask & SWT.BUTTON_MASK) != 0) {
909 if (!fAutoScrollEnabled) {
910 scrollBy(-(event.x - fMouseDownX), -(event.y - fMousDownY));
911 return;
912 }
913
914 int sx = 0, sy = 0;
915
916 int v_right = getContentsX() + getVisibleWidth();
917 int v_bottom = getContentsY() + getVisibleHeight();
918
919 // auto scroll... ?
920 if (event.x < getContentsX()) {
921 sx = (getContentsX() - event.x);
922 fMouseDownX = getContentsX();
923 } else if (event.x > v_right) {
924 sx = -event.x + v_right;
925 fMouseDownX = v_right;
926 }
927 if (event.y < getContentsY()) {
928 sy = (getContentsY() - event.y);
929 fMousDownY = getContentsY();
930 } else if (event.y > v_bottom) {
931 sy = -event.y + v_bottom;
932 fMousDownY = v_bottom;
933 }
934
935 if (sx != 0 || sy != 0) {
936 // start auto scroll...
937 if (fAutoScroll == null) {
938 if (fAutoScrollTimer == null) {
939 fAutoScrollTimer = new Timer(true);
940 }
941 fAutoScroll = new AutoScroll(this, sx, sy);
942 fAutoScrollTimer.schedule(fAutoScroll, 0, fAutoScrollPeriod);
943 } else {
944 fAutoScroll.deltaX = sx;
945 fAutoScroll.deltaY = sy;
946 }
947 } else {
948 if (fAutoScroll != null) {
949 fAutoScroll.cancel();
950 fAutoScroll = null;
951 }
952
953 scrollBy(-(event.x - fMouseDownX), -(event.y - fMousDownY));
954 }
955 }
956 }
957
958 /**
959 * Called when mouse is on contents area and button is released
960 *
961 * @param event
962 * Mouse event
963 */
964 protected void contentsMouseUpEvent(MouseEvent event) {
965 // reset auto scroll if it's engaged
966 if (fAutoScroll != null) {
967 fAutoScroll.cancel();
968 fAutoScroll = null;
969 }
970 }
971
972 /**
973 * Responsible to draw contents area. At least rectangle clipX must be
974 * redrawn. This rectangle is given in contents coordinates. By default, no
975 * paint is produced.
976 *
977 * @param gc
978 * Graphics context
979 * @param clipx
980 * X clip
981 * @param clipy
982 * Y clip
983 * @param clipw
984 * W clip
985 * @param cliph
986 * H clip
987 */
988 protected void drawContents(GC gc, int clipx, int clipy, int clipw, int cliph) {
989 }
990
991 /**
992 * Change the size of the contents area.
993 *
994 * @param width new width of the area.
995 * @param height new height of the area.
996 */
997 public void resizeContents(int width, int height) {
998 int localWidth = width;
999 int localHeight = height;
1000
1001 if (localWidth < 0) {
1002 localWidth = 0;
1003 }
1004 if (localHeight < 0) {
1005 localHeight = 0;
1006 }
1007
1008 int oldW = fContentsWidth;
1009 int oldH = fContentsHeight;
1010
1011 if (localWidth == oldW && localHeight == oldH) {
1012 return;
1013 }
1014
1015 fContentsWidth = localWidth;
1016 fContentsHeight = localHeight;
1017
1018 if (oldW > localWidth) {
1019 int s = localWidth;
1020 localWidth = oldW;
1021 oldW = s;
1022 }
1023
1024 int vis_width = getVisibleWidth();
1025 int vis_height = getVisibleHeight();
1026 if (oldW < vis_width) {
1027 if (localWidth > vis_width) {
1028 localWidth = vis_width;
1029 }
1030 fViewControl.redraw(getContentsX() + oldW, 0, localWidth - oldW, vis_height, true);
1031 }
1032
1033 if (oldH > localHeight) {
1034 int s = localHeight;
1035 localHeight = oldH;
1036 oldH = s;
1037 }
1038
1039 if (oldH < vis_height) {
1040 if (localHeight > vis_height) {
1041 localHeight = vis_height;
1042 }
1043 fViewControl.redraw(0, getContentsY() + oldH, vis_width, localHeight - oldH, true);
1044 }
1045 if (updateScrollBarVisiblity()) {
1046 layout();
1047 } else {
1048 updateScrollBarsValues();
1049 }
1050 }
1051
1052 // redefined for internal use ..
1053 @Override
1054 public void redraw() {
1055 super.redraw();
1056 // ..need to redraw this already:
1057 fViewControl.redraw();
1058 }
1059
1060 /**
1061 * @param delataX The delta in X
1062 * @param deltaY the delta in Y
1063 */
1064 public void scrollBy(int delataX, int deltaY) {
1065 setContentsPos(getContentsX() + delataX, getContentsY() + deltaY);
1066 }
1067
1068 /**
1069 * Scroll to ensure point(in contents coordinates) is visible.
1070 *
1071 * @param px Point's x position
1072 * @param py Point's y position
1073 */
1074 public void ensureVisible(int px, int py) {
1075 int cx = getContentsX(), cy = getContentsY();
1076 int right = getContentsX() + getVisibleWidth();
1077 int bottom = getContentsY() + getVisibleHeight();
1078 if (px < getContentsX()) {
1079 cx = px;
1080 } else if (px > right) {
1081 cx = px - getVisibleWidth();
1082 }
1083 if (py < getContentsY()) {
1084 cy = py;
1085 } else if (py > bottom) {
1086 cy = py - getVisibleHeight();
1087 }
1088 setContentsPos(cx, cy);
1089 }
1090
1091 /**
1092 * Make rectangle (x,y,w,h, in contents coordinates) visible. if rectangle cannot be completely visible, use
1093 * align flags.
1094 *
1095 * @param xValue x contents coordinates of rectangle.
1096 * @param yValue y contents coordinates of rectangle.
1097 * @param width width of rectangle.
1098 * @param height height of rectangle.
1099 * @param align bit or'ed SWT flag like SWT.LEFT,RIGHT,CENTER,TOP,BOTTOM,VERTICAL used only for bigger rectangle
1100 * than visible area. By default CENTER/VERTICAL
1101 */
1102 public void ensureVisible(int xValue, int yValue, int width, int height, int align) {
1103 ensureVisible(xValue, yValue, width, height, align, false);
1104 }
1105
1106 /**
1107 * Make rectangle (xValue,yValue,width,height, in contents coordinates) visible. if rectangle cannot be completely visible, use
1108 * align flags.
1109 *
1110 * @param xValue x contents coordinates of rectangle.
1111 * @param yValue y contents coordinates of rectangle.
1112 * @param width width of rectangle.
1113 * @param height height of rectangle.
1114 * @param align bit or'ed SWT flag like SWT.LEFT,RIGHT,CENTER,TOP,BOTTOM,VERTICAL used only for bigger rectangle
1115 * than visible area. By default CENTER/VERTICAL
1116 * @param forceAlign force alignment for rectangle smaller than the visible area
1117 */
1118 protected void ensureVisible(int xValue, int yValue, int width, int height, int align, boolean forceAlign) {
1119
1120 int localX = xValue;
1121 int localY = yValue;
1122 int localWidth = width;
1123 int localHeight = height;
1124
1125 if (localWidth < 0) {
1126 localX = localX + localWidth;
1127 localWidth = -localWidth;
1128 }
1129 if (localHeight < 0) {
1130 localY = localY + localHeight;
1131 localHeight = -localHeight;
1132 }
1133 int hbar = getHorizontalBarHeight();
1134 int vbar = getVerticalBarWidth();
1135 int cx = getContentsX();
1136 int cy = getContentsY();
1137 int right = getContentsX() + getVisibleWidth() - vbar;
1138 int bottom = getContentsY() + getVisibleHeight() - hbar;
1139 boolean align_h = false, align_v = false;
1140
1141 if (localX < getContentsX()) {
1142 cx = localX;
1143 } else if (localX + localWidth > right) {
1144 cx = localX - localWidth;
1145 }
1146 if (localY < getContentsY()) {
1147 cy = localY;
1148 } else if (localY + localHeight > bottom) {
1149 cy = localY - localHeight;
1150 }
1151
1152 if (localWidth > getVisibleWidth()) {
1153 align_h = true;
1154 }
1155 if (localHeight > getVisibleHeight()) {
1156 align_v = true;
1157 }
1158 // compute alignment on visible area horizontally
1159 if (align_h || (forceAlign && localX + localWidth > right)) {
1160 // use align flags
1161 if ((align & SWT.LEFT) != 0) {
1162 cx = localX;
1163 } else if ((align & SWT.RIGHT) != 0) {
1164 cx = right - localWidth;
1165 } else { // center
1166 cx = localX + (localWidth - getVisibleWidth()) / 2;
1167 }
1168 }
1169 // compute alignment on visible area vertically
1170 if (align_v || (forceAlign && localY + localHeight > bottom)) {
1171 // use align flags
1172 if ((align & SWT.TOP) != 0) {
1173 cy = localY;
1174 } else if ((align & SWT.BOTTOM) != 0) {
1175 cy = bottom - localHeight;
1176 } else { // center
1177 cy = localY + (localHeight - getVisibleHeight()) / 2;
1178 }
1179 }
1180 setContentsPos(cx, cy);
1181 }
1182
1183 /**
1184 * Returns true if point is visible (expressed in contents coordinates).
1185 *
1186 * @param px Point's x position
1187 * @param py Point's y position
1188 * @return true if point is visible (expressed in contents coordinates)
1189 */
1190 public boolean isVisible(int px, int py) {
1191 if (px < getContentsX()) {
1192 return false;
1193 }
1194 if (py < getContentsY()) {
1195 return false;
1196 }
1197 if (px > (getContentsX() + getVisibleWidth())) {
1198 return false;
1199 }
1200 if (py > (getContentsY() + getVisibleHeight())) {
1201 return false;
1202 }
1203 return true;
1204 }
1205
1206 /**
1207 * Returns true if rectangle if partially visible.
1208 *
1209 * @param xValue x contents coordinates of rectangle.
1210 * @param yValue y contents coordinates of rectangle.
1211 * @param width width of rectangle.
1212 * @param height height of rectangle.
1213 * @return true if rectangle if partially visible.
1214 */
1215 public boolean isVisible(int xValue, int yValue, int width, int height) {
1216 if (xValue + width < getContentsX()) {
1217 return false;
1218 }
1219 if (yValue + height < getContentsY()) {
1220 return false;
1221 }
1222 int vr = getContentsX() + getVisibleWidth();
1223 int vb = getContentsY() + getVisibleHeight();
1224 if (xValue > vr) {
1225 return false;
1226 }
1227 if (yValue > vb) {
1228 return false;
1229 }
1230 return true;
1231 }
1232
1233 /**
1234 * Returns visible part of rectangle, or null if rectangle is not visible.
1235 * Rectangle is expressed in contents coordinates.
1236 *
1237 * @param xValue
1238 * x contents coordinates of rectangle.
1239 * @param yValue
1240 * y contents coordinates of rectangle.
1241 * @param width
1242 * width of rectangle.
1243 * @param height
1244 * height of rectangle.
1245 * @return visible part of rectangle, or null if rectangle is not visible.
1246 */
1247 public Rectangle getVisiblePart(int xValue, int yValue, int width, int height) {
1248 if (xValue + width < getContentsX()) {
1249 return null;
1250 }
1251 if (yValue + height < getContentsY()) {
1252 return null;
1253 }
1254 int vr = getContentsX() + getVisibleWidth();
1255 int vb = getContentsY() + getVisibleHeight();
1256 if (xValue > vr) {
1257 return null;
1258 }
1259 if (yValue > vb) {
1260 return null;
1261 }
1262 int rr = xValue + width, rb = yValue + height;
1263 int nl = Math.max(xValue, getContentsX()), nt = Math.max(yValue, getContentsY()), nr = Math.min(rr, vr), nb = Math.min(rb, vb);
1264 return new Rectangle(nl, nt, nr - nl, nb - nt);
1265 }
1266
1267 /**
1268 * Returns the visible part for given rectangle.
1269 *
1270 * @param rect A rectangle
1271 *
1272 * @return gets visible part of rectangle (or <code>null</code>)
1273 */
1274 public final Rectangle getVisiblePart(Rectangle rect) {
1275 if (rect == null) {
1276 return null;
1277 }
1278 return getVisiblePart(rect.x, rect.y, rect.width, rect.height);
1279 }
1280
1281 /**
1282 * Change top left position of visible area. Check if the given point is inside contents area.
1283 *
1284 * @param xValue x contents coordinates of visible area.
1285 * @param yValue y contents coordinates of visible area.
1286 * @return true if view really moves
1287 */
1288 public boolean setContentsPos(int xValue, int yValue) {
1289 int nx = xValue, ny = yValue;
1290 if (getVisibleWidth() >= getContentsWidth()) {
1291 nx = 0;
1292 } else {
1293 if (xValue < 0) {
1294 nx = 0;
1295 } else if (xValue + getVisibleWidth() > getContentsWidth()) {
1296 nx = getContentsWidth() - getVisibleWidth();
1297 }
1298 }
1299 if (getVisibleHeight() >= getContentsHeight()) {
1300 ny = 0;
1301 } else {
1302 if (yValue <= 0) {
1303 ny = 0;
1304 } else if (yValue + getVisibleHeight() > getContentsHeight()) {
1305 ny = getContentsHeight() - getVisibleHeight();
1306 }
1307 }
1308 // no move
1309 if (nx == fContentsX && ny == fContentsY) {
1310 return false;
1311 }
1312 fContentsX = nx;
1313 fContentsY = ny;
1314 updateScrollBarsValues();
1315 // ? find smallest area to redraw only them ?
1316 fViewControl.redraw();
1317 return true;
1318 }
1319
1320 // redefined to return our vertical bar
1321 /*
1322 * (non-Javadoc)
1323 * @see org.eclipse.swt.widgets.Scrollable#getVerticalBar()
1324 */
1325 @Override
1326 public ScrollBar getVerticalBar() {
1327 return fVertScrollBar.getVerticalBar();
1328 }
1329
1330 // redefined to return out horizontal bar
1331 /*
1332 * (non-Javadoc)
1333 * @see org.eclipse.swt.widgets.Scrollable#getHorizontalBar()
1334 */
1335 @Override
1336 public ScrollBar getHorizontalBar() {
1337 return fHorScrollBar.getHorizontalBar();
1338 }
1339
1340 /**
1341 * Compute visibility of vertical/horizontal bar using given width/height and current visibility (i.e. is bar size are already in
1342 * for_xxx)
1343 * @param forWidth width of foreground
1344 * @param forHeight height of foreground
1345 * @param currHorVis The current visibility state of horizontal scroll bar
1346 * @param currVertvis The current visibility state of vertical scroll bar
1347 * @return <code>true</code> if visibility changed else <code>false</code>
1348 */
1349 public int computeBarVisibility(int forWidth, int forHeight, boolean currHorVis, boolean currVertvis) {
1350
1351 int localForWidth = forWidth;
1352 int vis = 0x00;
1353 switch (fVertScrollbarMode) {
1354 case ALWAYS_OFF:
1355 break;
1356 case ALWAYS_ON:
1357 vis |= VBAR;
1358 break;
1359 case AUTO:
1360 if (getContentsHeight() > forHeight) {
1361 vis = VBAR;
1362 // v bar size is already in for_width.
1363 if (!currVertvis) {// (curr_vis&0x01)==0)
1364 localForWidth -= getVerticalBarWidth();
1365 }
1366 }
1367 break;
1368 default:
1369 break;
1370 }
1371
1372 switch (fHorScrollbarMode) {
1373 case ALWAYS_OFF:
1374 break;
1375 case ALWAYS_ON:
1376 vis |= HBAR;
1377 break;
1378 case AUTO:
1379 if (getContentsWidth() > localForWidth) {
1380 vis |= HBAR;
1381 // h bar is not in for_height
1382 if ((!currHorVis) && (getContentsHeight() > (forHeight - getHorizontalBarHeight()))) {// (curr_vis&0x02)==0 )
1383 vis |= VBAR;
1384 }
1385 }
1386 break;
1387 default:
1388 break;
1389 }
1390 return vis;
1391 }
1392
1393 /**
1394 * Setup scroll bars visibility.
1395 *
1396 * @return True if one of visibility changed.
1397 */
1398 protected boolean updateScrollBarVisiblity() {
1399 boolean change = false;
1400
1401 boolean currVertVis = fVertScrollBar.getVisible();
1402 boolean currHorVis = fHorScrollBar.getVisible();
1403 int barNewVis = computeBarVisibility(getVisibleWidth(), getVisibleHeight(), currHorVis, currVertVis);
1404 boolean newVertVis = (barNewVis & VBAR) != 0;
1405 boolean newHorVis = (barNewVis & HBAR) != 0;
1406 if (currVertVis ^ newVertVis) { // vertsb_.getVisible() )
1407 fVertScrollBar.setVisible(newVertVis);
1408 change = true;
1409 }
1410 if (currHorVis ^ newHorVis) {
1411 fHorScrollBar.setVisible(newHorVis);
1412 change = true;
1413 }
1414
1415 // update corner control visibility:
1416 if (fCornerControl != null && change) {
1417 boolean vis = newVertVis || newHorVis;
1418 if (vis ^ fCornerControl.getVisible()) {
1419 fCornerControl.setVisible(vis);
1420 change = true; // but must be already the case
1421 }
1422 }
1423 return change;
1424 }
1425
1426 /**
1427 * Setup scroll bar using contents, visible and scroll bar mode properties.
1428 */
1429 protected void updateScrollBarsValues() {
1430 /* update vertical scrollbar */
1431 ScrollBar b = getVerticalBar();
1432 if (b != null) {
1433 b.setMinimum(0);
1434 b.setMaximum(getContentsHeight());
1435 b.setThumb(getVisibleHeight());
1436 b.setPageIncrement(getVisibleHeight());
1437 b.setIncrement(fVertScrollbarIncrement);
1438 b.setSelection(getContentsY());
1439 }
1440
1441 // update "hidden" vertical bar too
1442 b = fViewControl.getVerticalBar();
1443 if (b != null) {
1444 b.setMinimum(0);
1445 b.setMaximum(getContentsHeight());
1446 b.setThumb(getVisibleHeight());
1447 b.setPageIncrement(getVisibleHeight());
1448 b.setIncrement(fVertScrollbarIncrement);
1449 b.setSelection(getContentsY());
1450 }
1451
1452 /* update horizontal scrollbar */
1453 b = getHorizontalBar();
1454 if (b != null) {
1455 b.setMinimum(0);
1456 b.setMaximum(getContentsWidth());
1457 b.setThumb(getVisibleWidth());
1458 b.setSelection(getContentsX());
1459 b.setPageIncrement(getVisibleWidth());
1460 b.setIncrement(fHorScrollbarIncrement);
1461 }
1462 // update "hidden" horizontal bar too
1463 b = fViewControl.getHorizontalBar();
1464 if (b != null) {
1465 b.setMinimum(0);
1466 b.setMaximum(getContentsWidth());
1467 b.setThumb(getVisibleWidth());
1468 b.setSelection(getContentsX());
1469 b.setPageIncrement(getVisibleWidth());
1470 b.setIncrement(fHorScrollbarIncrement);
1471 }
1472 }
1473
1474 /**
1475 * Change the control used in the bottom right corner (between two scrollbar), if control is null reset previous
1476 * corner control. This control is visible only if at least one scrollbar is visible. Given control will be disposed
1477 * by ScrollView, at dispose() time, at next setCornetControl() call or when calling setOverviewEnabled(). Pay
1478 * attention calling this reset overview feature until setOverviewEnabled(true) if called.
1479 * @param control The control for the overview
1480 */
1481 public void setCornerControl(Control control) {
1482 if (fCornerControl != null) {
1483 fCornerControl.dispose();
1484 }
1485 fCornerControl = control;
1486 if (fCornerControl != null) {
1487 ScrollBar vb = getVerticalBar();
1488 ScrollBar hb = getHorizontalBar();
1489 boolean vis = vb.getVisible() || hb.getVisible();
1490 fCornerControl.setVisible(vis);
1491 }
1492 }
1493
1494 /**
1495 * Transform (x,y) point in widget coordinates to contents coordinates.
1496 *
1497 * @param x The x widget coordinate.
1498 * @param y The y widget coordinate.
1499 * @return org.eclipse.swt.graphics.Point with content coordinates.
1500 */
1501 public final Point viewToContents(int x, int y) {
1502 return new Point(viewToContentsX(x), viewToContentsY(y));
1503 }
1504
1505 /**
1506 * Transform x in widget coordinates to contents coordinates
1507 *
1508 * @param x The y widget coordinate.
1509 * @return the x content coordinate.
1510 */
1511 public int viewToContentsX(int x) {
1512 return fContentsX + x;
1513 }
1514
1515 /**
1516 * Transform y in widget coordinates to contents coordinates
1517 *
1518 * @param y The y widget coordinate.
1519 * @return the y content coordinate.
1520 */
1521 public int viewToContentsY(int y) {
1522 return fContentsY + y;
1523 }
1524
1525 /**
1526 * Transform (x,y) point from contents coordinates, to widget coordinates.
1527 *
1528 * @param x The x content coordinate.
1529 * @param y The y content coordinate.
1530 * @return coordinates widget area as.
1531 */
1532 public final Point contentsToView(int x, int y) {
1533 return new Point(contentsToViewX(x), contentsToViewY(y));
1534 }
1535
1536 /**
1537 * Transform X axis coordinates from contents to widgets.
1538 *
1539 * @param x contents coordinate to transform.
1540 * @return x coordinate in widget area
1541 */
1542 public int contentsToViewX(int x) {
1543 return x - fContentsX;
1544 }
1545
1546 /**
1547 * Transform Y axis coordinates from contents to widgets.
1548 *
1549 * @param y contents coordinate to transform
1550 * @return y coordinate in widget area
1551 */
1552 public int contentsToViewY(int y) {
1553 return y - fContentsY;
1554 }
1555
1556 /**
1557 * Return the visible height of scroll view, might be > contentsHeight
1558 *
1559 * @return the visible height of scroll view, might be > contentsHeight()
1560 */
1561 public int getVisibleHeight() {
1562 return fViewControl.getClientArea().height;
1563 }
1564
1565 /**
1566 * Return int the visible width of scroll view, might be > contentsWidth().
1567 *
1568 * @return int the visible width of scroll view, might be > contentsWidth()
1569 */
1570 public int getVisibleWidth() {
1571 return fViewControl.getClientArea().width;
1572 }
1573
1574 /**
1575 * Add support for arrow key, scroll the ... scroll view. But you can
1576 * redefine this method for your convenience.
1577 *
1578 * @param event
1579 * Keyboard event
1580 */
1581 protected void keyPressedEvent(KeyEvent event) {
1582 switch (event.keyCode) {
1583 case SWT.ARROW_UP:
1584 scrollBy(0, -getVisibleHeight());
1585 break;
1586 case SWT.ARROW_DOWN:
1587 scrollBy(0, +getVisibleHeight());
1588 break;
1589 case SWT.ARROW_LEFT:
1590 scrollBy(-getVisibleWidth(), 0);
1591 break;
1592 case SWT.ARROW_RIGHT:
1593 scrollBy(+getVisibleWidth(), 0);
1594 break;
1595 default:
1596 break;
1597 }
1598 }
1599
1600 /**
1601 * Redefine this method at your convenience
1602 *
1603 * @param event The key event.
1604 */
1605 protected void keyReleasedEvent(KeyEvent event) {
1606 }
1607
1608 /**
1609 * Returns vertical bar width, even if bar isn't visible.
1610 *
1611 * @return vertical bar width, even if bar isn't visible
1612 */
1613 public int getVerticalBarWidth() {
1614 // include vertical bar width and trimming of scrollable used
1615 int bw = fVertScrollBar.computeTrim(0, 0, 0, 0).width;
1616 return bw + 1;
1617 }
1618
1619 /**
1620 * Returns horizontal bar height even if bar isn't visible.
1621 *
1622 * @return horizontal bar height even if bar isn't visible
1623 */
1624 public int getHorizontalBarHeight() {
1625 // include horiz. bar height and trimming of scrollable used
1626 int bh = fHorScrollBar.computeTrim(0, 0, 0, 0).height;
1627 // +1 because win32 H.bar need 1 pixel canvas size to appear ! (strange no ?)
1628 return bh + 1;
1629 }
1630
1631 /*
1632 * (non-Javadoc)
1633 * @see org.eclipse.swt.widgets.Scrollable#computeTrim(int, int, int, int)
1634 */
1635 @Override
1636 public Rectangle computeTrim(int x, int y, int w, int h) {
1637 Rectangle r = new Rectangle(x, y, w, h);
1638 int bar_vis = computeBarVisibility(w, h, false, false);
1639 if ((bar_vis & VBAR) != 0) {
1640 r.width += getVerticalBarWidth();
1641 }
1642 if ((bar_vis & HBAR) != 0) {
1643 r.height += getHorizontalBarHeight();
1644 }
1645 return r;
1646 }
1647
1648 /**
1649 * Internal layout for ScrollView, handle scrollbars, drawzone and corner control
1650 */
1651 protected class SVLayout extends Layout {
1652 /**
1653 * The seek value
1654 */
1655 int seek = 0;
1656 /**
1657 * The do-it-not flag
1658 */
1659 boolean dontLayout = false;
1660
1661 /*
1662 * (non-Javadoc)
1663 * @see org.eclipse.swt.widgets.Layout#computeSize(org.eclipse.swt.widgets.Composite, int, int, boolean)
1664 */
1665 @Override
1666 protected Point computeSize(Composite composite, int wHint, int hHint, boolean flushCache) {
1667 Point p = new Point(250, 250);
1668 if (fContentsWidth < p.x) {
1669 p.x = fContentsWidth;
1670 }
1671 if (fContentsHeight < p.y) {
1672 p.y = fContentsHeight;
1673 }
1674 return p;
1675 }
1676
1677 /*
1678 * (non-Javadoc)
1679 * @see org.eclipse.swt.widgets.Layout#layout(org.eclipse.swt.widgets.Composite, boolean)
1680 */
1681 @Override
1682 protected void layout(Composite composite, boolean flushCache) {
1683 if (dontLayout) {
1684 return;
1685 }
1686 seek++;
1687 if (seek > 10) {
1688 dontLayout = true;
1689 }
1690
1691 Point cs = composite.getSize();
1692 int bar_vis = computeBarVisibility(cs.x, cs.y, false, false);
1693 boolean vb_vis = (bar_vis & VBAR) != 0;
1694 boolean hb_vis = (bar_vis & HBAR) != 0;
1695 fVertScrollBar.setVisible(vb_vis);
1696 fHorScrollBar.setVisible(hb_vis);
1697 int vbw = getVerticalBarWidth();
1698 int hbh = getHorizontalBarHeight();
1699 int wb = vb_vis ? vbw : 0;
1700 int hb = hb_vis ? hbh : 0;
1701 int cww = 0, cwh = 0;
1702
1703 if (fCornerControl != null && (vb_vis || hb_vis)) { // corner_control_.getVisible())
1704 fCornerControl.setVisible(true);
1705 cww = vbw;
1706 cwh = hbh;
1707 if (wb == 0) {
1708 wb = vbw;
1709 }
1710 if (hb == 0) {
1711 hb = hbh;
1712 }
1713 } else if (vb_vis && hb_vis) {
1714 if (fCornerControl != null) {
1715 fCornerControl.setVisible(false);
1716 }
1717 cww = vbw;
1718 cwh = hbh;
1719 }
1720 if (vb_vis || hb_vis) {
1721 updateScrollBarsValues();
1722 }
1723
1724 int vw = cs.x - (vb_vis ? vbw : 0);
1725 int vh = cs.y - (hb_vis ? hbh : 0);
1726 int vbx = cs.x - wb;
1727 int hby = cs.y - hb;
1728
1729 fViewControl.setBounds(0, 0, vw, vh);
1730
1731 if (vb_vis) {
1732 fVertScrollBar.setBounds(vbx, 0, wb, cs.y - cwh);
1733 }
1734 if (hb_vis) {
1735 fHorScrollBar.setBounds(0, hby, cs.x - cww, hb);
1736 }
1737 if (fCornerControl != null && fCornerControl.getVisible()) {
1738 fCornerControl.setBounds(vbx, hby, vbw, hbh);
1739 }
1740 updateScrollBarsValues();
1741
1742 seek--;
1743 if (seek == 0) {
1744 dontLayout = false;
1745 }
1746 }
1747 }
1748
1749 // static must take place here... cursor is created once.
1750 volatile static Cursor fOverviewCursor;
1751
1752 /** Support for click-and-see overview shell on this ScrollView */
1753 protected class Overview {
1754
1755 /**
1756 * factor for X from real and overview sizes, for mouse move speed.
1757 */
1758 protected float fOverviewFactorX;
1759
1760 /**
1761 * factor for Y from real and overview sizes, for mouse move speed.
1762 */
1763 protected float fOverviewFactorY;
1764 /**
1765 * shell use to show overview
1766 */
1767 protected Shell fOverview;
1768 /**
1769 * save mouse X cursor location for disappear();
1770 */
1771 protected int fSaveCursorX;
1772 /**
1773 * save mouse Y cursor location for disappear();
1774 */
1775 protected int fSaveCursorY;
1776
1777 /**
1778 * Apply overview support on a control. Replace existing corner_widget
1779 *
1780 * @param control
1781 * The control to use
1782 */
1783 public void useControl(Control control) {
1784 final Point pos = control.getLocation();
1785 control.addMouseListener(new MouseListener() {
1786 @Override
1787 public void mouseDoubleClick(MouseEvent e) {
1788 }
1789
1790 @Override
1791 public void mouseDown(MouseEvent e) {
1792 overviewAppear(e.x, e.y);
1793 }
1794
1795 @Override
1796 public void mouseUp(MouseEvent e) {
1797 overviewDisappear();
1798 }
1799 });
1800
1801 control.addFocusListener(new FocusListener() {
1802
1803 @Override
1804 public void focusGained(FocusEvent e) {
1805 }
1806
1807 @Override
1808 public void focusLost(FocusEvent e) {
1809 if (overviewing()) {
1810 overviewDisappear(false);
1811 }
1812 }
1813
1814 });
1815 control.addKeyListener(new KeyListener() {
1816
1817 @Override
1818 public void keyPressed(KeyEvent event) {
1819 if (event.keyCode == 32 && !overviewing()) {
1820 overviewAppear(pos.x, pos.y);
1821 } else if (event.keyCode == 32) {
1822 overviewDisappear();
1823 }
1824 if (event.keyCode == SWT.ARROW_DOWN) {
1825 overviewMove(0, 1, event);
1826 }
1827
1828 if (event.keyCode == SWT.ARROW_UP) {
1829 overviewMove(0, -1, event);
1830 }
1831
1832 if (event.keyCode == SWT.ARROW_RIGHT) {
1833 overviewMove(1, 0, event);
1834 }
1835
1836 if (event.keyCode == SWT.ARROW_LEFT) {
1837 overviewMove(-1, 0, event);
1838 }
1839 }
1840
1841 @Override
1842 public void keyReleased(KeyEvent e) {
1843 }
1844 });
1845 control.addMouseMoveListener(new MouseMoveListener() {
1846 private int refReshCount = 0;
1847 @Override
1848 public void mouseMove(MouseEvent event) {
1849 if (overviewing()) {
1850 // Slow down the refresh
1851 if (refReshCount % 4 == 0) {
1852 overviewMove(event);
1853 }
1854 refReshCount++;
1855 }
1856 }
1857 });
1858 }
1859
1860 /**
1861 * Dispose controls of overview
1862 */
1863 public void dispose() {
1864 if (fOverview != null) {
1865 fOverview.dispose();
1866 }
1867 }
1868
1869 /**
1870 * @return true if overview is currently on screen
1871 */
1872 protected boolean overviewing() {
1873 return (fOverview != null && fOverview.isVisible());
1874 }
1875
1876 /**
1877 * Process overview appear
1878 *
1879 * @param mx
1880 * X coordinate
1881 * @param my
1882 * Y coordinate
1883 */
1884 protected void overviewAppear(int mx, int my) {
1885 if (fOverview == null) {
1886 fOverview = new Shell(getShell(), SWT.ON_TOP | SWT.NO_BACKGROUND);
1887 fOverview.addPaintListener(new PaintListener() {
1888 @Override
1889 public void paintControl(PaintEvent e) {
1890 drawOverview(e.gc, fOverview.getClientArea());
1891 }
1892 });
1893 }
1894 // always the same..
1895 // overview.setBackground( viewcontrol_.getBackground() );
1896 fOverview.setForeground(fViewControl.getForeground());
1897
1898 // get location of shell (in screeen coordinates)
1899 Point p = toGlobalCoordinates(fCornerControl, 0, 0);
1900 int x = p.x;
1901 int y = p.y;
1902 int w, h;
1903 w = h = fOverviewSize;
1904 Rectangle scr = getDisplay().getBounds();
1905 Point ccs = fCornerControl.getSize();
1906 try {
1907 if (fContentsWidth > fContentsHeight) {
1908 float ratio = fContentsHeight / (float) fContentsWidth;
1909 h = (int) (w * ratio);
1910 if (h < ccs.y) {
1911 h = ccs.y;
1912 } else if (h >= scr.height / 2) {
1913 h = scr.height / 2;
1914 }
1915 } else {
1916 float ratio = fContentsWidth / (float) fContentsHeight;
1917 w = (int) (h * ratio);
1918 if (w < ccs.x) {
1919 w = ccs.x;
1920 } else if (w >= scr.width / 2) {
1921 w = scr.width / 2;
1922 }
1923 }
1924 fOverviewFactorX = fContentsWidth / (float) w;
1925 fOverviewFactorY = fContentsHeight / (float) h;
1926 }
1927 // no contents size set ?
1928 catch (java.lang.ArithmeticException e) {
1929 }
1930
1931 // try pop-up on button, extending to bottom right,
1932 // if outside screen, extend pop-up to top left
1933 // if( x+w > scr.width ) x = scr.width-w; //x += corner_control_.getSize().x-w;
1934 // if( y+h > scr.height ) y = scr.height-h;//y += corner_control_.getSize().y-h;
1935 if (x <= 0) {
1936 x = 1;
1937 }
1938 if (y <= 0) {
1939 y = 1;
1940 }
1941 x = x - w + ccs.x;
1942 y = y - h + ccs.y;
1943 fOverview.setBounds(x, y, w, h);
1944 fOverview.setVisible(true);
1945 fOverview.redraw();
1946 // mouse cursor disappear, so set invisible mouse cursor ...
1947 if (fOverviewCursor == null) {
1948 RGB rgb[] = { new RGB(0, 0, 0), new RGB(255, 0, 0) };
1949 PaletteData palette = new PaletteData(rgb);
1950 int s = 1;
1951 byte src[] = new byte[s * s];
1952 byte msk[] = new byte[s * s];
1953 for (int i = 0; i < s * s; ++i) {
1954 src[i] = (byte) 0xFF;
1955 }
1956 ImageData i_src = new ImageData(s, s, 1, palette, 1, src);
1957 ImageData i_msk = new ImageData(s, s, 1, palette, 1, msk);
1958 fOverviewCursor = new Cursor(null, i_src, i_msk, 0, 0);
1959 }
1960 fCornerControl.setCursor(fOverviewCursor);
1961 // convert to global coordinates
1962 p = toGlobalCoordinates(fCornerControl, mx, my);
1963 fSaveCursorX = p.x;
1964 fSaveCursorY = p.y;
1965
1966 Rectangle r = fOverview.getClientArea();
1967 int cx = (int) (r.width * fContentsX / (float) fContentsWidth);
1968 int cy = (int) (r.height * fContentsY / (float) fContentsHeight);
1969
1970 // cx,cy to display's global coordinates
1971 p = toGlobalCoordinates(fOverview.getParent(), cx, cy);
1972 }
1973
1974 /**
1975 * Process disappear of overview
1976 */
1977 protected void overviewDisappear() {
1978 overviewDisappear(true);
1979 }
1980
1981 /**
1982 * Process disappear of overview
1983 * @param restoreCursorLoc A flag to restore cursor location
1984 */
1985 protected void overviewDisappear(boolean restoreCursorLoc) {
1986 if (fOverview == null) {
1987 return;
1988 }
1989 fOverview.setVisible(false);
1990 fCornerControl.setCursor(null);
1991 if (restoreCursorLoc) {
1992 getDisplay().setCursorLocation(fSaveCursorX, fSaveCursorY);
1993 }
1994 fOverview.dispose();
1995 fOverview = null;
1996 }
1997
1998 /**
1999 * Process mouse move in overview
2000 * @param event The mouse event
2001 */
2002 protected void overviewMove(MouseEvent event) {
2003 Point p = toGlobalCoordinates(fCornerControl, event.x, event.y);
2004 int dx = p.x - fSaveCursorX;
2005 int dy = p.y - fSaveCursorY;
2006 overviewMove(dx, dy, event);
2007 }
2008
2009 /**
2010 * Process mouse move event when overviewing
2011 *
2012 * @param dx The x coordinates delta
2013 * @param dy The y coordinates delta
2014 * @param event The typed event
2015 */
2016 protected void overviewMove(int dx, int dy, TypedEvent event) {
2017 boolean ctrl = false;
2018 boolean shift = false;
2019
2020 if (event instanceof MouseEvent) {
2021 MouseEvent e = (MouseEvent) event;
2022 getDisplay().setCursorLocation(fSaveCursorX, fSaveCursorY);
2023 ctrl = (e.stateMask & SWT.CONTROL) != 0;
2024 shift = (e.stateMask & SWT.SHIFT) != 0;
2025 } else if (event instanceof KeyEvent) {
2026 KeyEvent e = (KeyEvent) event;
2027 ctrl = (e.stateMask & SWT.CONTROL) != 0;
2028 shift = (e.stateMask & SWT.SHIFT) != 0;
2029 }
2030
2031 int cx = fContentsX;
2032 int cy = fContentsY;
2033 float fx = fOverviewFactorX;
2034 float fy = fOverviewFactorY;
2035
2036 if (ctrl && shift) {
2037 if ((fx * 0.25f > 1) && (fy * 0.25 > 1)) {
2038 fx = fy = 1.0f;
2039 } else {
2040 fx *= 0.1f;
2041 fy *= 0.1f;
2042 }
2043 } else if (ctrl) {
2044 fx *= 0.5f;
2045 fy *= 0.5f;
2046 } else if (shift) {
2047 fx *= 0.5f;
2048 fy *= 0.5f;
2049 }
2050 scrollBy((int) (fx * dx), (int) (fy * dy));
2051 if (cx != fContentsX || cy != fContentsY) {
2052 fOverview.redraw();
2053 fOverview.update(); // draw now !
2054 }
2055 }
2056
2057 /**
2058 * Convert overview coordinates to global coordinates.
2059 *
2060 * @param loc
2061 * the control reference
2062 * @param x
2063 * The x coordinate to convert
2064 * @param y
2065 * The y coordinate to convert
2066 * @return The new converted Point
2067 */
2068 protected Point toGlobalCoordinates(Control loc, int x, int y) {
2069 Point p = new Point(x, y);
2070 for (Control c = loc; c != null; c = c.getParent()) {
2071 // control might have client area with 'decorations'
2072 int trim_x = 0, trim_y = 0;
2073 // other kind of widget with trimming ??
2074 if (c instanceof Scrollable) {
2075 Scrollable s = (Scrollable) c;
2076 Rectangle rr = s.getClientArea();
2077 Rectangle tr = s.computeTrim(rr.x, rr.y, rr.width, rr.height);
2078 trim_x = rr.x - tr.x;
2079 trim_y = rr.y - tr.y;
2080 }
2081 p.x += c.getLocation().x + trim_x;
2082 p.y += c.getLocation().y + trim_y;
2083 }
2084 return p;
2085 }
2086 }
2087 }
This page took 0.077387 seconds and 5 git commands to generate.