1 /*******************************************************************************
2  * Copyright (c) 2000, 2008 IBM Corporation and others.
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 Corporation - initial API and implementation
10  * Port to the D programming language:
11  *     Frank Benoit <benoit@tionex.de>
12  *******************************************************************************/
13 module org.eclipse.swt.custom.ScrolledComposite;
14 
15 import java.lang.all;
16 
17 
18 import org.eclipse.swt.SWT;
19 import org.eclipse.swt.SWTException;
20 import org.eclipse.swt.events.DisposeEvent;
21 import org.eclipse.swt.events.DisposeListener;
22 import org.eclipse.swt.graphics.Point;
23 import org.eclipse.swt.graphics.Rectangle;
24 import org.eclipse.swt.widgets.Composite;
25 import org.eclipse.swt.widgets.Control;
26 import org.eclipse.swt.widgets.Display;
27 import org.eclipse.swt.widgets.Event;
28 import org.eclipse.swt.widgets.Layout;
29 import org.eclipse.swt.widgets.Listener;
30 import org.eclipse.swt.widgets.ScrollBar;
31 import org.eclipse.swt.widgets.Shell;
32 import org.eclipse.swt.custom.ScrolledCompositeLayout;
33 
34 /**
35  * A ScrolledComposite provides scrollbars and will scroll its content when the user
36  * uses the scrollbars.
37  *
38  *
39  * <p>There are two ways to use the ScrolledComposite:
40  *
41  * <p>
42  * 1) Set the size of the control that is being scrolled and the ScrolledComposite
43  * will show scrollbars when the contained control can not be fully seen.
44  *
45  * 2) The second way imitates the way a browser would work.  Set the minimum size of
46  * the control and the ScrolledComposite will show scroll bars if the visible area is
47  * less than the minimum size of the control and it will expand the size of the control
48  * if the visible area is greater than the minimum size.  This requires invoking
49  * both setMinWidth(), setMinHeight() and setExpandHorizontal(), setExpandVertical().
50  *
51  * <code><pre>
52  * public static void main (String [] args) {
53  *      Display display = new Display ();
54  *      Color red = display.getSystemColor(SWT.COLOR_RED);
55  *      Color blue = display.getSystemColor(SWT.COLOR_BLUE);
56  *      Shell shell = new Shell (display);
57  *      shell.setLayout(new FillLayout());
58  *
59  *      // set the size of the scrolled content - method 1
60  *      final ScrolledComposite sc1 = new ScrolledComposite(shell, SWT.H_SCROLL | SWT.V_SCROLL | SWT.BORDER);
61  *      final Composite c1 = new Composite(sc1, SWT.NONE);
62  *      sc1.setContent(c1);
63  *      c1.setBackground(red);
64  *      GridLayout layout = new GridLayout();
65  *      layout.numColumns = 4;
66  *      c1.setLayout(layout);
67  *      Button b1 = new Button (c1, SWT.PUSH);
68  *      b1.setText("first button");
69  *      c1.setSize(c1.computeSize(SWT.DEFAULT, SWT.DEFAULT));
70  *
71  *      // set the minimum width and height of the scrolled content - method 2
72  *      final ScrolledComposite sc2 = new ScrolledComposite(shell, SWT.H_SCROLL | SWT.V_SCROLL | SWT.BORDER);
73  *      sc2.setExpandHorizontal(true);
74  *      sc2.setExpandVertical(true);
75  *      final Composite c2 = new Composite(sc2, SWT.NONE);
76  *      sc2.setContent(c2);
77  *      c2.setBackground(blue);
78  *      layout = new GridLayout();
79  *      layout.numColumns = 4;
80  *      c2.setLayout(layout);
81  *      Button b2 = new Button (c2, SWT.PUSH);
82  *      b2.setText("first button");
83  *      sc2.setMinSize(c2.computeSize(SWT.DEFAULT, SWT.DEFAULT));
84  *
85  *      Button add = new Button (shell, SWT.PUSH);
86  *      add.setText("add children");
87  *      final int[] index = new int[]{0};
88  *      add.addListener(SWT.Selection, new Listener() {
89  *          public void handleEvent(Event e) {
90  *              index[0]++;
91  *              Button button = new Button(c1, SWT.PUSH);
92  *              button.setText("button "+index[0]);
93  *              // reset size of content so children can be seen - method 1
94  *              c1.setSize(c1.computeSize(SWT.DEFAULT, SWT.DEFAULT));
95  *              c1.layout();
96  *
97  *              button = new Button(c2, SWT.PUSH);
98  *              button.setText("button "+index[0]);
99  *              // reset the minimum width and height so children can be seen - method 2
100  *              sc2.setMinSize(c2.computeSize(SWT.DEFAULT, SWT.DEFAULT));
101  *              c2.layout();
102  *          }
103  *      });
104  *
105  *      shell.open ();
106  *      while (!shell.isDisposed ()) {
107  *          if (!display.readAndDispatch ()) display.sleep ();
108  *      }
109  *      display.dispose ();
110  * }
111  * </pre></code>
112  *
113  * <dl>
114  * <dt><b>Styles:</b><dd>H_SCROLL, V_SCROLL
115  * </dl>
116  *
117  * @see <a href="http://www.eclipse.org/swt/snippets/#scrolledcomposite">ScrolledComposite snippets</a>
118  * @see <a href="http://www.eclipse.org/swt/">Sample code and further information</a>
119  */
120 public class ScrolledComposite : Composite {
121 
122     Control content;
123     Listener contentListener;
124     Listener filter;
125 
126     int minHeight = 0;
127     int minWidth = 0;
128     bool expandHorizontal = false;
129     bool expandVertical = false;
130     bool alwaysShowScroll = false;
131     bool showFocusedControl = false;
132 
133 /**
134  * Constructs a new instance of this class given its parent
135  * and a style value describing its behavior and appearance.
136  * <p>
137  * The style value is either one of the style constants defined in
138  * class <code>SWT</code> which is applicable to instances of this
139  * class, or must be built by <em>bitwise OR</em>'ing together
140  * (that is, using the <code>int</code> "|" operator) two or more
141  * of those <code>SWT</code> style constants. The class description
142  * lists the style constants that are applicable to the class.
143  * Style bits are also inherited from superclasses.
144  * </p>
145  *
146  * @param parent a widget which will be the parent of the new instance (cannot be null)
147  * @param style the style of widget to construct
148  *
149  * @exception IllegalArgumentException <ul>
150  *    <li>ERROR_NULL_ARGUMENT - if the parent is null</li>
151  * </ul>
152  * @exception SWTException <ul>
153  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the parent</li>
154  * </ul>
155  *
156  * @see SWT#H_SCROLL
157  * @see SWT#V_SCROLL
158  * @see #getStyle()
159  */
160 public this(Composite parent, int style) {
161     super(parent, checkStyle(style));
162     super.setLayout(new ScrolledCompositeLayout());
163     ScrollBar hBar = getHorizontalBar ();
164     if (hBar !is null) {
165         hBar.setVisible(false);
166         hBar.addListener (SWT.Selection, new class() Listener  {
167             public void handleEvent (Event e) {
168                 hScroll();
169             }
170         });
171     }
172 
173     ScrollBar vBar = getVerticalBar ();
174     if (vBar !is null) {
175         vBar.setVisible(false);
176         vBar.addListener (SWT.Selection, new class() Listener {
177             public void handleEvent (Event e) {
178                 vScroll();
179             }
180         });
181     }
182 
183     contentListener = new class() Listener {
184         public void handleEvent(Event e) {
185             if (e.type !is SWT.Resize) return;
186             layout(false);
187         }
188     };
189 
190     filter = new class() Listener {
191         public void handleEvent(Event event) {
192             if (auto control = cast(Control)event.widget ) {
193                 if (contains(control)) showControl(control);
194             }
195         }
196     };
197 
198     addDisposeListener(new class() DisposeListener {
199         public void widgetDisposed(DisposeEvent e) {
200             getDisplay().removeFilter(SWT.FocusIn, filter);
201         }
202     });
203 }
204 
205 static int checkStyle (int style) {
206     int mask = SWT.H_SCROLL | SWT.V_SCROLL | SWT.BORDER | SWT.LEFT_TO_RIGHT | SWT.RIGHT_TO_LEFT;
207     return style & mask;
208 }
209 
210 bool contains(Control control) {
211     if (control is null || control.isDisposed()) return false;
212 
213     Composite parent = control.getParent();
214     while (parent !is null && !( null !is cast(Shell)parent )) {
215         if (this is parent) return true;
216         parent = parent.getParent();
217     }
218     return false;
219 }
220 
221 /**
222  * Returns the Always Show Scrollbars flag.  True if the scrollbars are
223  * always shown even if they are not required.  False if the scrollbars are only
224  * visible when some part of the composite needs to be scrolled to be seen.
225  * The H_SCROLL and V_SCROLL style bits are also required to enable scrollbars in the
226  * horizontal and vertical directions.
227  *
228  * @return the Always Show Scrollbars flag value
229  */
230 public bool getAlwaysShowScrollBars() {
231     //checkWidget();
232     return alwaysShowScroll;
233 }
234 
235 /**
236  * Returns <code>true</code> if the content control
237  * will be expanded to fill available horizontal space.
238  *
239  * @return the receiver's horizontal expansion state
240  *
241  * @exception SWTException <ul>
242  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
243  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
244  * </ul>
245  *
246  * @since 3.2
247  */
248 public bool getExpandHorizontal() {
249     checkWidget();
250     return expandHorizontal;
251 }
252 
253 /**
254  * Returns <code>true</code> if the content control
255  * will be expanded to fill available vertical space.
256  *
257  * @return the receiver's vertical expansion state
258  *
259  * @exception SWTException <ul>
260  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
261  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
262  * </ul>
263  *
264  * @since 3.2
265  */
266 public bool getExpandVertical() {
267     checkWidget();
268     return expandVertical;
269 }
270 
271 /**
272  * Returns the minimum width of the content control.
273  *
274  * @return the minimum width
275  *
276  * @exception SWTException <ul>
277  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
278  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
279  * </ul>
280  *
281  * @since 3.2
282  */
283 public int getMinWidth() {
284     checkWidget();
285     return minWidth;
286 }
287 
288 /**
289  * Returns the minimum height of the content control.
290  *
291  * @return the minimum height
292  *
293  * @exception SWTException <ul>
294  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
295  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
296  * </ul>
297  *
298  * @since 3.2
299  */
300 public int getMinHeight() {
301     checkWidget();
302     return minHeight;
303 }
304 
305 /**
306  * Get the content that is being scrolled.
307  *
308  * @return the control displayed in the content area
309  */
310 public Control getContent() {
311     //checkWidget();
312     return content;
313 }
314 
315 /**
316  * Returns <code>true</code> if the receiver automatically scrolls to a focused child control
317  * to make it visible. Otherwise, returns <code>false</code>.
318  *
319  * @return a bool indicating whether focused child controls are automatically scrolled into the viewport
320  *
321  * @exception SWTException <ul>
322  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
323  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
324  * </ul>
325  *
326  * @since 3.4
327  */
328 public bool getShowFocusedControl() {
329     checkWidget();
330     return showFocusedControl;
331 }
332 
333 void hScroll() {
334     if (content is null) return;
335     Point location = content.getLocation ();
336     ScrollBar hBar = getHorizontalBar ();
337     int hSelection = hBar.getSelection ();
338     content.setLocation (-hSelection, location.y);
339 }
340 bool needHScroll(Rectangle contentRect, bool vVisible) {
341     ScrollBar hBar = getHorizontalBar();
342     if (hBar is null) return false;
343 
344     Rectangle hostRect = getBounds();
345     int border = getBorderWidth();
346     hostRect.width -= 2*border;
347     ScrollBar vBar = getVerticalBar();
348     if (vVisible && vBar !is null) hostRect.width -= vBar.getSize().x;
349 
350     if (!expandHorizontal && contentRect.width > hostRect.width) return true;
351     if (expandHorizontal && minWidth > hostRect.width) return true;
352     return false;
353 }
354 
355 bool needVScroll(Rectangle contentRect, bool hVisible) {
356     ScrollBar vBar = getVerticalBar();
357     if (vBar is null) return false;
358 
359     Rectangle hostRect = getBounds();
360     int border = getBorderWidth();
361     hostRect.height -= 2*border;
362     ScrollBar hBar = getHorizontalBar();
363     if (hVisible && hBar !is null) hostRect.height -= hBar.getSize().y;
364 
365     if (!expandVertical && contentRect.height > hostRect.height) return true;
366     if (expandVertical && minHeight > hostRect.height) return true;
367     return false;
368 }
369 
370 /**
371  * Return the point in the content that currently appears in the top left
372  * corner of the scrolled composite.
373  *
374  * @return the point in the content that currently appears in the top left
375  * corner of the scrolled composite.  If no content has been set, this returns
376  * (0, 0).
377  *
378  * @exception SWTException <ul>
379  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
380  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
381  * </ul>
382  *
383  * @since 2.0
384  */
385 public Point getOrigin() {
386     checkWidget();
387     if (content is null) return new Point(0, 0);
388     Point location = content.getLocation();
389     return new Point(-location.x, -location.y);
390 }
391 /**
392  * Scrolls the content so that the specified point in the content is in the top
393  * left corner.  If no content has been set, nothing will occur.
394  *
395  * Negative values will be ignored.  Values greater than the maximum scroll
396  * distance will result in scrolling to the end of the scrollbar.
397  *
398  * @param origin the point on the content to appear in the top left corner
399  *
400  * @exception SWTException <ul>
401  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
402  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
403  *    <li>ERROR_INVALID_ARGUMENT - value of origin is outside of content
404  * </ul>
405  * @since 2.0
406  */
407 public void setOrigin(Point origin) {
408     setOrigin(origin.x, origin.y);
409 }
410 /**
411  * Scrolls the content so that the specified point in the content is in the top
412  * left corner.  If no content has been set, nothing will occur.
413  *
414  * Negative values will be ignored.  Values greater than the maximum scroll
415  * distance will result in scrolling to the end of the scrollbar.
416  *
417  * @param x the x coordinate of the content to appear in the top left corner
418  *
419  * @param y the y coordinate of the content to appear in the top left corner
420  *
421  * @exception SWTException <ul>
422  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
423  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
424  * </ul>
425  *
426  * @since 2.0
427  */
428 public void setOrigin(int x, int y) {
429     checkWidget();
430     if (content is null) return;
431     ScrollBar hBar = getHorizontalBar ();
432     if (hBar !is null) {
433         hBar.setSelection(x);
434         x = -hBar.getSelection ();
435     } else {
436         x = 0;
437     }
438     ScrollBar vBar = getVerticalBar ();
439     if (vBar !is null) {
440         vBar.setSelection(y);
441         y = -vBar.getSelection ();
442     } else {
443         y = 0;
444     }
445     content.setLocation(x, y);
446 }
447 /**
448  * Set the Always Show Scrollbars flag.  True if the scrollbars are
449  * always shown even if they are not required.  False if the scrollbars are only
450  * visible when some part of the composite needs to be scrolled to be seen.
451  * The H_SCROLL and V_SCROLL style bits are also required to enable scrollbars in the
452  * horizontal and vertical directions.
453  *
454  * @param show true to show the scrollbars even when not required, false to show scrollbars only when required
455  *
456  * @exception SWTException <ul>
457  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
458  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
459  * </ul>
460  */
461 public void setAlwaysShowScrollBars(bool show) {
462     checkWidget();
463     if (show is alwaysShowScroll) return;
464     alwaysShowScroll = show;
465     ScrollBar hBar = getHorizontalBar ();
466     if (hBar !is null && alwaysShowScroll) hBar.setVisible(true);
467     ScrollBar vBar = getVerticalBar ();
468     if (vBar !is null && alwaysShowScroll) vBar.setVisible(true);
469     layout(false);
470 }
471 
472 /**
473  * Set the content that will be scrolled.
474  *
475  * @param content the control to be displayed in the content area
476  *
477  * @exception SWTException <ul>
478  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
479  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
480  * </ul>
481  */
482 public void setContent(Control content) {
483     checkWidget();
484     if (this.content !is null && !this.content.isDisposed()) {
485         this.content.removeListener(SWT.Resize, contentListener);
486         this.content.setBounds(new Rectangle(-200, -200, 0, 0));
487     }
488 
489     this.content = content;
490     ScrollBar vBar = getVerticalBar ();
491     ScrollBar hBar = getHorizontalBar ();
492     if (this.content !is null) {
493         if (vBar !is null) {
494             vBar.setMaximum (0);
495             vBar.setThumb (0);
496             vBar.setSelection(0);
497         }
498         if (hBar !is null) {
499             hBar.setMaximum (0);
500             hBar.setThumb (0);
501             hBar.setSelection(0);
502         }
503         content.setLocation(0, 0);
504         layout(false);
505         this.content.addListener(SWT.Resize, contentListener);
506     } else {
507         if (hBar !is null) hBar.setVisible(alwaysShowScroll);
508         if (vBar !is null) vBar.setVisible(alwaysShowScroll);
509     }
510 }
511 /**
512  * Configure the ScrolledComposite to resize the content object to be as wide as the
513  * ScrolledComposite when the width of the ScrolledComposite is greater than the
514  * minimum width specified in setMinWidth.  If the ScrolledComposite is less than the
515  * minimum width, the content will not be resized and instead the horizontal scroll bar will be
516  * used to view the entire width.
517  * If expand is false, this behaviour is turned off.  By default, this behaviour is turned off.
518  *
519  * @param expand true to expand the content control to fill available horizontal space
520  *
521  * @exception SWTException <ul>
522  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
523  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
524  * </ul>
525  */
526 public void setExpandHorizontal(bool expand) {
527     checkWidget();
528     if (expand is expandHorizontal) return;
529     expandHorizontal = expand;
530     layout(false);
531 }
532 /**
533  * Configure the ScrolledComposite to resize the content object to be as tall as the
534  * ScrolledComposite when the height of the ScrolledComposite is greater than the
535  * minimum height specified in setMinHeight.  If the ScrolledComposite is less than the
536  * minimum height, the content will not be resized and instead the vertical scroll bar will be
537  * used to view the entire height.
538  * If expand is false, this behaviour is turned off.  By default, this behaviour is turned off.
539  *
540  * @param expand true to expand the content control to fill available vertical space
541  *
542  * @exception SWTException <ul>
543  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
544  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
545  * </ul>
546  */
547 public void setExpandVertical(bool expand) {
548     checkWidget();
549     if (expand is expandVertical) return;
550     expandVertical = expand;
551     layout(false);
552 }
553 /**
554  * Sets the layout which is associated with the receiver to be
555  * the argument which may be null.
556  * <p>
557  * Note: No Layout can be set on this Control because it already
558  * manages the size and position of its children.
559  * </p>
560  *
561  * @param layout the receiver's new layout or null
562  *
563  * @exception SWTException <ul>
564  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
565  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
566  * </ul>
567  */
568 public override void setLayout (Layout layout) {
569     checkWidget();
570     return;
571 }
572 /**
573  * Specify the minimum height at which the ScrolledComposite will begin scrolling the
574  * content with the vertical scroll bar.  This value is only relevant if
575  * setExpandVertical(true) has been set.
576  *
577  * @param height the minimum height or 0 for default height
578  *
579  * @exception SWTException <ul>
580  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
581  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
582  * </ul>
583  */
584 public void setMinHeight(int height) {
585     setMinSize(minWidth, height);
586 }
587 /**
588  * Specify the minimum width and height at which the ScrolledComposite will begin scrolling the
589  * content with the horizontal scroll bar.  This value is only relevant if
590  * setExpandHorizontal(true) and setExpandVertical(true) have been set.
591  *
592  * @param size the minimum size or null for the default size
593  *
594  * @exception SWTException <ul>
595  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
596  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
597  * </ul>
598  */
599 public void setMinSize(Point size) {
600     if (size is null) {
601         setMinSize(0, 0);
602     } else {
603         setMinSize(size.x, size.y);
604     }
605 }
606 /**
607  * Specify the minimum width and height at which the ScrolledComposite will begin scrolling the
608  * content with the horizontal scroll bar.  This value is only relevant if
609  * setExpandHorizontal(true) and setExpandVertical(true) have been set.
610  *
611  * @param width the minimum width or 0 for default width
612  * @param height the minimum height or 0 for default height
613  *
614  * @exception SWTException <ul>
615  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
616  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
617  * </ul>
618  */
619 public void setMinSize(int width, int height) {
620     checkWidget();
621     if (width is minWidth && height is minHeight) return;
622     minWidth = Math.max(0, width);
623     minHeight = Math.max(0, height);
624     layout(false);
625 }
626 /**
627  * Specify the minimum width at which the ScrolledComposite will begin scrolling the
628  * content with the horizontal scroll bar.  This value is only relevant if
629  * setExpandHorizontal(true) has been set.
630  *
631  * @param width the minimum width or 0 for default width
632  *
633  * @exception SWTException <ul>
634  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
635  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
636  * </ul>
637  */
638 public void setMinWidth(int width) {
639     setMinSize(width, minHeight);
640 }
641 
642 /**
643  * Configure the receiver to automatically scroll to a focused child control
644  * to make it visible.
645  *
646  * If show is <code>false</code>, show a focused control is off.
647  * By default, show a focused control is off.
648  *
649  * @param show <code>true</code> to show a focused control.
650  *
651  * @exception SWTException <ul>
652  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
653  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
654  * </ul>
655  *
656  * @since 3.4
657  */
658 public void setShowFocusedControl(bool show) {
659     checkWidget();
660     if (showFocusedControl is show) return;
661     Display display = getDisplay();
662     display.removeFilter(SWT.FocusIn, filter);
663     showFocusedControl = show;
664     if (!showFocusedControl) return;
665     display.addFilter(SWT.FocusIn, filter);
666     Control control = display.getFocusControl();
667     if (contains(control)) showControl(control);
668 }
669 
670 /**
671  * Scrolls the content of the receiver so that the control is visible.
672  *
673  * @param control the control to be shown
674  *
675  * @exception IllegalArgumentException <ul>
676  *    <li>ERROR_NULL_ARGUMENT - if the control is null</li>
677  *    <li>ERROR_INVALID_ARGUMENT - if the control has been disposed</li>
678  * </ul>
679  * @exception SWTException <ul>
680  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
681  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
682  * </ul>
683  *
684  * @since 3.4
685  */
686 public void showControl(Control control) {
687     checkWidget ();
688     if (control is null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
689     if (control.isDisposed ()) SWT.error(SWT.ERROR_INVALID_ARGUMENT);
690     if (!contains(control)) SWT.error(SWT.ERROR_INVALID_ARGUMENT);
691 
692     Rectangle itemRect = getDisplay().map(control.getParent(), this, control.getBounds());
693     Rectangle area = getClientArea();
694     Point origin = getOrigin();
695     if (itemRect.x < 0) origin.x = Math.max(0, origin.x + itemRect.x);
696     if (itemRect.y < 0) origin.y = Math.max(0, origin.y + itemRect.y);
697     if (area.width < itemRect.x + itemRect.width) origin.x = Math.max(0, origin.x + itemRect.x + itemRect.width - area.width);
698     if (area.height < itemRect.y + itemRect.height) origin.y = Math.max(0, origin.y + itemRect.y + itemRect.height - area.height);
699     setOrigin(origin);
700 }
701 
702 void vScroll() {
703     if (content is null) return;
704     Point location = content.getLocation ();
705     ScrollBar vBar = getVerticalBar ();
706     int vSelection = vBar.getSelection ();
707     content.setLocation (location.x, -vSelection);
708 }
709 }