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