Mercurial > projects > dwt-win
diff dwt/custom/ScrolledComposite.d @ 155:a5afe31f5cdd
Added custom controls
author | Frank Benoit <benoit@tionex.de> |
---|---|
date | Thu, 14 Feb 2008 19:18:37 +0100 |
parents | |
children | ab60f3309436 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dwt/custom/ScrolledComposite.d Thu Feb 14 19:18:37 2008 +0100 @@ -0,0 +1,595 @@ +/******************************************************************************* + * Copyright (c) 2000, 2006 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Port to the D programming language: + * Frank Benoit <benoit@tionex.de> + *******************************************************************************/ +module dwt.custom.ScrolledComposite; + + +import dwt.DWT; +import dwt.DWTException; +import dwt.graphics.Point; +import dwt.graphics.Rectangle; +import dwt.widgets.Composite; +import dwt.widgets.Control; +import dwt.widgets.Event; +import dwt.widgets.Layout; +import dwt.widgets.Listener; +import dwt.widgets.ScrollBar; +import dwt.custom.ScrolledCompositeLayout; + +/** + * A ScrolledComposite provides scrollbars and will scroll its content when the user + * uses the scrollbars. + * + * + * <p>There are two ways to use the ScrolledComposite: + * + * <p> + * 1) Set the size of the control that is being scrolled and the ScrolledComposite + * will show scrollbars when the contained control can not be fully seen. + * + * 2) The second way imitates the way a browser would work. Set the minimum size of + * the control and the ScrolledComposite will show scroll bars if the visible area is + * less than the minimum size of the control and it will expand the size of the control + * if the visible area is greater than the minimum size. This requires invoking + * both setMinWidth(), setMinHeight() and setExpandHorizontal(), setExpandVertical(). + * + * <code><pre> + * public static void main (String [] args) { + * Display display = new Display (); + * Color red = display.getSystemColor(DWT.COLOR_RED); + * Color blue = display.getSystemColor(DWT.COLOR_BLUE); + * Shell shell = new Shell (display); + * shell.setLayout(new FillLayout()); + * + * // set the size of the scrolled content - method 1 + * final ScrolledComposite sc1 = new ScrolledComposite(shell, DWT.H_SCROLL | DWT.V_SCROLL | DWT.BORDER); + * final Composite c1 = new Composite(sc1, DWT.NONE); + * sc1.setContent(c1); + * c1.setBackground(red); + * GridLayout layout = new GridLayout(); + * layout.numColumns = 4; + * c1.setLayout(layout); + * Button b1 = new Button (c1, DWT.PUSH); + * b1.setText("first button"); + * c1.setSize(c1.computeSize(DWT.DEFAULT, DWT.DEFAULT)); + * + * // set the minimum width and height of the scrolled content - method 2 + * final ScrolledComposite sc2 = new ScrolledComposite(shell, DWT.H_SCROLL | DWT.V_SCROLL | DWT.BORDER); + * sc2.setExpandHorizontal(true); + * sc2.setExpandVertical(true); + * final Composite c2 = new Composite(sc2, DWT.NONE); + * sc2.setContent(c2); + * c2.setBackground(blue); + * layout = new GridLayout(); + * layout.numColumns = 4; + * c2.setLayout(layout); + * Button b2 = new Button (c2, DWT.PUSH); + * b2.setText("first button"); + * sc2.setMinSize(c2.computeSize(DWT.DEFAULT, DWT.DEFAULT)); + * + * Button add = new Button (shell, DWT.PUSH); + * add.setText("add children"); + * final int[] index = new int[]{0}; + * add.addListener(DWT.Selection, new Listener() { + * public void handleEvent(Event e) { + * index[0]++; + * Button button = new Button(c1, DWT.PUSH); + * button.setText("button "+index[0]); + * // reset size of content so children can be seen - method 1 + * c1.setSize(c1.computeSize(DWT.DEFAULT, DWT.DEFAULT)); + * c1.layout(); + * + * button = new Button(c2, DWT.PUSH); + * button.setText("button "+index[0]); + * // reset the minimum width and height so children can be seen - method 2 + * sc2.setMinSize(c2.computeSize(DWT.DEFAULT, DWT.DEFAULT)); + * c2.layout(); + * } + * }); + * + * shell.open (); + * while (!shell.isDisposed ()) { + * if (!display.readAndDispatch ()) display.sleep (); + * } + * display.dispose (); + * } + * </pre></code> + * + * <dl> + * <dt><b>Styles:</b><dd>H_SCROLL, V_SCROLL + * </dl> + */ +public class ScrolledComposite : Composite { + + Control content; + Listener contentListener; + + int minHeight = 0; + int minWidth = 0; + bool expandHorizontal = false; + bool expandVertical = false; + bool alwaysShowScroll = false; + +/** + * Constructs a new instance of this class given its parent + * and a style value describing its behavior and appearance. + * <p> + * The style value is either one of the style constants defined in + * class <code>DWT</code> which is applicable to instances of this + * class, or must be built by <em>bitwise OR</em>'ing together + * (that is, using the <code>int</code> "|" operator) two or more + * of those <code>DWT</code> style constants. The class description + * lists the style constants that are applicable to the class. + * Style bits are also inherited from superclasses. + * </p> + * + * @param parent a widget which will be the parent of the new instance (cannot be null) + * @param style the style of widget to construct + * + * @exception IllegalArgumentException <ul> + * <li>ERROR_NULL_ARGUMENT - if the parent is null</li> + * </ul> + * @exception DWTException <ul> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the parent</li> + * </ul> + * + * @see DWT#H_SCROLL + * @see DWT#V_SCROLL + * @see #getStyle() + */ +public this(Composite parent, int style) { + super(parent, checkStyle(style)); + super.setLayout(new ScrolledCompositeLayout()); + ScrollBar hBar = getHorizontalBar (); + if (hBar !is null) { + hBar.setVisible(false); + hBar.addListener (DWT.Selection, new class() Listener { + public void handleEvent (Event e) { + hScroll(); + } + }); + } + + ScrollBar vBar = getVerticalBar (); + if (vBar !is null) { + vBar.setVisible(false); + vBar.addListener (DWT.Selection, new class() Listener { + public void handleEvent (Event e) { + vScroll(); + } + }); + } + + contentListener = new class() Listener { + public void handleEvent(Event e) { + if (e.type !is DWT.Resize) return; + layout(false); + } + }; +} + +static int checkStyle (int style) { + int mask = DWT.H_SCROLL | DWT.V_SCROLL | DWT.BORDER | DWT.LEFT_TO_RIGHT | DWT.RIGHT_TO_LEFT; + return style & mask; +} + +/** + * Returns the Always Show Scrollbars flag. True if the scrollbars are + * always shown even if they are not required. False if the scrollbars are only + * visible when some part of the composite needs to be scrolled to be seen. + * The H_SCROLL and V_SCROLL style bits are also required to enable scrollbars in the + * horizontal and vertical directions. + * + * @return the Always Show Scrollbars flag value + */ +public bool getAlwaysShowScrollBars() { + //checkWidget(); + return alwaysShowScroll; +} + +/** + * Returns <code>true</code> if the content control + * will be expanded to fill available horizontal space. + * + * @return the receiver's horizontal expansion state + * + * @exception DWTException <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> + * </ul> + * + * @since 3.2 + */ +public bool getExpandHorizontal() { + checkWidget(); + return expandHorizontal; +} + +/** + * Returns <code>true</code> if the content control + * will be expanded to fill available vertical space. + * + * @return the receiver's vertical expansion state + * + * @exception DWTException <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> + * </ul> + * + * @since 3.2 + */ +public bool getExpandVertical() { + checkWidget(); + return expandVertical; +} + +/** + * Returns the minimum width of the content control. + * + * @return the minimum width + * + * @exception DWTException <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> + * </ul> + * + * @since 3.2 + */ +public int getMinWidth() { + checkWidget(); + return minWidth; +} + +/** + * Returns the minimum height of the content control. + * + * @return the minimum height + * + * @exception DWTException <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> + * </ul> + * + * @since 3.2 + */ +public int getMinHeight() { + checkWidget(); + return minHeight; +} + +/** + * Get the content that is being scrolled. + * + * @return the control displayed in the content area + */ +public Control getContent() { + //checkWidget(); + return content; +} + +void hScroll() { + if (content is null) return; + Point location = content.getLocation (); + ScrollBar hBar = getHorizontalBar (); + int hSelection = hBar.getSelection (); + content.setLocation (-hSelection, location.y); +} +bool needHScroll(Rectangle contentRect, bool vVisible) { + ScrollBar hBar = getHorizontalBar(); + if (hBar is null) return false; + + Rectangle hostRect = getBounds(); + int border = getBorderWidth(); + hostRect.width -= 2*border; + ScrollBar vBar = getVerticalBar(); + if (vVisible && vBar !is null) hostRect.width -= vBar.getSize().x; + + if (!expandHorizontal && contentRect.width > hostRect.width) return true; + if (expandHorizontal && minWidth > hostRect.width) return true; + return false; +} + +bool needVScroll(Rectangle contentRect, bool hVisible) { + ScrollBar vBar = getVerticalBar(); + if (vBar is null) return false; + + Rectangle hostRect = getBounds(); + int border = getBorderWidth(); + hostRect.height -= 2*border; + ScrollBar hBar = getHorizontalBar(); + if (hVisible && hBar !is null) hostRect.height -= hBar.getSize().y; + + if (!expandVertical && contentRect.height > hostRect.height) return true; + if (expandVertical && minHeight > hostRect.height) return true; + return false; +} + +/** + * Return the point in the content that currently appears in the top left + * corner of the scrolled composite. + * + * @return the point in the content that currently appears in the top left + * corner of the scrolled composite. If no content has been set, this returns + * (0, 0). + * + * @exception DWTException <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> + * </ul> + * + * @since 2.0 + */ +public Point getOrigin() { + checkWidget(); + if (content is null) return new Point(0, 0); + Point location = content.getLocation(); + return new Point(-location.x, -location.y); +} +/** + * Scrolls the content so that the specified point in the content is in the top + * left corner. If no content has been set, nothing will occur. + * + * Negative values will be ignored. Values greater than the maximum scroll + * distance will result in scrolling to the end of the scrollbar. + * + * @param origin the point on the content to appear in the top left corner + * + * @exception DWTException <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> + * <li>ERROR_INVALID_ARGUMENT - value of origin is outside of content + * </ul> + * @since 2.0 + */ +public void setOrigin(Point origin) { + setOrigin(origin.x, origin.y); +} +/** + * Scrolls the content so that the specified point in the content is in the top + * left corner. If no content has been set, nothing will occur. + * + * Negative values will be ignored. Values greater than the maximum scroll + * distance will result in scrolling to the end of the scrollbar. + * + * @param x the x coordinate of the content to appear in the top left corner + * + * @param y the y coordinate of the content to appear in the top left corner + * + * @exception DWTException <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> + * </ul> + * + * @since 2.0 + */ +public void setOrigin(int x, int y) { + checkWidget(); + if (content is null) return; + ScrollBar hBar = getHorizontalBar (); + if (hBar !is null) { + hBar.setSelection(x); + x = -hBar.getSelection (); + } else { + x = 0; + } + ScrollBar vBar = getVerticalBar (); + if (vBar !is null) { + vBar.setSelection(y); + y = -vBar.getSelection (); + } else { + y = 0; + } + content.setLocation(x, y); +} +/** + * Set the Always Show Scrollbars flag. True if the scrollbars are + * always shown even if they are not required. False if the scrollbars are only + * visible when some part of the composite needs to be scrolled to be seen. + * The H_SCROLL and V_SCROLL style bits are also required to enable scrollbars in the + * horizontal and vertical directions. + * + * @param show true to show the scrollbars even when not required, false to show scrollbars only when required + * + * @exception DWTException <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> + * </ul> + */ +public void setAlwaysShowScrollBars(bool show) { + checkWidget(); + if (show is alwaysShowScroll) return; + alwaysShowScroll = show; + ScrollBar hBar = getHorizontalBar (); + if (hBar !is null && alwaysShowScroll) hBar.setVisible(true); + ScrollBar vBar = getVerticalBar (); + if (vBar !is null && alwaysShowScroll) vBar.setVisible(true); + layout(false); +} + +/** + * Set the content that will be scrolled. + * + * @param content the control to be displayed in the content area + * + * @exception DWTException <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> + * </ul> + */ +public void setContent(Control content) { + checkWidget(); + if (this.content !is null && !this.content.isDisposed()) { + this.content.removeListener(DWT.Resize, contentListener); + this.content.setBounds(new Rectangle(-200, -200, 0, 0)); + } + + this.content = content; + ScrollBar vBar = getVerticalBar (); + ScrollBar hBar = getHorizontalBar (); + if (this.content !is null) { + if (vBar !is null) { + vBar.setMaximum (0); + vBar.setThumb (0); + vBar.setSelection(0); + } + if (hBar !is null) { + hBar.setMaximum (0); + hBar.setThumb (0); + hBar.setSelection(0); + } + content.setLocation(0, 0); + layout(false); + this.content.addListener(DWT.Resize, contentListener); + } else { + if (hBar !is null) hBar.setVisible(alwaysShowScroll); + if (vBar !is null) vBar.setVisible(alwaysShowScroll); + } +} +/** + * Configure the ScrolledComposite to resize the content object to be as wide as the + * ScrolledComposite when the width of the ScrolledComposite is greater than the + * minimum width specified in setMinWidth. If the ScrolledComposite is less than the + * minimum width, the content will not be resized and instead the horizontal scroll bar will be + * used to view the entire width. + * If expand is false, this behaviour is turned off. By default, this behaviour is turned off. + * + * @param expand true to expand the content control to fill available horizontal space + * + * @exception DWTException <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> + * </ul> + */ +public void setExpandHorizontal(bool expand) { + checkWidget(); + if (expand is expandHorizontal) return; + expandHorizontal = expand; + layout(false); +} +/** + * Configure the ScrolledComposite to resize the content object to be as tall as the + * ScrolledComposite when the height of the ScrolledComposite is greater than the + * minimum height specified in setMinHeight. If the ScrolledComposite is less than the + * minimum height, the content will not be resized and instead the vertical scroll bar will be + * used to view the entire height. + * If expand is false, this behaviour is turned off. By default, this behaviour is turned off. + * + * @param expand true to expand the content control to fill available vertical space + * + * @exception DWTException <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> + * </ul> + */ +public void setExpandVertical(bool expand) { + checkWidget(); + if (expand is expandVertical) return; + expandVertical = expand; + layout(false); +} +/** + * Sets the layout which is associated with the receiver to be + * the argument which may be null. + * <p> + * Note: No Layout can be set on this Control because it already + * manages the size and position of its children. + * </p> + * + * @param layout the receiver's new layout or null + * + * @exception DWTException <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> + * </ul> + */ +public override void setLayout (Layout layout) { + checkWidget(); + return; +} +/** + * Specify the minimum height at which the ScrolledComposite will begin scrolling the + * content with the vertical scroll bar. This value is only relevant if + * setExpandVertical(true) has been set. + * + * @param height the minimum height or 0 for default height + * + * @exception DWTException <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> + * </ul> + */ +public void setMinHeight(int height) { + setMinSize(minWidth, height); +} +/** + * Specify the minimum width and height at which the ScrolledComposite will begin scrolling the + * content with the horizontal scroll bar. This value is only relevant if + * setExpandHorizontal(true) and setExpandVertical(true) have been set. + * + * @param size the minimum size or null for the default size + * + * @exception DWTException <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> + * </ul> + */ +public void setMinSize(Point size) { + if (size is null) { + setMinSize(0, 0); + } else { + setMinSize(size.x, size.y); + } +} +/** + * Specify the minimum width and height at which the ScrolledComposite will begin scrolling the + * content with the horizontal scroll bar. This value is only relevant if + * setExpandHorizontal(true) and setExpandVertical(true) have been set. + * + * @param width the minimum width or 0 for default width + * @param height the minimum height or 0 for default height + * + * @exception DWTException <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> + * </ul> + */ +public void setMinSize(int width, int height) { + checkWidget(); + if (width is minWidth && height is minHeight) return; + minWidth = Math.max(0, width); + minHeight = Math.max(0, height); + layout(false); +} +/** + * Specify the minimum width at which the ScrolledComposite will begin scrolling the + * content with the horizontal scroll bar. This value is only relevant if + * setExpandHorizontal(true) has been set. + * + * @param width the minimum width or 0 for default width + * + * @exception DWTException <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> + * </ul> + */ +public void setMinWidth(int width) { + setMinSize(width, minHeight); +} + +void vScroll() { + if (content is null) return; + Point location = content.getLocation (); + ScrollBar vBar = getVerticalBar (); + int vSelection = vBar.getSelection (); + content.setLocation (location.x, -vSelection); +} +}