Mercurial > projects > dwt-mac
view dwt/custom/CBanner.d @ 17:5b53d338c709
Fixed some errors after latest merge
author | Jacob Carlborg <doob@me.com> <jacob.carlborg@gmail.com> |
---|---|
date | Fri, 29 Aug 2008 22:04:22 +0200 |
parents | f565d3a95c0a e831403a80a9 |
children | 6337764516f1 |
line wrap: on
line source
/******************************************************************************* * Copyright (c) 2000, 2007 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: * Jacob Carlborg <jacob.carlborg@gmail.com> *******************************************************************************/ module dwt.custom.CBanner; import dwt.DWT; import dwt.DWTException; import dwt.graphics.Color; import dwt.graphics.Cursor; import dwt.graphics.GC; import dwt.graphics.Point; import dwt.graphics.RGB; import dwt.graphics.Rectangle; import dwt.widgets.Composite; import dwt.widgets.Control; import dwt.widgets.Event; import dwt.widgets.Layout; import dwt.widgets.Listener; /** * 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>cast(None)</dd> * </dl> * <p> * IMPORTANT: This class is <em>not</em> intended to be subclassed. * </p> * * @since 3.0 */ public class CBanner : Composite { Control left; Control right; Control bottom; bool simple = true; int[] curve = new int[0]; int curveStart = 0; Rectangle curveRect = new Rectangle(0, 0, 0, 0); int curve_width = 5; int curve_indent = -2; int rightWidth = DWT.DEFAULT; int rightMinWidth = 0; int rightMinHeight = 0; Cursor resizeCursor; bool dragging = false; int rightDragDisplacement = 0; static const int OFFSCREEN = -200; static const int BORDER_BOTTOM = 2; static const int BORDER_TOP = 3; static const int BORDER_STRIPE = 1; static const int CURVE_TAIL = 200; static const int BEZIER_RIGHT = 30; static const int BEZIER_LEFT = 30; static const int MIN_LEFT = 10; static int BORDER1 = DWT.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>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> * */ public this (Composite parent, int style) { super(parent, checkStyle(style)); super.setLayout(new CBannerLayout()); resizeCursor = new Cursor(getDisplay(), DWT.CURSOR_SIZEWE); Listener listener = new class Listener { public void handleEvent (Event e) { switch (e.type) { case DWT.Dispose: onDispose(); break; case DWT.MouseDown: onMouseDown(e.x, e.y); break; case DWT.MouseExit: onMouseExit(); break; case DWT.MouseMove: onMouseMove(e.x, e.y); break; case DWT.MouseUp: onMouseUp(); break; case DWT.Paint: onPaint(e.gc); break; case DWT.Resize: onResize(); break; } } }; int[] events = new int[][DWT.Dispose , DWT.MouseDown , DWT.MouseExit , DWT.MouseMove , DWT.MouseUp , DWT.Paint , DWT.Resize]; for (int i = 0; i < events.length; i++) { addListener(events[i], listener); } } 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 = cast(double) i / cast(double) count; polygon[2 * i] = cast(int) (a0 + a1 * t + a2 * t * t + a3 * t * t * t); polygon[2 * i + 1] = cast(int) (b0 + b1 * t + b2 * t * t + b3 * t * t * t); } return polygon; } static int checkStyle (int style) { return DWT.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 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.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 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.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 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.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 is null) return 0; if (rightWidth is DWT.DEFAULT) { Point size = right.computeSize(DWT.DEFAULT, DWT.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 bool getSimple () { checkWidget(); return simple; } void onDispose () { if (resizeCursor !is 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 is DWT.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(DWT.COLOR_GREEN)); // gc.fillRectangle(-10, -10, size.x+20, size.y+20); // } if (left is null && right is null) return; Point size = getSize(); Color border1 = getDisplay().getSystemColor(BORDER1); if (bottom !is null) { int y = bottom.getBounds().y - BORDER_STRIPE - 1; gc.setForeground(border1); gc.drawLine(0, y, size.x, y); } if (left is null || right is 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); } /** * 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 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 - 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 !is null && control.getParent() !is this) { DWT.error(DWT.ERROR_INVALID_ARGUMENT); } if (bottom !is null && !bottom.isDisposed()) { Point size = bottom.getSize(); bottom.setLocation(OFFSCREEN - size.x, OFFSCREEN - size.y); } bottom = control; 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 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 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 - 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 !is null && control.getParent() !is this) { DWT.error(DWT.ERROR_INVALID_ARGUMENT); } if (left !is null && !left.isDisposed()) { Point size = left.getSize(); left.setLocation(OFFSCREEN - size.x, OFFSCREEN - size.y); } left = control; layout(false); } /** * 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 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 - 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 !is null && control.getParent() !is this) { DWT.error(DWT.ERROR_INVALID_ARGUMENT); } if (right !is null && !right.isDisposed()) { Point size = right.getSize(); right.setLocation(OFFSCREEN - size.x, OFFSCREEN - size.y); } right = control; layout(false); } /** * 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 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 - if the size is null or the values of size are less than DWT.DEFAULT</li> * </ul> * * @since 3.1 */ public void setRightMinimumSize (Point size) { checkWidget(); if (size is null || size.x < DWT.DEFAULT || size.y < DWT.DEFAULT) DWT.error(DWT.ERROR_INVALID_ARGUMENT); rightMinWidth = size.x; rightMinHeight = size.y; layout(false); } /** * 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 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 - if width is less than DWT.DEFAULT</li> * </ul> * * @since 3.0 */ public void setRightWidth (int width) { checkWidget(); if (width < DWT.DEFAULT) DWT.error(DWT.ERROR_INVALID_ARGUMENT); rightWidth = width; layout(false); } /** * 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 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.0 */ public void setSimple (bool simple) { checkWidget(); if (this.simple !is simple) { this.simple = simple; if (simple) { curve_width = 5; curve_indent = -2; } else { curve_width = 50; curve_indent = 5; } updateCurve(getSize().y); layout(false); 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); } } }