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