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