| /******************************************************************************* |
| * 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 |
| ******************************************************************************/ |
| package org.eclipse.swt.custom; |
| |
| import org.eclipse.swt.SWT; |
| import org.eclipse.swt.SWTException; |
| import org.eclipse.swt.events.*; |
| import org.eclipse.swt.graphics.Point; |
| import org.eclipse.swt.graphics.Rectangle; |
| import org.eclipse.swt.widgets.*; |
| |
| /** |
| * Instances of this class implement a Composite that lays out its children and |
| * allows programmatic control of the layout. It draws a separator between the |
| * left and right children which can be dragged to resize the right control. |
| * CBanner is used in the workbench to layout the toolbar area and perspective |
| * switching toolbar. |
| * <p> |
| * Note that although this class is a subclass of <code>Composite</code>, it |
| * does not make sense to set a layout on it. |
| * </p> |
| * <p> |
| * <dl> |
| * <dt><b>Styles:</b></dt> |
| * <dd>NONE</dd> |
| * <dt><b>Events:</b></dt> |
| * <dd>(None)</dd> |
| * </dl> |
| * <p> |
| * IMPORTANT: This class is <em>not</em> intended to be subclassed. |
| * </p> |
| * |
| * @since 3.0 |
| */ |
| public class CBanner extends Composite { |
| |
| Control left; |
| Control right; |
| Control bottom; |
| /** Sash to replace the curved separator in SWT */ |
| Sash separator; |
| boolean simple = true; |
| int[] curve; |
| int curveStart = 0; |
| Rectangle curveRect = new Rectangle( 0, 0, 0, 0 ); |
| int curve_width = 5; |
| int curve_indent = -2; |
| int rightWidth = SWT.DEFAULT; |
| int rightMinWidth = 0; |
| int rightMinHeight = 0; |
| // Cursor resizeCursor; |
| // boolean dragging = false; |
| // int rightDragDisplacement = 0; |
| static final int OFFSCREEN = -200; |
| static final int BORDER_BOTTOM = 2; |
| static final int BORDER_TOP = 3; |
| static final int BORDER_STRIPE = 1; |
| static final int CURVE_TAIL = 200; |
| static final int BEZIER_RIGHT = 30; |
| static final int BEZIER_LEFT = 30; |
| static final int MIN_LEFT = 10; |
| |
| // static int BORDER1 = SWT.COLOR_WIDGET_HIGHLIGHT_SHADOW; |
| /** |
| * 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>SWT</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>SWT</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 SWTException |
| * <ul> |
| * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the |
| * thread that created the parent</li> |
| * </ul> |
| */ |
| public CBanner( Composite parent, int style ) { |
| super( parent, checkStyle( style ) ); |
| super.setLayout( new CBannerLayout() ); |
| separator = new Sash( this, SWT.VERTICAL ); |
| separator.addSelectionListener( new SelectionAdapter() { |
| |
| public void widgetSelected( SelectionEvent event ) { |
| // TODO: check SWT.DRAG in event.details ? |
| onSepMove( event.x, event.width ); |
| } |
| } ); |
| // Listener listener = new Listener() { |
| // public void handleEvent(Event e) { |
| // switch (e.type) { |
| // case SWT.Dispose: |
| // onDispose(); break; |
| // case SWT.MouseDown: |
| // onMouseDown (e.x, e.y); break; |
| // case SWT.MouseExit: |
| // onMouseExit(); break; |
| // case SWT.MouseMove: |
| // onMouseMove(e.x, e.y); break; |
| // case SWT.MouseUp: |
| // onMouseUp(); break; |
| // case SWT.Paint: |
| // onPaint(e.gc); break; |
| // case SWT.Resize: |
| // onResize(); break; |
| // } |
| // } |
| // }; |
| // int[] events = new int[] {SWT.Dispose, SWT.MouseDown, SWT.MouseExit, |
| // SWT.MouseMove, SWT.MouseUp, SWT.Paint, SWT.Resize}; |
| // for (int i = 0; i < events.length; i++) { |
| // addListener(events[i], listener); |
| // } |
| addControlListener( new ControlListener() { |
| |
| public void controlMoved( ControlEvent event ) { |
| } |
| |
| public void controlResized( ControlEvent event ) { |
| onResize(); |
| } |
| } ); |
| addDisposeListener( new DisposeListener() { |
| |
| public void widgetDisposed( DisposeEvent event ) { |
| onDispose(); |
| } |
| } ); |
| } |
| |
| static int[] bezier( int x0, |
| int y0, |
| int x1, |
| int y1, |
| int x2, |
| int y2, |
| int x3, |
| int y3, |
| int count ) |
| { |
| // The parametric equations for a Bezier curve for x[t] and y[t] where 0 <= |
| // t <=1 are: |
| // x[t] = x0+3(x1-x0)t+3(x0+x2-2x1)t^2+(x3-x0+3x1-3x2)t^3 |
| // y[t] = y0+3(y1-y0)t+3(y0+y2-2y1)t^2+(y3-y0+3y1-3y2)t^3 |
| double a0 = x0; |
| double a1 = 3 * ( x1 - x0 ); |
| double a2 = 3 * ( x0 + x2 - 2 * x1 ); |
| double a3 = x3 - x0 + 3 * x1 - 3 * x2; |
| double b0 = y0; |
| double b1 = 3 * ( y1 - y0 ); |
| double b2 = 3 * ( y0 + y2 - 2 * y1 ); |
| double b3 = y3 - y0 + 3 * y1 - 3 * y2; |
| int[] polygon = new int[ 2 * count + 2 ]; |
| for( int i = 0; i <= count; i++ ) { |
| double t = ( double )i / ( double )count; |
| polygon[ 2 * i ] = ( int )( a0 + a1 * t + a2 * t * t + a3 * t * t * t ); |
| polygon[ 2 * i + 1 ] = ( int )( b0 + b1 * t + b2 * t * t + b3 * t * t * t ); |
| } |
| return polygon; |
| } |
| |
| static int checkStyle( int style ) { |
| return SWT.NONE; |
| } |
| |
| /** |
| * Returns the Control that appears on the bottom side of the banner. |
| * |
| * @return the control that appears on the bottom side of the banner or null |
| * @exception SWTException |
| * <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.0 |
| */ |
| public Control getBottom() { |
| // checkWidget(); |
| return bottom; |
| } |
| |
| public Rectangle getClientArea() { |
| return new Rectangle( 0, 0, 0, 0 ); |
| } |
| |
| /** |
| * Returns the Control that appears on the left side of the banner. |
| * |
| * @return the control that appears on the left side of the banner or null |
| * @exception SWTException |
| * <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.0 |
| */ |
| public Control getLeft() { |
| // checkWidget(); |
| return left; |
| } |
| |
| /** |
| * Returns the Control that appears on the right side of the banner. |
| * |
| * @return the control that appears on the right side of the banner or null |
| * @exception SWTException |
| * <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.0 |
| */ |
| public Control getRight() { |
| // checkWidget(); |
| return right; |
| } |
| |
| /** |
| * Returns the minimum size of the control that appears on the right of the |
| * banner. |
| * |
| * @return the minimum size of the control that appears on the right of the |
| * banner |
| * @since 3.1 |
| */ |
| public Point getRightMinimumSize() { |
| // checkWidget(); |
| return new Point( rightMinWidth, rightMinHeight ); |
| } |
| |
| /** |
| * Returns the width of the control that appears on the right of the banner. |
| * |
| * @return the width of the control that appears on the right of the banner |
| * @since 3.0 |
| */ |
| public int getRightWidth() { |
| // checkWidget(); |
| if( right == null ) |
| return 0; |
| if( rightWidth == SWT.DEFAULT ) { |
| Point size = right.computeSize( SWT.DEFAULT, SWT.DEFAULT, false ); |
| return size.x; |
| } |
| return rightWidth; |
| } |
| |
| /** |
| * Returns <code>true</code> if the CBanner is rendered with a simple, |
| * traditional shape. |
| * |
| * @return <code>true</code> if the Cbanner is rendered with a simple shape |
| * @since 3.0 |
| */ |
| public boolean getSimple() { |
| // checkWidget(); |
| return simple; |
| } |
| |
| void onDispose() { |
| // if (resizeCursor != null) resizeCursor.dispose(); |
| // resizeCursor = null; |
| left = null; |
| right = null; |
| bottom = null; |
| } |
| |
| /* |
| * void onMouseDown (int x, int y) { if (curveRect.contains(x, y)) { dragging = |
| * true; rightDragDisplacement = curveStart - x + curve_width - curve_indent; } } |
| * void onMouseExit() { if (!dragging) setCursor(null); } void onMouseMove(int |
| * x, int y) { if (dragging) { Point size = getSize(); if (!(0 < x && x < |
| * size.x)) return; rightWidth = Math.max(0, size.x - x - |
| * rightDragDisplacement); if (rightMinWidth == SWT.DEFAULT) { Point minSize = |
| * right.computeSize(rightMinWidth, rightMinHeight); rightWidth = |
| * Math.max(minSize.x, rightWidth); } else { rightWidth = |
| * Math.max(rightMinWidth, rightWidth); } layout(false); return; } if |
| * (curveRect.contains(x, y)) { setCursor(resizeCursor); } else { |
| * setCursor(null); } } void onMouseUp () { dragging = false; } void |
| * onPaint(GC gc) { // Useful for debugging paint problems // { // Point size = |
| * getSize(); // |
| * gc.setBackground(getDisplay().getSystemColor(SWT.COLOR_GREEN)); // |
| * gc.fillRectangle(-10, -10, size.x+20, size.y+20); // } if (left == null && |
| * right == null) return; Point size = getSize(); Color border1 = |
| * getDisplay().getSystemColor(BORDER1); if (bottom != null) { int y = |
| * bottom.getBounds().y - BORDER_STRIPE - 1; gc.setForeground(border1); |
| * gc.drawLine(0, y, size.x, y); } if (left == null || right == null) return; |
| * int[] line1 = new int[curve.length+6]; int index = 0; int x = curveStart; |
| * line1[index++] = x + 1; line1[index++] = size.y - BORDER_STRIPE; for (int i = |
| * 0; i < curve.length/2; i++) { line1[index++]=x+curve[2*i]; |
| * line1[index++]=curve[2*i+1]; } line1[index++] = x + curve_width; |
| * line1[index++] = 0; line1[index++] = size.x; line1[index++] = 0; Color |
| * background = getBackground(); if (getDisplay().getDepth() >= 15) { // Anti- |
| * aliasing int[] line2 = new int[line1.length]; index = 0; for (int i = 0; i < |
| * line1.length/2; i++) { line2[index] = line1[index++] - 1; line2[index] = |
| * line1[index++]; } int[] line3 = new int[line1.length]; index = 0; for (int |
| * i = 0; i < line1.length/2; i++) { line3[index] = line1[index++] + 1; |
| * line3[index] = line1[index++]; } RGB from = border1.getRGB(); RGB to = |
| * background.getRGB(); int red = from.red + 3*(to.red - from.red)/4; int |
| * green = from.green + 3*(to.green - from.green)/4; int blue = from.blue + |
| * 3*(to.blue - from.blue)/4; Color color = new Color(getDisplay(), red, |
| * green, blue); gc.setForeground(color); gc.drawPolyline(line2); |
| * gc.drawPolyline(line3); color.dispose(); // draw tail fading to background |
| * int x1 = Math.max(0, curveStart - CURVE_TAIL); |
| * gc.setForeground(background); gc.setBackground(border1); |
| * gc.fillGradientRectangle(x1, size.y - BORDER_STRIPE, curveStart-x1+1, 1, |
| * false); } else { // draw solid tail int x1 = Math.max(0, curveStart - |
| * CURVE_TAIL); gc.setForeground(border1); gc.drawLine(x1, size.y - |
| * BORDER_STRIPE, curveStart+1, size.y - BORDER_STRIPE); } // draw border |
| * gc.setForeground(border1); gc.drawPolyline(line1); } |
| */ |
| void onResize() { |
| updateCurve( getSize().y ); |
| } |
| |
| void onSepMove( int x, int width ) { |
| Point size = getSize(); |
| // int rightDragDisplacement = curveStart - x + curve_width - curve_indent; |
| // rightWidth = Math.max(0, size.x - x - rightDragDisplacement); |
| rightWidth = Math.max( 0, size.x - x - curve_width + 2 * curve_indent ); |
| if( rightMinWidth == SWT.DEFAULT ) { |
| // Point minSize = right.computeSize(rightMinWidth, rightMinHeight); |
| Point minSize = right.computeSize( rightMinWidth, rightMinHeight, false ); |
| rightWidth = Math.max( minSize.x, rightWidth ); |
| } else { |
| rightWidth = Math.max( rightMinWidth, rightWidth ); |
| } |
| layout(); |
| } |
| |
| /** |
| * Set the control that appears on the bottom side of the banner. The bottom |
| * control is optional. Setting the bottom control to null will remove it from |
| * the banner - however, the creator of the control must dispose of the |
| * control. |
| * |
| * @param control the control to be displayed on the bottom or null |
| * @exception SWTException |
| * <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 - if the bottom control was not |
| * created as a child of the receiver</li> |
| * </ul> |
| * @since 3.0 |
| */ |
| public void setBottom( Control control ) { |
| // checkWidget(); |
| if( control != null && control.getParent() != this ) { |
| SWT.error( SWT.ERROR_INVALID_ARGUMENT ); |
| } |
| if( bottom != null && !bottom.isDisposed() ) { |
| Point size = bottom.getSize(); |
| bottom.setLocation( OFFSCREEN - size.x, OFFSCREEN - size.y ); |
| } |
| bottom = control; |
| layout(); |
| } |
| |
| /** |
| * 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 SWTException |
| * <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 setLayout( Layout layout ) { |
| // checkWidget(); |
| return; |
| } |
| |
| /** |
| * Set the control that appears on the left side of the banner. The left |
| * control is optional. Setting the left control to null will remove it from |
| * the banner - however, the creator of the control must dispose of the |
| * control. |
| * |
| * @param control the control to be displayed on the left or null |
| * @exception SWTException |
| * <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 - if the left control was not |
| * created as a child of the receiver</li> |
| * </ul> |
| * @since 3.0 |
| */ |
| public void setLeft( Control control ) { |
| // checkWidget(); |
| if( control != null && control.getParent() != this ) { |
| SWT.error( SWT.ERROR_INVALID_ARGUMENT ); |
| } |
| if( left != null && !left.isDisposed() ) { |
| Point size = left.getSize(); |
| left.setLocation( OFFSCREEN - size.x, OFFSCREEN - size.y ); |
| } |
| left = control; |
| layout(); |
| } |
| |
| /** |
| * Set the control that appears on the right side of the banner. The right |
| * control is optional. Setting the right control to null will remove it from |
| * the banner - however, the creator of the control must dispose of the |
| * control. |
| * |
| * @param control the control to be displayed on the right or null |
| * @exception SWTException |
| * <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 - if the right control was not |
| * created as a child of the receiver</li> |
| * </ul> |
| * @since 3.0 |
| */ |
| public void setRight( Control control ) { |
| // checkWidget(); |
| if( control != null && control.getParent() != this ) { |
| SWT.error( SWT.ERROR_INVALID_ARGUMENT ); |
| } |
| if( right != null && !right.isDisposed() ) { |
| Point size = right.getSize(); |
| right.setLocation( OFFSCREEN - size.x, OFFSCREEN - size.y ); |
| } |
| right = control; |
| layout(); |
| } |
| |
| /** |
| * Set the minimum height of the control that appears on the right side of the |
| * banner. |
| * |
| * @param size the minimum size of the control on the right |
| * @exception SWTException |
| * <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 - if the size is null or the |
| * values of size are less than SWT.DEFAULT</li> |
| * </ul> |
| * @since 3.1 |
| */ |
| public void setRightMinimumSize( Point size ) { |
| // checkWidget(); |
| if( size == null || size.x < SWT.DEFAULT || size.y < SWT.DEFAULT ) |
| SWT.error( SWT.ERROR_INVALID_ARGUMENT ); |
| rightMinWidth = size.x; |
| rightMinHeight = size.y; |
| layout(); |
| } |
| |
| /** |
| * Set the width of the control that appears on the right side of the banner. |
| * |
| * @param width the width of the control on the right |
| * @exception SWTException |
| * <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 - if width is less than |
| * SWT.DEFAULT</li> |
| * </ul> |
| * @since 3.0 |
| */ |
| public void setRightWidth( int width ) { |
| // checkWidget(); |
| if( width < SWT.DEFAULT ) |
| SWT.error( SWT.ERROR_INVALID_ARGUMENT ); |
| rightWidth = width; |
| layout(); |
| } |
| |
| /** |
| * Sets the shape that the CBanner will use to render itself. |
| * |
| * @param simple <code>true</code> if the CBanner should render itself in a |
| * simple, traditional style |
| * @exception SWTException |
| * <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.0 |
| */ |
| public void setSimple( boolean simple ) { |
| // checkWidget(); |
| if( this.simple != simple ) { |
| this.simple = simple; |
| if( simple ) { |
| curve_width = 5; |
| curve_indent = -2; |
| } else { |
| curve_width = 50; |
| curve_indent = 5; |
| } |
| updateCurve( getSize().y ); |
| layout(); |
| // redraw(); |
| } |
| } |
| |
| void updateCurve( int height ) { |
| int h = height - BORDER_STRIPE; |
| if( simple ) { |
| curve = new int[]{ |
| 0, h, 1, h, 2, h - 1, 3, h - 2, 3, 2, 4, 1, 5, 0, |
| }; |
| } else { |
| curve = bezier( 0, |
| h + 1, |
| BEZIER_LEFT, |
| h + 1, |
| curve_width - BEZIER_RIGHT, |
| 0, |
| curve_width, |
| 0, |
| curve_width ); |
| } |
| } |
| } |