Mercurial > projects > dwt-mac
diff dwt/graphics/GC.d @ 0:380af2bdd8e5
Upload of whole dwt tree
author | Jacob Carlborg <doob@me.com> <jacob.carlborg@gmail.com> |
---|---|
date | Sat, 09 Aug 2008 17:00:02 +0200 |
parents | |
children | 649b8e223d5a |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dwt/graphics/GC.d Sat Aug 09 17:00:02 2008 +0200 @@ -0,0 +1,3424 @@ +/******************************************************************************* + * 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 + *******************************************************************************/ +module dwt.graphics.GC; + +import dwt.dwthelper.utils; + +import dwt.DWT; +import dwt.DWTError; +import dwt.DWTException; +import dwt.internal.cocoa.NSAffineTransform; +import dwt.internal.cocoa.NSAffineTransformStruct; +import dwt.internal.cocoa.NSAttributedString; +import dwt.internal.cocoa.NSBezierPath; +import dwt.internal.cocoa.NSColor; +import dwt.internal.cocoa.NSFont; +import dwt.internal.cocoa.NSGradient; +import dwt.internal.cocoa.NSGraphicsContext; +import dwt.internal.cocoa.NSImage; +import dwt.internal.cocoa.NSMutableDictionary; +import dwt.internal.cocoa.NSPoint; +import dwt.internal.cocoa.NSRect; +import dwt.internal.cocoa.NSSize; +import dwt.internal.cocoa.NSString; +import dwt.internal.cocoa.OS; + +/** + * Class <code>GC</code> is where all of the drawing capabilities that are + * supported by DWT are located. Instances are used to draw on either an + * <code>Image</code>, a <code>Control</code>, or directly on a <code>Display</code>. + * <dl> + * <dt><b>Styles:</b></dt> + * <dd>LEFT_TO_RIGHT, RIGHT_TO_LEFT</dd> + * </dl> + * + * <p> + * The DWT drawing coordinate system is the two-dimensional space with the origin + * (0,0) at the top left corner of the drawing area and with (x,y) values increasing + * to the right and downward respectively. + * </p> + * + * <p> + * Application code must explicitly invoke the <code>GC.dispose()</code> + * method to release the operating system resources managed by each instance + * when those instances are no longer required. This is <em>particularly</em> + * important on Windows95 and Windows98 where the operating system has a limited + * number of device contexts available. + * </p> + * + * <p> + * Note: Only one of LEFT_TO_RIGHT and RIGHT_TO_LEFT may be specified. + * </p> + * + * @see dwt.events.PaintEvent + */ +public final class GC extends Resource { + /** + * the handle to the OS device context + * (Warning: This field is platform dependent) + * <p> + * <b>IMPORTANT:</b> This field is <em>not</em> part of the DWT + * public API. It is marked public only so that it can be shared + * within the packages provided by DWT. It is not available on all + * platforms and should never be accessed from application code. + * </p> + */ + public NSGraphicsContext handle; + + Drawable drawable; + GCData data; + + static final int TAB_COUNT = 32; + + final static int FOREGROUND = 1 << 0; + final static int BACKGROUND = 1 << 1; + final static int FONT = 1 << 2; + final static int LINE_STYLE = 1 << 3; + final static int LINE_CAP = 1 << 4; + final static int LINE_JOIN = 1 << 5; + final static int LINE_WIDTH = 1 << 6; + final static int LINE_MITERLIMIT = 1 << 7; + final static int FOREGROUND_FILL = 1 << 8; + final static int DRAW_OFFSET = 1 << 9; + final static int CLIPPING = 1 << 10; + final static int TRANSFORM = 1 << 11; + final static int DRAW = CLIPPING | TRANSFORM | FOREGROUND | LINE_WIDTH | LINE_STYLE | LINE_CAP | LINE_JOIN | LINE_MITERLIMIT | DRAW_OFFSET; + final static int FILL = CLIPPING | TRANSFORM | BACKGROUND; + + static final float[] LINE_DOT = new float[]{1, 1}; + static final float[] LINE_DASH = new float[]{3, 1}; + static final float[] LINE_DASHDOT = new float[]{3, 1, 1, 1}; + static final float[] LINE_DASHDOTDOT = new float[]{3, 1, 1, 1, 1, 1}; + static final float[] LINE_DOT_ZERO = new float[]{3, 3}; + static final float[] LINE_DASH_ZERO = new float[]{18, 6}; + static final float[] LINE_DASHDOT_ZERO = new float[]{9, 6, 3, 6}; + static final float[] LINE_DASHDOTDOT_ZERO = new float[]{9, 3, 3, 3, 3, 3}; + +GC() { +} + +/** + * Constructs a new instance of this class which has been + * configured to draw on the specified drawable. Sets the + * foreground color, background color and font in the GC + * to match those in the drawable. + * <p> + * You must dispose the graphics context when it is no longer required. + * </p> + * @param drawable the drawable to draw on + * @exception IllegalArgumentException <ul> + * <li>ERROR_NULL_ARGUMENT - if the drawable is null</li> + * <li>ERROR_NULL_ARGUMENT - if there is no current device</li> + * <li>ERROR_INVALID_ARGUMENT + * - if the drawable is an image that is not a bitmap or an icon + * - if the drawable is an image or printer that is already selected + * into another graphics context</li> + * </ul> + * @exception DWTError <ul> + * <li>ERROR_NO_HANDLES if a handle could not be obtained for GC creation</li> + * <li>ERROR_THREAD_INVALID_ACCESS if not called from the thread that created the drawable</li> + * </ul> + */ +public GC(Drawable drawable) { + this(drawable, 0); +} + +/** + * Constructs a new instance of this class which has been + * configured to draw on the specified drawable. Sets the + * foreground color, background color and font in the GC + * to match those in the drawable. + * <p> + * You must dispose the graphics context when it is no longer required. + * </p> + * + * @param drawable the drawable to draw on + * @param style the style of GC to construct + * + * @exception IllegalArgumentException <ul> + * <li>ERROR_NULL_ARGUMENT - if the drawable is null</li> + * <li>ERROR_NULL_ARGUMENT - if there is no current device</li> + * <li>ERROR_INVALID_ARGUMENT + * - if the drawable is an image that is not a bitmap or an icon + * - if the drawable is an image or printer that is already selected + * into another graphics context</li> + * </ul> + * @exception DWTError <ul> + * <li>ERROR_NO_HANDLES if a handle could not be obtained for GC creation</li> + * <li>ERROR_THREAD_INVALID_ACCESS if not called from the thread that created the drawable</li> + * </ul> + * + * @since 2.1.2 + */ +public GC(Drawable drawable, int style) { + if (drawable is null) DWT.error(DWT.ERROR_NULL_ARGUMENT); + GCData data = new GCData(); + data.style = checkStyle(style); + int contextId = drawable.internal_new_GC(data); + Device device = data.device; + if (device is null) device = Device.getDevice(); + if (device is null) DWT.error(DWT.ERROR_NULL_ARGUMENT); + this.device = data.device = device; + init(drawable, data, contextId); + init(); +} + +static int checkStyle (int style) { + if ((style & DWT.LEFT_TO_RIGHT) !is 0) style &= ~DWT.RIGHT_TO_LEFT; + return style & (DWT.LEFT_TO_RIGHT | DWT.RIGHT_TO_LEFT); +} + +/** + * Invokes platform specific functionality to allocate a new graphics context. + * <p> + * <b>IMPORTANT:</b> This method is <em>not</em> part of the public + * API for <code>GC</code>. It is marked public only so that it + * can be shared within the packages provided by DWT. It is not + * available on all platforms, and should never be called from + * application code. + * </p> + * + * @param drawable the Drawable for the receiver. + * @param data the data for the receiver. + * + * @return a new <code>GC</code> + * + * @private + */ +public static GC cocoa_new(Drawable drawable, GCData data) { + GC gc = new GC(); + int context = drawable.internal_new_GC(data); + gc.device = data.device; + gc.init(drawable, data, context); + return gc; +} + +/** + * Invokes platform specific functionality to wrap a graphics context. + * <p> + * <b>IMPORTANT:</b> This method is <em>not</em> part of the public + * API for <code>GC</code>. It is marked public only so that it + * can be shared within the packages provided by DWT. It is not + * available on all platforms, and should never be called from + * application code. + * </p> + * + * @param context the Quartz context. + * @param data the data for the receiver. + * + * @return a new <code>GC</code> + */ +public static GC carbon_new(int context, GCData data) { + GC gc = new GC(); + gc.device = data.device; + gc.init(null, data, context); + return gc; +} + +void checkGC (int mask) { + if ((data.state & CLIPPING) is 0 || (data.state & TRANSFORM) is 0) { + handle.restoreGraphicsState(); + handle.saveGraphicsState(); + if (data.clipPath !is null) data.clipPath.addClip(); + if (data.transform !is null) data.transform.concat(); + mask &= ~(TRANSFORM | CLIPPING); + data.state |= TRANSFORM | CLIPPING; + data.state &= ~(BACKGROUND | FOREGROUND); + } + + int state = data.state; + if ((state & mask) is mask) return; + state = (state ^ mask) & mask; + data.state |= mask; + + if ((state & FOREGROUND) !is 0) { + Pattern pattern = data.foregroundPattern; + if (pattern !is null) { + if (pattern.color !is null) pattern.color.setStroke(); + } else { + float[] color = data.foreground; + NSColor.colorWithDeviceRed(color[0], color[1], color[2], data.alpha / 255f).setStroke(); + } + } + if ((state & FOREGROUND_FILL) !is 0) { + Pattern pattern = data.foregroundPattern; + if (pattern !is null) { + if (pattern.color !is null) pattern.color.setFill(); + } else { + float[] color = data.foreground; + NSColor.colorWithDeviceRed(color[0], color[1], color[2], data.alpha / 255f).setFill(); + } + data.state &= ~BACKGROUND; + } + if ((state & BACKGROUND) !is 0) { + Pattern pattern = data.backgroundPattern; + if (pattern !is null) { + if (pattern.color !is null) pattern.color.setFill(); + } else { + float[] color = data.background; + NSColor.colorWithDeviceRed(color[0], color[1], color[2], data.alpha / 255f).setFill(); + } + data.state &= ~FOREGROUND_FILL; + } + NSBezierPath path = data.path; + if ((state & LINE_WIDTH) !is 0) { + path.setLineWidth(data.lineWidth is 0 ? 1 : data.lineWidth); + switch (data.lineStyle) { + case DWT.LINE_DOT: + case DWT.LINE_DASH: + case DWT.LINE_DASHDOT: + case DWT.LINE_DASHDOTDOT: + state |= LINE_STYLE; + } + } + if ((state & LINE_STYLE) !is 0) { + float[] dashes = null; + float width = data.lineWidth; + switch (data.lineStyle) { + case DWT.LINE_SOLID: break; + case DWT.LINE_DASH: dashes = width !is 0 ? LINE_DASH : LINE_DASH_ZERO; break; + case DWT.LINE_DOT: dashes = width !is 0 ? LINE_DOT : LINE_DOT_ZERO; break; + case DWT.LINE_DASHDOT: dashes = width !is 0 ? LINE_DASHDOT : LINE_DASHDOT_ZERO; break; + case DWT.LINE_DASHDOTDOT: dashes = width !is 0 ? LINE_DASHDOTDOT : LINE_DASHDOTDOT_ZERO; break; + case DWT.LINE_CUSTOM: dashes = data.lineDashes; break; + } + if (dashes !is null) { + float[] lengths = new float[dashes.length]; + for (int i = 0; i < lengths.length; i++) { + lengths[i] = width is 0 || data.lineStyle is DWT.LINE_CUSTOM ? dashes[i] : dashes[i] * width; + } + path.setLineDash(lengths, lengths.length, data.lineDashesOffset); + } else { + path.setLineDash(null, 0, 0); + } + } + if ((state & LINE_MITERLIMIT) !is 0) { + path.setMiterLimit(data.lineMiterLimit); + } + if ((state & LINE_JOIN) !is 0) { + int joinStyle = 0; + switch (data.lineJoin) { + case DWT.JOIN_MITER: joinStyle = OS.NSMiterLineJoinStyle; break; + case DWT.JOIN_ROUND: joinStyle = OS.NSRoundLineJoinStyle; break; + case DWT.JOIN_BEVEL: joinStyle = OS.NSBevelLineJoinStyle; break; + } + path.setLineJoinStyle(joinStyle); + } + if ((state & LINE_CAP) !is 0) { + int capStyle = 0; + switch (data.lineCap) { + case DWT.CAP_ROUND: capStyle = OS.NSRoundLineCapStyle; break; + case DWT.CAP_FLAT: capStyle = OS.NSButtLineCapStyle; break; + case DWT.CAP_SQUARE: capStyle = OS.NSSquareLineCapStyle; break; + } + path.setLineCapStyle(capStyle); + } + if ((state & DRAW_OFFSET) !is 0) { + data.drawXOffset = data.drawYOffset = 0; + NSSize size = new NSSize(); + size.width = size.height = 1; + if (data.transform !is null) { + size = data.transform.transformSize(size); + } + float scaling = size.width; + if (scaling < 0) scaling = -scaling; + float strokeWidth = data.lineWidth * scaling; + if (strokeWidth is 0 || ((int)strokeWidth % 2) is 1) { + data.drawXOffset = 0.5f / scaling; + } + scaling = size.height; + if (scaling < 0) scaling = -scaling; + strokeWidth = data.lineWidth * scaling; + if (strokeWidth is 0 || ((int)strokeWidth % 2) is 1) { + data.drawYOffset = 0.5f / scaling; + } + } +} + +/** + * Copies a rectangular area of the receiver at the specified + * position into the image, which must be of type <code>DWT.BITMAP</code>. + * + * @param image the image to copy into + * @param x the x coordinate in the receiver of the area to be copied + * @param y the y coordinate in the receiver of the area to be copied + * + * @exception IllegalArgumentException <ul> + * <li>ERROR_NULL_ARGUMENT - if the image is null</li> + * <li>ERROR_INVALID_ARGUMENT - if the image is not a bitmap or has been disposed</li> + * </ul> + * @exception DWTException <ul> + * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> + * </ul> + */ +public void copyArea(Image image, int x, int y) { + if (handle is null) DWT.error(DWT.ERROR_GRAPHIC_DISPOSED); + if (image is null) DWT.error(DWT.ERROR_NULL_ARGUMENT); + if (image.type !is DWT.BITMAP || image.isDisposed()) DWT.error(DWT.ERROR_INVALID_ARGUMENT); +// if (data.image !is null) { +// copyArea(image, x, y, data.image.handle); +// } else if (data.control !is 0) { +// int imageHandle = image.handle; +// int width = OS.CGImageGetWidth(imageHandle); +// int height = OS.CGImageGetHeight(imageHandle); +// int window = OS.GetControlOwner(data.control); +// Rect srcRect = new Rect (); +// CGPoint pt = new CGPoint (); +// int[] contentView = new int[1]; +// OS.HIViewFindByID(OS.HIViewGetRoot(window), OS.kHIViewWindowContentID(), contentView); +// OS.HIViewConvertPoint (pt, data.control, contentView[0]); +// x += (int) pt.x; +// y += (int) pt.y; +// Rect inset = data.insetRect; +// x -= inset.left; +// y -= inset.top; +// srcRect.left = (short)x; +// srcRect.top = (short)y; +// srcRect.right = (short)(x + width); +// srcRect.bottom = (short)(y + height); +// Rect destRect = new Rect(); +// destRect.right = (short)width; +// destRect.bottom = (short)height; +// int bpl = width * 4; +// int[] gWorld = new int[1]; +// int port = OS.GetWindowPort(window); +// OS.NewGWorldFromPtr(gWorld, OS.k32ARGBPixelFormat, destRect, 0, 0, 0, image.data, bpl); +// OS.CopyBits(OS.GetPortBitMapForCopyBits(port), OS.GetPortBitMapForCopyBits(gWorld[0]), srcRect, destRect, (short)OS.srcCopy, 0); +// OS.DisposeGWorld(gWorld [0]); +// } else if (data.window !is 0) { +// int imageHandle = image.handle; +// CGRect rect = new CGRect(); +// rect.x = x; +// rect.y = y; +// rect.width = OS.CGImageGetWidth(imageHandle); +// rect.height = OS.CGImageGetHeight(imageHandle); +// int[] displays = new int[16]; +// int[] count = new int[1]; +// if (OS.CGGetDisplaysWithRect(rect, displays.length, displays, count) !is 0) return; +// for (int i = 0; i < count[0]; i++) { +// int display = displays[i]; +// int address = OS.CGDisplayBaseAddress(display); +// if (address !is 0) { +// int width = OS.CGDisplayPixelsWide(display); +// int height = OS.CGDisplayPixelsHigh(display); +// int bpr = OS.CGDisplayBytesPerRow(display); +// int bpp = OS.CGDisplayBitsPerPixel(display); +// int bps = OS.CGDisplayBitsPerSample(display); +// int bitmapInfo = OS.kCGImageAlphaNoneSkipFirst; +// switch (bpp) { +// case 16: bitmapInfo |= OS.kCGBitmapByteOrder16Host; break; +// case 32: bitmapInfo |= OS.kCGBitmapByteOrder32Host; break; +// } +// int srcImage = 0; +// if (OS.__BIG_ENDIAN__() && OS.VERSION >= 0x1040) { +// int context = OS.CGBitmapContextCreate(address, width, height, bps, bpr, data.device.colorspace, bitmapInfo); +// srcImage = OS.CGBitmapContextCreateImage(context); +// OS.CGContextRelease(context); +// } else { +// int provider = OS.CGDataProviderCreateWithData(0, address, bpr * height, 0); +// srcImage = OS.CGImageCreate(width, height, bps, bpp, bpr, data.device.colorspace, bitmapInfo, provider, null, true, 0); +// OS.CGDataProviderRelease(provider); +// } +// copyArea(image, x, y, srcImage); +// if (srcImage !is 0) OS.CGImageRelease(srcImage); +// } +// } +// } +} + +void copyArea (Image image, int x, int y, int srcImage) { + if (srcImage is 0) return; +// int imageHandle = image.handle; +// int bpc = OS.CGImageGetBitsPerComponent(imageHandle); +// int width = OS.CGImageGetWidth(imageHandle); +// int height = OS.CGImageGetHeight(imageHandle); +// int bpr = OS.CGImageGetBytesPerRow(imageHandle); +// int alphaInfo = OS.CGImageGetAlphaInfo(imageHandle); +// int context = OS.CGBitmapContextCreate(image.data, width, height, bpc, bpr, data.device.colorspace, alphaInfo); +// if (context !is 0) { +// CGRect rect = new CGRect(); +// rect.x = -x; +// rect.y = y; +// rect.width = OS.CGImageGetWidth(srcImage); +// rect.height = OS.CGImageGetHeight(srcImage); +// OS.CGContextTranslateCTM(context, 0, -(rect.height - height)); +// OS.CGContextDrawImage(context, rect, srcImage); +// OS.CGContextRelease(context); +// } +} + +/** + * Copies a rectangular area of the receiver at the source + * position onto the receiver at the destination position. + * + * @param srcX the x coordinate in the receiver of the area to be copied + * @param srcY the y coordinate in the receiver of the area to be copied + * @param width the width of the area to copy + * @param height the height of the area to copy + * @param destX the x coordinate in the receiver of the area to copy to + * @param destY the y coordinate in the receiver of the area to copy to + * + * @exception DWTException <ul> + * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> + * </ul> + */ +public void copyArea(int srcX, int srcY, int width, int height, int destX, int destY) { + copyArea(srcX, srcY, width, height, destX, destY, true); +} +/** + * Copies a rectangular area of the receiver at the source + * position onto the receiver at the destination position. + * + * @param srcX the x coordinate in the receiver of the area to be copied + * @param srcY the y coordinate in the receiver of the area to be copied + * @param width the width of the area to copy + * @param height the height of the area to copy + * @param destX the x coordinate in the receiver of the area to copy to + * @param destY the y coordinate in the receiver of the area to copy to + * @param paint if <code>true</code> paint events will be generated for old and obscured areas + * + * @exception DWTException <ul> + * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> + * </ul> + * + * @since 3.1 + */ +public void copyArea(int srcX, int srcY, int width, int height, int destX, int destY, bool paint) { +// if (handle is 0) DWT.error(DWT.ERROR_GRAPHIC_DISPOSED); +// if (data.updateClip) setCGClipping(); +// if (width <= 0 || height <= 0) return; +// int deltaX = destX - srcX, deltaY = destY - srcY; +// if (deltaX is 0 && deltaY is 0) return; +// if (data.image !is null) { +// OS.CGContextSaveGState(handle); +// OS.CGContextScaleCTM(handle, 1, -1); +// OS.CGContextTranslateCTM(handle, 0, -(height + 2 * destY)); +// CGRect rect = new CGRect(); +// rect.x = destX; +// rect.y = destY; +// rect.width = width; +// rect.height = height; +// int h = OS.CGImageGetHeight(data.image.handle); +// int bpr = OS.CGImageGetBytesPerRow(data.image.handle); +// int provider = OS.CGDataProviderCreateWithData(0, data.image.data, bpr * h, 0); +// if (provider !is 0) { +// int colorspace = device.colorspace; +// int img = OS.CGImageCreate(width, height, 8, 32, bpr, colorspace, OS.kCGImageAlphaNoneSkipFirst, provider, null, true, 0); +// OS.CGDataProviderRelease(provider); +// OS.CGContextDrawImage(handle, rect, img); +// OS.CGImageRelease(img); +// } +// OS.CGContextRestoreGState(handle); +// return; +// } +// if (data.control !is 0) { +// int port = data.port; +// int window = OS.GetControlOwner(data.control); +// if (port is 0) port = OS.GetWindowPort(window); +// +// /* Calculate src and dest rectangles/regions */ +// Rect rect = new Rect(); +// OS.GetControlBounds(data.control, rect); +// int convertX = 0, convertY = 0; +// CGPoint pt = new CGPoint (); +// int[] contentView = new int[1]; +// OS.HIViewFindByID(OS.HIViewGetRoot(window), OS.kHIViewWindowContentID(), contentView); +// OS.HIViewConvertPoint(pt, OS.HIViewGetSuperview(data.control), contentView[0]); +// convertX = rect.left + (int) pt.x; +// convertY = rect.top + (int) pt.y; +// rect.left += (int) pt.x; +// rect.top += (int) pt.y; +// rect.right += (int) pt.x; +// rect.bottom += (int) pt.y; +// Rect srcRect = new Rect(); +// int left = rect.left + srcX; +// int top = rect.top + srcY; +// OS.SetRect(srcRect, (short)left, (short)top, (short)(left + width), (short)(top + height)); +// int srcRgn = OS.NewRgn(); +// OS.RectRgn(srcRgn, srcRect); +// OS.SectRect(rect, srcRect, srcRect); +// Rect destRect = new Rect (); +// OS.SetRect(destRect, srcRect.left, srcRect.top, srcRect.right, srcRect.bottom); +// OS.OffsetRect(destRect, (short)deltaX, (short)deltaY); +// int destRgn = OS.NewRgn(); +// OS.RectRgn(destRgn, destRect); +// +// /* Copy bits with appropriated clipping region */ +// if (!OS.EmptyRect(srcRect)) { +// if (data.visibleRgn is 0 || OS.RectInRgn(srcRect, data.visibleRgn)) { +// int clipRgn = data.visibleRgn; +// if (data.clipRgn !is 0) { +// clipRgn = OS.NewRgn(); +// OS.SectRgn(data.clipRgn, data.visibleRgn, clipRgn); +// } +// +// /* +// * Feature in the Macintosh. ScrollRect() only copies bits +// * that are inside the specified rectangle. This means that +// * it is not possible to copy non overlaping bits without +// * copying the bits in between the source and destination +// * rectangles. The fix is to check if the source and +// * destination rectangles are disjoint and use CopyBits() +// * instead. +// */ +// if (!OS.EmptyRgn(clipRgn)) { +// bool disjoint = (destX + width < srcX) || (srcX + width < destX) || (destY + height < srcY) || (srcY + height < destY); +// if (!disjoint && (deltaX is 0 || deltaY is 0)) { +// int[] currentPort = new int[1]; +// OS.GetPort(currentPort); +// OS.SetPort(port); +// int oldClip = OS.NewRgn(); +// OS.GetClip(oldClip); +// OS.SetClip(clipRgn); +// OS.UnionRect(srcRect, destRect, rect); +// OS.ScrollRect(rect, (short)deltaX, (short)deltaY, 0); +// OS.SetClip(oldClip); +// OS.DisposeRgn(oldClip); +// OS.SetPort(currentPort[0]); +// } else { +// int portBitMap = OS.GetPortBitMapForCopyBits (port); +// OS.CopyBits(portBitMap, portBitMap, srcRect, destRect, (short)OS.srcCopy, clipRgn); +// OS.QDFlushPortBuffer(port, destRgn); +// } +// } +// +// if (clipRgn !is data.visibleRgn) OS.DisposeRgn(clipRgn); +// } +// } +// +// /* Invalidate src and obscured areas */ +// if (paint) { +// int invalRgn = OS.NewRgn(); +// OS.DiffRgn(srcRgn, data.visibleRgn, invalRgn); +// OS.OffsetRgn(invalRgn, (short)deltaX, (short)deltaY); +// OS.DiffRgn(srcRgn, destRgn, srcRgn); +// OS.UnionRgn(srcRgn, invalRgn, invalRgn); +// OS.SectRgn(data.visibleRgn, invalRgn, invalRgn); +// OS.OffsetRgn(invalRgn, (short)-convertX, (short)-convertY); +// OS.HIViewSetNeedsDisplayInRegion(data.control, invalRgn, true); +// OS.DisposeRgn(invalRgn); +// } +// +// /* Dispose src and dest regions */ +// OS.DisposeRgn(destRgn); +// OS.DisposeRgn(srcRgn); +// } +} + +NSAttributedString createString(String string, int flags) { + NSMutableDictionary dict = NSMutableDictionary.dictionaryWithCapacity(4); + float[] foreground = data.foreground; + NSColor color = NSColor.colorWithDeviceRed(foreground[0], foreground[1], foreground[2], data.alpha / 255f); + dict.setObject(color, OS.NSForegroundColorAttributeName()); + dict.setObject(data.font.handle, OS.NSFontAttributeName()); + if ((flags & DWT.DRAW_TRANSPARENT) is 0) { + float[] background = data.background; + color = NSColor.colorWithDeviceRed(background[0], background[1], background[2], data.alpha / 255f); + dict.setObject(color, OS.NSBackgroundColorAttributeName()); + } + int length = string.length(); + char[] chars = new char[length]; + string.getChars(0, length, chars, 0); +// int breakCount = 0; +// int[] breaks = null; +// if ((flags & (DWT.DRAW_MNEMONIC | DWT.DRAW_DELIMITER)) !is 0) { +// int i=0, j=0; +// while (i < chars.length) { +// char c = chars [j++] = chars [i++]; +// switch (c) { +// case '&': { +// if ((flags & DWT.DRAW_MNEMONIC) !is 0) { +// if (i is chars.length) {continue;} +// if (chars [i] is '&') {i++; continue;} +// j--; +// } +// break; +// } +// case '\r': +// case '\n': { +// if ((flags & DWT.DRAW_DELIMITER) !is 0) { +// if (c is '\r' && i !is chars.length && chars[i] is '\n') i++; +// j--; +// if (breaks is null) { +// breaks = new int[4]; +// } else if (breakCount is breaks.length) { +// int[] newBreaks = new int[breaks.length + 4]; +// System.arraycopy(breaks, 0, newBreaks, 0, breaks.length); +// breaks = newBreaks; +// } +// breaks[breakCount++] = j; +// } +// break; +// } +// } +// } +// length = j; +// } + NSString str = NSString.stringWithCharacters(chars, length); + return ((NSAttributedString)new NSAttributedString().alloc()).initWithString_attributes_(str, dict); +} + +void destroy() { + /* Free resources */ + Image image = data.image; + if (image !is null) { + image.memGC = null; + image.createAlpha(); + } + if (data.clipPath !is null) data.clipPath.release(); + if (data.transform !is null) data.transform.release(); + if (data.inverseTransform !is null) data.inverseTransform.release(); + data.path = data.clipPath = null; + data.transform = data.inverseTransform = null; + + /* Dispose the GC */ + if (drawable !is null) drawable.internal_dispose_GC(handle.id, data); + handle.restoreGraphicsState(); + handle.release(); + + drawable = null; + data.image = null; + data = null; + handle = null; +} + +/** + * Draws the outline of a circular or elliptical arc + * within the specified rectangular area. + * <p> + * The resulting arc begins at <code>startAngle</code> and extends + * for <code>arcAngle</code> degrees, using the current color. + * Angles are interpreted such that 0 degrees is at the 3 o'clock + * position. A positive value indicates a counter-clockwise rotation + * while a negative value indicates a clockwise rotation. + * </p><p> + * The center of the arc is the center of the rectangle whose origin + * is (<code>x</code>, <code>y</code>) and whose size is specified by the + * <code>width</code> and <code>height</code> arguments. + * </p><p> + * The resulting arc covers an area <code>width + 1</code> pixels wide + * by <code>height + 1</code> pixels tall. + * </p> + * + * @param x the x coordinate of the upper-left corner of the arc to be drawn + * @param y the y coordinate of the upper-left corner of the arc to be drawn + * @param width the width of the arc to be drawn + * @param height the height of the arc to be drawn + * @param startAngle the beginning angle + * @param arcAngle the angular extent of the arc, relative to the start angle + * + * @exception DWTException <ul> + * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> + * </ul> + */ +public void drawArc(int x, int y, int width, int height, int startAngle, int arcAngle) { + if (handle is null) DWT.error(DWT.ERROR_GRAPHIC_DISPOSED); + NSGraphicsContext context = NSGraphicsContext.currentContext(); + NSGraphicsContext.setCurrentContext(handle); + checkGC(DRAW); + if (width < 0) { + x = x + width; + width = -width; + } + if (height < 0) { + y = y + height; + height = -height; + } + if (width is 0 || height is 0 || arcAngle is 0) return; + handle.saveGraphicsState(); + NSAffineTransform transform = NSAffineTransform.transform(); + float xOffset = data.drawXOffset, yOffset = data.drawYOffset; + transform.translateXBy(x + xOffset + width / 2f, y + yOffset + height / 2f); + transform.scaleXBy(width / 2f, height / 2f); + NSBezierPath path = data.path; + NSPoint center = new NSPoint(); + float sAngle = -startAngle; + float eAngle = -(startAngle + arcAngle); + path.appendBezierPathWithArcWithCenter_radius_startAngle_endAngle_clockwise_(center, 1, sAngle, eAngle, arcAngle>0); + path.transformUsingAffineTransform(transform); + path.stroke(); + path.removeAllPoints(); + handle.restoreGraphicsState(); + NSGraphicsContext.setCurrentContext(context); +} + +/** + * Draws a rectangle, based on the specified arguments, which has + * the appearance of the platform's <em>focus rectangle</em> if the + * platform supports such a notion, and otherwise draws a simple + * rectangle in the receiver's foreground color. + * + * @param x the x coordinate of the rectangle + * @param y the y coordinate of the rectangle + * @param width the width of the rectangle + * @param height the height of the rectangle + * + * @exception DWTException <ul> + * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> + * </ul> + * + * @see #drawRectangle(int, int, int, int) + */ +public void drawFocus(int x, int y, int width, int height) { + if (handle is null) DWT.error(DWT.ERROR_GRAPHIC_DISPOSED); + NSGraphicsContext context = NSGraphicsContext.currentContext(); + NSGraphicsContext.setCurrentContext(handle); + checkGC(CLIPPING | TRANSFORM); +// int[] metric = new int[1]; +// OS.GetThemeMetric(OS.kThemeMetricFocusRectOutset, metric); +// CGRect rect = new CGRect (); +// rect.x = x + metric[0]; +// rect.y = y + metric[0]; +// rect.width = width - metric[0] * 2; +// rect.height = height - metric[0] * 2; +// OS.HIThemeDrawFocusRect(rect, true, handle, OS.kHIThemeOrientationNormal); +// flush(); + NSGraphicsContext.setCurrentContext(context); +} + +/** + * Draws the given image in the receiver at the specified + * coordinates. + * + * @param image the image to draw + * @param x the x coordinate of where to draw + * @param y the y coordinate of where to draw + * + * @exception IllegalArgumentException <ul> + * <li>ERROR_NULL_ARGUMENT - if the image is null</li> + * <li>ERROR_INVALID_ARGUMENT - if the image has been disposed</li> + * <li>ERROR_INVALID_ARGUMENT - if the given coordinates are outside the bounds of the image</li> + * @exception DWTException <ul> + * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> + * </ul> + * @exception DWTError <ul> + * <li>ERROR_NO_HANDLES - if no handles are available to perform the operation</li> + * </ul> + */ +public void drawImage(Image image, int x, int y) { + if (handle is null) DWT.error(DWT.ERROR_GRAPHIC_DISPOSED); + if (image is null) DWT.error(DWT.ERROR_NULL_ARGUMENT); + if (image.isDisposed()) DWT.error(DWT.ERROR_INVALID_ARGUMENT); + drawImage(image, 0, 0, -1, -1, x, y, -1, -1, true); +} + +/** + * Copies a rectangular area from the source image into a (potentially + * different sized) rectangular area in the receiver. If the source + * and destination areas are of differing sizes, then the source + * area will be stretched or shrunk to fit the destination area + * as it is copied. The copy fails if any part of the source rectangle + * lies outside the bounds of the source image, or if any of the width + * or height arguments are negative. + * + * @param image the source image + * @param srcX the x coordinate in the source image to copy from + * @param srcY the y coordinate in the source image to copy from + * @param srcWidth the width in pixels to copy from the source + * @param srcHeight the height in pixels to copy from the source + * @param destX the x coordinate in the destination to copy to + * @param destY the y coordinate in the destination to copy to + * @param destWidth the width in pixels of the destination rectangle + * @param destHeight the height in pixels of the destination rectangle + * + * @exception IllegalArgumentException <ul> + * <li>ERROR_NULL_ARGUMENT - if the image is null</li> + * <li>ERROR_INVALID_ARGUMENT - if the image has been disposed</li> + * <li>ERROR_INVALID_ARGUMENT - if any of the width or height arguments are negative. + * <li>ERROR_INVALID_ARGUMENT - if the source rectangle is not contained within the bounds of the source image</li> + * </ul> + * @exception DWTException <ul> + * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> + * </ul> + * @exception DWTError <ul> + * <li>ERROR_NO_HANDLES - if no handles are available to perform the operation</li> + * </ul> + */ +public void drawImage(Image image, int srcX, int srcY, int srcWidth, int srcHeight, int destX, int destY, int destWidth, int destHeight) { + if (handle is null) DWT.error(DWT.ERROR_GRAPHIC_DISPOSED); + if (srcWidth is 0 || srcHeight is 0 || destWidth is 0 || destHeight is 0) return; + if (srcX < 0 || srcY < 0 || srcWidth < 0 || srcHeight < 0 || destWidth < 0 || destHeight < 0) { + DWT.error (DWT.ERROR_INVALID_ARGUMENT); + } + if (image is null) DWT.error(DWT.ERROR_NULL_ARGUMENT); + if (image.isDisposed()) DWT.error(DWT.ERROR_INVALID_ARGUMENT); + drawImage(image, srcX, srcY, srcWidth, srcHeight, destX, destY, destWidth, destHeight, false); +} + +void drawImage(Image srcImage, int srcX, int srcY, int srcWidth, int srcHeight, int destX, int destY, int destWidth, int destHeight, bool simple) { + NSGraphicsContext context = NSGraphicsContext.currentContext(); + NSGraphicsContext.setCurrentContext(handle); + checkGC(CLIPPING | TRANSFORM); + NSImage imageHandle = srcImage.handle; + NSSize size = imageHandle.size(); + int imgWidth = (int)size.width; + int imgHeight = (int)size.height; + if (simple) { + srcWidth = destWidth = imgWidth; + srcHeight = destHeight = imgHeight; + } else { + simple = srcX is 0 && srcY is 0 && + srcWidth is destWidth && destWidth is imgWidth && + srcHeight is destHeight && destHeight is imgHeight; + if (srcX + srcWidth > imgWidth || srcY + srcHeight > imgHeight) { + NSGraphicsContext.setCurrentContext(context); + DWT.error(DWT.ERROR_INVALID_ARGUMENT); + } + } + if (srcImage.memGC !is null) srcImage.createAlpha(); + handle.saveGraphicsState(); + NSAffineTransform transform = NSAffineTransform.transform(); + transform.scaleXBy(1, -1); + transform.translateXBy(0, -(destHeight + 2 * destY)); + transform.concat(); + NSRect srcRect = new NSRect(); + srcRect.x = srcX; + srcRect.y = srcY; + srcRect.width = srcWidth; + srcRect.height = srcHeight; + NSRect destRect = new NSRect(); + destRect.x = destX; + destRect.y = destY; + destRect.width = destWidth; + destRect.height = destHeight; + imageHandle.drawInRect(destRect, srcRect, OS.NSCompositeSourceOver, 1); + handle.restoreGraphicsState(); + NSGraphicsContext.setCurrentContext(context); +} + +/** + * Draws a line, using the foreground color, between the points + * (<code>x1</code>, <code>y1</code>) and (<code>x2</code>, <code>y2</code>). + * + * @param x1 the first point's x coordinate + * @param y1 the first point's y coordinate + * @param x2 the second point's x coordinate + * @param y2 the second point's y coordinate + * + * @exception DWTException <ul> + * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> + * </ul> + */ +public void drawLine(int x1, int y1, int x2, int y2) { + if (handle is null) DWT.error(DWT.ERROR_GRAPHIC_DISPOSED); + NSGraphicsContext context = NSGraphicsContext.currentContext(); + NSGraphicsContext.setCurrentContext(handle); + checkGC(DRAW); + NSBezierPath path = data.path; + NSPoint pt = new NSPoint(); + pt.x = x1 + data.drawXOffset; + pt.y = y1 + data.drawYOffset; + path.moveToPoint(pt); + pt.x = x2 + data.drawXOffset; + pt.y = y2 + data.drawYOffset; + path.lineToPoint(pt); + path.stroke(); + path.removeAllPoints(); + NSGraphicsContext.setCurrentContext(context); +} + +/** + * Draws the outline of an oval, using the foreground color, + * within the specified rectangular area. + * <p> + * The result is a circle or ellipse that fits within the + * rectangle specified by the <code>x</code>, <code>y</code>, + * <code>width</code>, and <code>height</code> arguments. + * </p><p> + * The oval covers an area that is <code>width + 1</code> + * pixels wide and <code>height + 1</code> pixels tall. + * </p> + * + * @param x the x coordinate of the upper left corner of the oval to be drawn + * @param y the y coordinate of the upper left corner of the oval to be drawn + * @param width the width of the oval to be drawn + * @param height the height of the oval to be drawn + * + * @exception DWTException <ul> + * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> + * </ul> + */ +public void drawOval(int x, int y, int width, int height) { + if (handle is null) DWT.error(DWT.ERROR_GRAPHIC_DISPOSED); + NSGraphicsContext context = NSGraphicsContext.currentContext(); + NSGraphicsContext.setCurrentContext(handle); + checkGC(DRAW); + if (width < 0) { + x = x + width; + width = -width; + } + if (height < 0) { + y = y + height; + height = -height; + } + NSBezierPath path = data.path; + NSRect rect = new NSRect(); + rect.x = x + data.drawXOffset; + rect.y = y + data.drawXOffset; + rect.width = width; + rect.height = height; + path.appendBezierPathWithOvalInRect(rect); + path.stroke(); + path.removeAllPoints(); + NSGraphicsContext.setCurrentContext(context); +} + +/** + * Draws the path described by the parameter. + * <p> + * This operation requires the operating system's advanced + * graphics subsystem which may not be available on some + * platforms. + * </p> + * + * @param path the path to draw + * + * @exception IllegalArgumentException <ul> + * <li>ERROR_NULL_ARGUMENT - if the parameter is null</li> + * <li>ERROR_INVALID_ARGUMENT - if the parameter has been disposed</li> + * </ul> + * @exception DWTException <ul> + * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> + * <li>ERROR_NO_GRAPHICS_LIBRARY - if advanced graphics are not available</li> + * </ul> + * + * @see Path + * + * @since 3.1 + */ +public void drawPath(Path path) { + if (handle is null) DWT.error(DWT.ERROR_GRAPHIC_DISPOSED); + if (path is null) DWT.error(DWT.ERROR_NULL_ARGUMENT); + if (path.handle is null) DWT.error(DWT.ERROR_INVALID_ARGUMENT); + NSGraphicsContext context = NSGraphicsContext.currentContext(); + NSGraphicsContext.setCurrentContext(handle); + checkGC(DRAW); + handle.saveGraphicsState(); + NSAffineTransform transform = NSAffineTransform.transform(); + transform.translateXBy(data.drawXOffset, data.drawYOffset); + transform.concat(); + NSBezierPath drawPath = data.path; + drawPath.appendBezierPath(path.handle); + drawPath.stroke(); + drawPath.removeAllPoints(); + handle.restoreGraphicsState(); + NSGraphicsContext.setCurrentContext(context); +} + +/** + * Draws a pixel, using the foreground color, at the specified + * point (<code>x</code>, <code>y</code>). + * <p> + * Note that the receiver's line attributes do not affect this + * operation. + * </p> + * + * @param x the point's x coordinate + * @param y the point's y coordinate + * + * @exception DWTException <ul> + * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> + * </ul> + * + * @since 3.0 + */ +public void drawPoint(int x, int y) { + if (handle is null) DWT.error(DWT.ERROR_GRAPHIC_DISPOSED); + NSGraphicsContext context = NSGraphicsContext.currentContext(); + NSGraphicsContext.setCurrentContext(handle); + checkGC(FOREGROUND_FILL); + NSRect rect = new NSRect(); + rect.x = x; + rect.y = y; + rect.width = 1; + rect.height = 1; + NSBezierPath path = data.path; + path.appendBezierPathWithRect(rect); + path.fill(); + path.removeAllPoints(); + NSGraphicsContext.setCurrentContext(context); +} + +/** + * Draws the closed polygon which is defined by the specified array + * of integer coordinates, using the receiver's foreground color. The array + * contains alternating x and y values which are considered to represent + * points which are the vertices of the polygon. Lines are drawn between + * each consecutive pair, and between the first pair and last pair in the + * array. + * + * @param pointArray an array of alternating x and y values which are the vertices of the polygon + * + * @exception IllegalArgumentException <ul> + * <li>ERROR_NULL_ARGUMENT if pointArray is null</li> + * </ul> + * @exception DWTException <ul> + * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> + * </ul> + */ +public void drawPolygon(int[] pointArray) { + if (handle is null) DWT.error(DWT.ERROR_GRAPHIC_DISPOSED); + if (pointArray is null) DWT.error(DWT.ERROR_NULL_ARGUMENT); + NSGraphicsContext context = NSGraphicsContext.currentContext(); + NSGraphicsContext.setCurrentContext(handle); + checkGC(DRAW); + if (pointArray.length < 4) return; + float xOffset = data.drawXOffset, yOffset = data.drawYOffset; + NSBezierPath path = data.path; + NSPoint pt = new NSPoint(); + pt.x = pointArray[0] + xOffset; + pt.y = pointArray[1] + yOffset; + path.moveToPoint(pt); + int end = pointArray.length / 2 * 2; + for (int i = 2; i < end; i+=2) { + pt.x = pointArray[i] + xOffset; + pt.y = pointArray[i+1] + yOffset; + path.lineToPoint(pt); + } + path.closePath(); + path.stroke(); + path.removeAllPoints(); + NSGraphicsContext.setCurrentContext(context); +} + +/** + * Draws the polyline which is defined by the specified array + * of integer coordinates, using the receiver's foreground color. The array + * contains alternating x and y values which are considered to represent + * points which are the corners of the polyline. Lines are drawn between + * each consecutive pair, but not between the first pair and last pair in + * the array. + * + * @param pointArray an array of alternating x and y values which are the corners of the polyline + * + * @exception IllegalArgumentException <ul> + * <li>ERROR_NULL_ARGUMENT - if the point array is null</li> + * </ul> + * @exception DWTException <ul> + * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> + * </ul> + */ +public void drawPolyline(int[] pointArray) { + if (handle is null) DWT.error(DWT.ERROR_GRAPHIC_DISPOSED); + if (pointArray is null) DWT.error(DWT.ERROR_NULL_ARGUMENT); + NSGraphicsContext context = NSGraphicsContext.currentContext(); + NSGraphicsContext.setCurrentContext(handle); + checkGC(DRAW); + if (pointArray.length < 4) return; + float xOffset = data.drawXOffset, yOffset = data.drawYOffset; + NSBezierPath path = data.path; + NSPoint pt = new NSPoint(); + pt.x = pointArray[0] + xOffset; + pt.y = pointArray[1] + yOffset; + path.moveToPoint(pt); + int end = pointArray.length / 2 * 2; + for (int i = 2; i < end; i+=2) { + pt.x = pointArray[i] + xOffset; + pt.y = pointArray[i+1] + yOffset; + path.lineToPoint(pt); + } + path.stroke(); + path.removeAllPoints(); + NSGraphicsContext.setCurrentContext(context); +} + +/** + * Draws the outline of the rectangle specified by the arguments, + * using the receiver's foreground color. The left and right edges + * of the rectangle are at <code>x</code> and <code>x + width</code>. + * The top and bottom edges are at <code>y</code> and <code>y + height</code>. + * + * @param x the x coordinate of the rectangle to be drawn + * @param y the y coordinate of the rectangle to be drawn + * @param width the width of the rectangle to be drawn + * @param height the height of the rectangle to be drawn + * + * @exception DWTException <ul> + * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> + * </ul> + */ +public void drawRectangle(int x, int y, int width, int height) { + if (handle is null) DWT.error(DWT.ERROR_GRAPHIC_DISPOSED); + NSGraphicsContext context = NSGraphicsContext.currentContext(); + NSGraphicsContext.setCurrentContext(handle); + checkGC(DRAW); + if (width < 0) { + x = x + width; + width = -width; + } + if (height < 0) { + y = y + height; + height = -height; + } + NSRect rect = new NSRect(); + rect.x = x + data.drawXOffset; + rect.y = y + data.drawYOffset; + rect.width = width; + rect.height = height; + NSBezierPath path = data.path; + path.appendBezierPathWithRect(rect); + path.stroke(); + path.removeAllPoints(); + NSGraphicsContext.setCurrentContext(context); +} + +/** + * Draws the outline of the specified rectangle, using the receiver's + * foreground color. The left and right edges of the rectangle are at + * <code>rect.x</code> and <code>rect.x + rect.width</code>. The top + * and bottom edges are at <code>rect.y</code> and + * <code>rect.y + rect.height</code>. + * + * @param rect the rectangle to draw + * + * @exception IllegalArgumentException <ul> + * <li>ERROR_NULL_ARGUMENT - if the rectangle is null</li> + * </ul> + * @exception DWTException <ul> + * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> + * </ul> + */ +public void drawRectangle(Rectangle rect) { + if (handle is null) DWT.error(DWT.ERROR_GRAPHIC_DISPOSED); + if (rect is null) DWT.error(DWT.ERROR_NULL_ARGUMENT); + drawRectangle (rect.x, rect.y, rect.width, rect.height); +} + +/** + * Draws the outline of the round-cornered rectangle specified by + * the arguments, using the receiver's foreground color. The left and + * right edges of the rectangle are at <code>x</code> and <code>x + width</code>. + * The top and bottom edges are at <code>y</code> and <code>y + height</code>. + * The <em>roundness</em> of the corners is specified by the + * <code>arcWidth</code> and <code>arcHeight</code> arguments, which + * are respectively the width and height of the ellipse used to draw + * the corners. + * + * @param x the x coordinate of the rectangle to be drawn + * @param y the y coordinate of the rectangle to be drawn + * @param width the width of the rectangle to be drawn + * @param height the height of the rectangle to be drawn + * @param arcWidth the width of the arc + * @param arcHeight the height of the arc + * + * @exception DWTException <ul> + * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> + * </ul> + */ +public void drawRoundRectangle(int x, int y, int width, int height, int arcWidth, int arcHeight) { + if (handle is null) DWT.error(DWT.ERROR_GRAPHIC_DISPOSED); + NSGraphicsContext context = NSGraphicsContext.currentContext(); + NSGraphicsContext.setCurrentContext(handle); + checkGC(DRAW); + if (arcWidth is 0 || arcHeight is 0) { + drawRectangle(x, y, width, height); + NSGraphicsContext.setCurrentContext(context); + return; + } + NSBezierPath path = data.path; + NSRect rect = new NSRect(); + rect.x = x + data.drawXOffset; + rect.y = y + data.drawYOffset; + rect.width = width; + rect.height = height; + path.appendBezierPathWithRoundedRect(rect, arcWidth, arcHeight); + path.stroke(); + path.removeAllPoints(); + NSGraphicsContext.setCurrentContext(context); +} + +/** + * Draws the given string, using the receiver's current font and + * foreground color. No tab expansion or carriage return processing + * will be performed. The background of the rectangular area where + * the string is being drawn will be filled with the receiver's + * background color. + * + * @param string the string to be drawn + * @param x the x coordinate of the top left corner of the rectangular area where the string is to be drawn + * @param y the y coordinate of the top left corner of the rectangular area where the string is to be drawn + * + * @exception IllegalArgumentException <ul> + * <li>ERROR_NULL_ARGUMENT - if the string is null</li> + * </ul> + * @exception DWTException <ul> + * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> + * </ul> + */ +public void drawString (String string, int x, int y) { + drawString(string, x, y, false); +} + +/** + * Draws the given string, using the receiver's current font and + * foreground color. No tab expansion or carriage return processing + * will be performed. If <code>isTransparent</code> is <code>true</code>, + * then the background of the rectangular area where the string is being + * drawn will not be modified, otherwise it will be filled with the + * receiver's background color. + * + * @param string the string to be drawn + * @param x the x coordinate of the top left corner of the rectangular area where the string is to be drawn + * @param y the y coordinate of the top left corner of the rectangular area where the string is to be drawn + * @param isTransparent if <code>true</code> the background will be transparent, otherwise it will be opaque + * + * @exception IllegalArgumentException <ul> + * <li>ERROR_NULL_ARGUMENT - if the string is null</li> + * </ul> + * @exception DWTException <ul> + * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> + * </ul> + */ +public void drawString(String string, int x, int y, bool isTransparent) { + drawText(string, x, y, isTransparent ? DWT.DRAW_TRANSPARENT : 0); +} + +/** + * Draws the given string, using the receiver's current font and + * foreground color. Tab expansion and carriage return processing + * are performed. The background of the rectangular area where + * the text is being drawn will be filled with the receiver's + * background color. + * + * @param string the string to be drawn + * @param x the x coordinate of the top left corner of the rectangular area where the text is to be drawn + * @param y the y coordinate of the top left corner of the rectangular area where the text is to be drawn + * + * @exception IllegalArgumentException <ul> + * <li>ERROR_NULL_ARGUMENT - if the string is null</li> + * </ul> + * @exception DWTException <ul> + * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> + * </ul> + */ +public void drawText(String string, int x, int y) { + drawText(string, x, y, DWT.DRAW_DELIMITER | DWT.DRAW_TAB); +} + +/** + * Draws the given string, using the receiver's current font and + * foreground color. Tab expansion and carriage return processing + * are performed. If <code>isTransparent</code> is <code>true</code>, + * then the background of the rectangular area where the text is being + * drawn will not be modified, otherwise it will be filled with the + * receiver's background color. + * + * @param string the string to be drawn + * @param x the x coordinate of the top left corner of the rectangular area where the text is to be drawn + * @param y the y coordinate of the top left corner of the rectangular area where the text is to be drawn + * @param isTransparent if <code>true</code> the background will be transparent, otherwise it will be opaque + * + * @exception IllegalArgumentException <ul> + * <li>ERROR_NULL_ARGUMENT - if the string is null</li> + * </ul> + * @exception DWTException <ul> + * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> + * </ul> + */ +public void drawText(String string, int x, int y, bool isTransparent) { + int flags = DWT.DRAW_DELIMITER | DWT.DRAW_TAB; + if (isTransparent) flags |= DWT.DRAW_TRANSPARENT; + drawText(string, x, y, flags); +} + +/** + * Draws the given string, using the receiver's current font and + * foreground color. Tab expansion, line delimiter and mnemonic + * processing are performed according to the specified flags. If + * <code>flags</code> includes <code>DRAW_TRANSPARENT</code>, + * then the background of the rectangular area where the text is being + * drawn will not be modified, otherwise it will be filled with the + * receiver's background color. + * <p> + * The parameter <code>flags</code> may be a combination of: + * <dl> + * <dt><b>DRAW_DELIMITER</b></dt> + * <dd>draw multiple lines</dd> + * <dt><b>DRAW_TAB</b></dt> + * <dd>expand tabs</dd> + * <dt><b>DRAW_MNEMONIC</b></dt> + * <dd>underline the mnemonic character</dd> + * <dt><b>DRAW_TRANSPARENT</b></dt> + * <dd>transparent background</dd> + * </dl> + * </p> + * + * @param string the string to be drawn + * @param x the x coordinate of the top left corner of the rectangular area where the text is to be drawn + * @param y the y coordinate of the top left corner of the rectangular area where the text is to be drawn + * @param flags the flags specifying how to process the text + * + * @exception IllegalArgumentException <ul> + * <li>ERROR_NULL_ARGUMENT - if the string is null</li> + * </ul> + * @exception DWTException <ul> + * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> + * </ul> + */ +public void drawText (String string, int x, int y, int flags) { + if (handle is null) DWT.error(DWT.ERROR_GRAPHIC_DISPOSED); + if (string is null) DWT.error(DWT.ERROR_NULL_ARGUMENT); + NSGraphicsContext context = NSGraphicsContext.currentContext(); + NSGraphicsContext.setCurrentContext(handle); + checkGC(CLIPPING | TRANSFORM | FONT | FOREGROUND_FILL); + NSAttributedString str = createString(string, flags); + if (data.paintRect is null) { + handle.saveGraphicsState(); + NSAffineTransform transform = NSAffineTransform.transform(); + transform.scaleXBy(1, -1); + transform.translateXBy(0, -(str.size().height + 2 * y)); + transform.concat(); + } + NSPoint pt = new NSPoint(); + pt.x = x; + pt.y = y; + str.drawAtPoint(pt); + str.release(); + if (data.paintRect is null) { + handle.restoreGraphicsState(); + } + NSGraphicsContext.setCurrentContext(context); +} + +/** + * Compares the argument to the receiver, and returns true + * if they represent the <em>same</em> object using a class + * specific comparison. + * + * @param object the object to compare with this object + * @return <code>true</code> if the object is the same as this object and <code>false</code> otherwise + * + * @see #hashCode + */ +public bool equals(Object object) { + if (object is this) return true; + if (!(object instanceof GC)) return false; + return handle is ((GC)object).handle; +} + +/** + * Fills the interior of a circular or elliptical arc within + * the specified rectangular area, with the receiver's background + * color. + * <p> + * The resulting arc begins at <code>startAngle</code> and extends + * for <code>arcAngle</code> degrees, using the current color. + * Angles are interpreted such that 0 degrees is at the 3 o'clock + * position. A positive value indicates a counter-clockwise rotation + * while a negative value indicates a clockwise rotation. + * </p><p> + * The center of the arc is the center of the rectangle whose origin + * is (<code>x</code>, <code>y</code>) and whose size is specified by the + * <code>width</code> and <code>height</code> arguments. + * </p><p> + * The resulting arc covers an area <code>width + 1</code> pixels wide + * by <code>height + 1</code> pixels tall. + * </p> + * + * @param x the x coordinate of the upper-left corner of the arc to be filled + * @param y the y coordinate of the upper-left corner of the arc to be filled + * @param width the width of the arc to be filled + * @param height the height of the arc to be filled + * @param startAngle the beginning angle + * @param arcAngle the angular extent of the arc, relative to the start angle + * + * @exception DWTException <ul> + * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> + * </ul> + * + * @see #drawArc + */ +public void fillArc(int x, int y, int width, int height, int startAngle, int arcAngle) { + if (handle is null) DWT.error(DWT.ERROR_GRAPHIC_DISPOSED); + NSGraphicsContext context = NSGraphicsContext.currentContext(); + NSGraphicsContext.setCurrentContext(handle); + checkGC(FILL); + if (width < 0) { + x = x + width; + width = -width; + } + if (height < 0) { + y = y + height; + height = -height; + } + if (width is 0 || height is 0 || arcAngle is 0) return; + handle.saveGraphicsState(); + NSAffineTransform transform = NSAffineTransform.transform(); + float xOffset = data.drawXOffset, yOffset = data.drawYOffset; + transform.translateXBy(x + xOffset + width / 2f, y + yOffset + height / 2f); + transform.scaleXBy(width / 2f, height / 2f); + NSBezierPath path = data.path; + NSPoint center = new NSPoint(); + path.moveToPoint(center); + float sAngle = -startAngle; + float eAngle = -(startAngle + arcAngle); + path.appendBezierPathWithArcWithCenter_radius_startAngle_endAngle_clockwise_(center, 1, sAngle, eAngle, arcAngle>0); + path.closePath(); + path.transformUsingAffineTransform(transform); + path.fill(); + path.removeAllPoints(); + handle.restoreGraphicsState(); + NSGraphicsContext.setCurrentContext(context); +} + +/** + * Fills the interior of the specified rectangle with a gradient + * sweeping from left to right or top to bottom progressing + * from the receiver's foreground color to its background color. + * + * @param x the x coordinate of the rectangle to be filled + * @param y the y coordinate of the rectangle to be filled + * @param width the width of the rectangle to be filled, may be negative + * (inverts direction of gradient if horizontal) + * @param height the height of the rectangle to be filled, may be negative + * (inverts direction of gradient if vertical) + * @param vertical if true sweeps from top to bottom, else + * sweeps from left to right + * + * @exception DWTException <ul> + * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> + * </ul> + * + * @see #drawRectangle(int, int, int, int) + */ +public void fillGradientRectangle(int x, int y, int width, int height, bool vertical) { + if (handle is null) DWT.error(DWT.ERROR_GRAPHIC_DISPOSED); + NSGraphicsContext context = NSGraphicsContext.currentContext(); + NSGraphicsContext.setCurrentContext(handle); + checkGC(CLIPPING | TRANSFORM); + if ((width is 0) || (height is 0)) return; + + RGB backgroundRGB, foregroundRGB; + backgroundRGB = getBackground().getRGB(); + foregroundRGB = getForeground().getRGB(); + + RGB fromRGB, toRGB; + fromRGB = foregroundRGB; + toRGB = backgroundRGB; + bool swapColors = false; + if (width < 0) { + x += width; width = -width; + if (! vertical) swapColors = true; + } + if (height < 0) { + y += height; height = -height; + if (vertical) swapColors = true; + } + if (swapColors) { + fromRGB = backgroundRGB; + toRGB = foregroundRGB; + } + if (fromRGB.equals(toRGB)) { + fillRectangle(x, y, width, height); + } else { + NSColor startingColor = NSColor.colorWithDeviceRed(fromRGB.red / 255f, fromRGB.green / 255f, fromRGB.blue / 255f, data.alpha / 255f); + NSColor endingColor = NSColor.colorWithDeviceRed(toRGB.red / 255f, toRGB.green / 255f, toRGB.blue / 255f, data.alpha / 255f); + NSGradient gradient = ((NSGradient)new NSGradient().alloc()).initWithStartingColor(startingColor, endingColor); + NSRect rect = new NSRect(); + rect.x = x; + rect.y = y; + rect.width = width; + rect.height = height; + gradient.drawInRect_angle_(rect, vertical ? 90 : 0); + gradient.release(); + } + NSGraphicsContext.setCurrentContext(context); +} + +/** + * Fills the interior of an oval, within the specified + * rectangular area, with the receiver's background + * color. + * + * @param x the x coordinate of the upper left corner of the oval to be filled + * @param y the y coordinate of the upper left corner of the oval to be filled + * @param width the width of the oval to be filled + * @param height the height of the oval to be filled + * + * @exception DWTException <ul> + * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> + * </ul> + * + * @see #drawOval + */ +public void fillOval(int x, int y, int width, int height) { + if (handle is null) DWT.error(DWT.ERROR_GRAPHIC_DISPOSED); + NSGraphicsContext context = NSGraphicsContext.currentContext(); + NSGraphicsContext.setCurrentContext(handle); + checkGC(FILL); + if (width < 0) { + x = x + width; + width = -width; + } + if (height < 0) { + y = y + height; + height = -height; + } + NSBezierPath path = data.path; + NSRect rect = new NSRect(); + rect.x = x; + rect.y = y; + rect.width = width; + rect.height = height; + path.appendBezierPathWithOvalInRect(rect); + Pattern pattern = data.backgroundPattern; + if (pattern !is null && pattern.gradient !is null) { + fillPattern(path, pattern); + } else { + path.fill(); + } + path.removeAllPoints(); + NSGraphicsContext.setCurrentContext(context); +} + +void fillPattern(NSBezierPath path, Pattern pattern) { + NSGraphicsContext context = NSGraphicsContext.currentContext(); + NSGraphicsContext.setCurrentContext(handle); + path.addClip(); + pattern.gradient.drawFromPoint(pattern.pt1, pattern.pt2, OS.NSGradientDrawsAfterEndingLocation | OS.NSGradientDrawsBeforeStartingLocation); + NSGraphicsContext.setCurrentContext(context); +} + +/** + * Fills the path described by the parameter. + * <p> + * This operation requires the operating system's advanced + * graphics subsystem which may not be available on some + * platforms. + * </p> + * + * @param path the path to fill + * + * @exception IllegalArgumentException <ul> + * <li>ERROR_NULL_ARGUMENT - if the parameter is null</li> + * <li>ERROR_INVALID_ARGUMENT - if the parameter has been disposed</li> + * </ul> + * @exception DWTException <ul> + * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> + * <li>ERROR_NO_GRAPHICS_LIBRARY - if advanced graphics are not available</li> + * </ul> + * + * @see Path + * + * @since 3.1 + */ +public void fillPath(Path path) { + if (handle is null) DWT.error(DWT.ERROR_GRAPHIC_DISPOSED); + if (path is null) DWT.error(DWT.ERROR_NULL_ARGUMENT); + if (path.handle is null) DWT.error(DWT.ERROR_INVALID_ARGUMENT); + NSGraphicsContext context = NSGraphicsContext.currentContext(); + NSGraphicsContext.setCurrentContext(handle); + checkGC(FILL); + NSBezierPath drawPath = data.path; + drawPath.appendBezierPath(path.handle); + Pattern pattern = data.backgroundPattern; + if (pattern !is null && pattern.gradient !is null) { + fillPattern(drawPath, pattern); + } else { + drawPath.fill(); + } + drawPath.removeAllPoints(); + NSGraphicsContext.setCurrentContext(context); +} + +/** + * Fills the interior of the closed polygon which is defined by the + * specified array of integer coordinates, using the receiver's + * background color. The array contains alternating x and y values + * which are considered to represent points which are the vertices of + * the polygon. Lines are drawn between each consecutive pair, and + * between the first pair and last pair in the array. + * + * @param pointArray an array of alternating x and y values which are the vertices of the polygon + * + * @exception IllegalArgumentException <ul> + * <li>ERROR_NULL_ARGUMENT if pointArray is null</li> + * </ul> + * @exception DWTException <ul> + * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> + * </ul> + * + * @see #drawPolygon + */ +public void fillPolygon(int[] pointArray) { + if (handle is null) DWT.error(DWT.ERROR_GRAPHIC_DISPOSED); + if (pointArray is null) DWT.error(DWT.ERROR_NULL_ARGUMENT); + NSGraphicsContext context = NSGraphicsContext.currentContext(); + NSGraphicsContext.setCurrentContext(handle); + checkGC(FILL); + if (pointArray.length < 4) return; + NSBezierPath path = data.path; + NSPoint pt = new NSPoint(); + pt.x = pointArray[0]; + pt.y = pointArray[1]; + path.moveToPoint(pt); + int end = pointArray.length / 2 * 2; + for (int i = 2; i < end; i+=2) { + pt.x = pointArray[i]; + pt.y = pointArray[i+1]; + path.lineToPoint(pt); + } + path.closePath(); + Pattern pattern = data.backgroundPattern; + if (pattern !is null && pattern.gradient !is null) { + fillPattern(path, pattern); + } else { + path.fill(); + } + path.removeAllPoints(); + NSGraphicsContext.setCurrentContext(context); +} + +/** + * Fills the interior of the rectangle specified by the arguments, + * using the receiver's background color. + * + * @param x the x coordinate of the rectangle to be filled + * @param y the y coordinate of the rectangle to be filled + * @param width the width of the rectangle to be filled + * @param height the height of the rectangle to be filled + * + * @exception DWTException <ul> + * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> + * </ul> + * + * @see #drawRectangle(int, int, int, int) + */ +public void fillRectangle(int x, int y, int width, int height) { + if (handle is null) DWT.error(DWT.ERROR_GRAPHIC_DISPOSED); + NSGraphicsContext context = NSGraphicsContext.currentContext(); + NSGraphicsContext.setCurrentContext(handle); + checkGC(FILL); + if (width < 0) { + x = x + width; + width = -width; + } + if (height < 0) { + y = y + height; + height = -height; + } + NSRect rect = new NSRect(); + rect.x = x; + rect.y = y; + rect.width = width; + rect.height = height; + NSBezierPath path = data.path; + path.appendBezierPathWithRect(rect); + Pattern pattern = data.backgroundPattern; + if (pattern !is null && pattern.gradient !is null) { + fillPattern(path, pattern); + } else { + path.fill(); + } + path.removeAllPoints(); + NSGraphicsContext.setCurrentContext(context); +} + +/** + * Fills the interior of the specified rectangle, using the receiver's + * background color. + * + * @param rect the rectangle to be filled + * + * @exception IllegalArgumentException <ul> + * <li>ERROR_NULL_ARGUMENT - if the rectangle is null</li> + * </ul> + * @exception DWTException <ul> + * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> + * </ul> + * + * @see #drawRectangle(int, int, int, int) + */ +public void fillRectangle(Rectangle rect) { + if (handle is null) DWT.error(DWT.ERROR_GRAPHIC_DISPOSED); + if (rect is null) DWT.error(DWT.ERROR_NULL_ARGUMENT); + fillRectangle(rect.x, rect.y, rect.width, rect.height); +} + +/** + * Fills the interior of the round-cornered rectangle specified by + * the arguments, using the receiver's background color. + * + * @param x the x coordinate of the rectangle to be filled + * @param y the y coordinate of the rectangle to be filled + * @param width the width of the rectangle to be filled + * @param height the height of the rectangle to be filled + * @param arcWidth the width of the arc + * @param arcHeight the height of the arc + * + * @exception DWTException <ul> + * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> + * </ul> + * + * @see #drawRoundRectangle + */ +public void fillRoundRectangle(int x, int y, int width, int height, int arcWidth, int arcHeight) { + if (handle is null) DWT.error(DWT.ERROR_GRAPHIC_DISPOSED); + NSGraphicsContext context = NSGraphicsContext.currentContext(); + NSGraphicsContext.setCurrentContext(handle); + checkGC(FILL); + if (arcWidth is 0 || arcHeight is 0) { + fillRectangle(x, y, width, height); + return; + } + NSBezierPath path = data.path; + NSRect rect = new NSRect(); + rect.x = x; + rect.y = y; + rect.width = width; + rect.height = height; + path.appendBezierPathWithRoundedRect(rect, arcWidth, arcHeight); + Pattern pattern = data.backgroundPattern; + if (pattern !is null && pattern.gradient !is null) { + fillPattern(path, pattern); + } else { + path.fill(); + } + path.removeAllPoints(); + NSGraphicsContext.setCurrentContext(context); +} + +void flush () { +} + +/** + * Returns the <em>advance width</em> of the specified character in + * the font which is currently selected into the receiver. + * <p> + * The advance width is defined as the horizontal distance the cursor + * should move after printing the character in the selected font. + * </p> + * + * @param ch the character to measure + * @return the distance in the x direction to move past the character before painting the next + * + * @exception DWTException <ul> + * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> + * </ul> + */ +public int getAdvanceWidth(char ch) { + if (handle is null) DWT.error(DWT.ERROR_GRAPHIC_DISPOSED); + //NOT DONE + return stringExtent(new String(new char[]{ch})).x; +} + +/** + * Returns the background color. + * + * @return the receiver's background color + * + * @exception DWTException <ul> + * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> + * </ul> + */ +public Color getBackground() { + if (handle is null) DWT.error(DWT.ERROR_GRAPHIC_DISPOSED); + return Color.cocoa_new (data.device, data.background); +} + +/** + * Returns the background pattern. The default value is + * <code>null</code>. + * + * @return the receiver's background pattern + * + * @exception DWTException <ul> + * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> + * </ul> + * + * @see Pattern + * + * @since 3.1 + */ +public Pattern getBackgroundPattern() { + if (handle is null) DWT.error(DWT.ERROR_WIDGET_DISPOSED); + return data.backgroundPattern; +} + +/** + * Returns <code>true</code> if receiver is using the operating system's + * advanced graphics subsystem. Otherwise, <code>false</code> is returned + * to indicate that normal graphics are in use. + * <p> + * Advanced graphics may not be installed for the operating system. In this + * case, <code>false</code> is always returned. Some operating system have + * only one graphics subsystem. If this subsystem supports advanced graphics, + * then <code>true</code> is always returned. If any graphics operation such + * as alpha, antialias, patterns, interpolation, paths, clipping or transformation + * has caused the receiver to switch from regular to advanced graphics mode, + * <code>true</code> is returned. If the receiver has been explicitly switched + * to advanced mode and this mode is supported, <code>true</code> is returned. + * </p> + * + * @return the advanced value + * + * @exception DWTException <ul> + * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> + * </ul> + * + * @see #setAdvanced + * + * @since 3.1 + */ +public bool getAdvanced() { + if (handle is null) DWT.error(DWT.ERROR_GRAPHIC_DISPOSED); + return true; +} + +/** + * Returns the receiver's alpha value. + * + * @return the alpha value + * + * @exception DWTException <ul> + * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> + * </ul> + * + * @since 3.1 + */ +public int getAlpha() { + if (handle is null) DWT.error(DWT.ERROR_GRAPHIC_DISPOSED); + return data.alpha; +} + +/** + * Returns the receiver's anti-aliasing setting value, which will be + * one of <code>DWT.DEFAULT</code>, <code>DWT.OFF</code> or + * <code>DWT.ON</code>. Note that this controls anti-aliasing for all + * <em>non-text drawing</em> operations. + * + * @return the anti-aliasing setting + * + * @exception DWTException <ul> + * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> + * </ul> + * + * @see #getTextAntialias + * + * @since 3.1 + */ +public int getAntialias() { + if (handle is null) DWT.error(DWT.ERROR_GRAPHIC_DISPOSED); + return data.antialias; +} + +/** + * Returns the width of the specified character in the font + * selected into the receiver. + * <p> + * The width is defined as the space taken up by the actual + * character, not including the leading and tailing whitespace + * or overhang. + * </p> + * + * @param ch the character to measure + * @return the width of the character + * + * @exception DWTException <ul> + * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> + * </ul> + */ +public int getCharWidth(char ch) { + if (handle is null) DWT.error(DWT.ERROR_GRAPHIC_DISPOSED); + //NOT DONE + return stringExtent(new String(new char[]{ch})).x; +} + +/** + * Returns the bounding rectangle of the receiver's clipping + * region. If no clipping region is set, the return value + * will be a rectangle which covers the entire bounds of the + * object the receiver is drawing on. + * + * @return the bounding rectangle of the clipping region + * + * @exception DWTException <ul> + * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> + * </ul> + */ +public Rectangle getClipping() { + if (handle is null) DWT.error(DWT.ERROR_GRAPHIC_DISPOSED); + NSRect rect = null; + if (data.view !is null) { + rect = data.view.bounds(); + } else { + rect = new NSRect(); + if (data.image !is null) { + NSSize size = data.image.handle.size(); + rect.width = size.width; + rect.height = size.height; + } else if (data.size !is null) { + rect.width = data.size.width; + rect.height = data.size.height; + } + } + if (data.paintRect !is null || data.clipPath !is null || data.inverseTransform !is null) { + if (data.paintRect !is null) { + OS.NSIntersectionRect(rect, rect, data.paintRect); + } + if (data.clipPath !is null) { + NSRect clip = data.clipPath.bounds(); + OS.NSIntersectionRect(rect, rect, clip); + } + if (data.inverseTransform !is null && rect.width > 0 && rect.height > 0) { + NSPoint pt = new NSPoint(); + pt.x = rect.x; + pt.y = rect.y; + NSSize size = new NSSize(); + size.width = rect.width; + size.height = rect.height; + pt = data.inverseTransform.transformPoint(pt); + size = data.inverseTransform.transformSize(size); + rect.x = pt.x; + rect.y = pt.y; + rect.width = size.width; + rect.height = size.height; + } + } + return new Rectangle((int)rect.x, (int)rect.y, (int)rect.width, (int)rect.height); +} + +/** + * Sets the region managed by the argument to the current + * clipping region of the receiver. + * + * @param region the region to fill with the clipping region + * + * @exception IllegalArgumentException <ul> + * <li>ERROR_NULL_ARGUMENT - if the region is null</li> + * <li>ERROR_INVALID_ARGUMENT - if the region is disposed</li> + * </ul> + * @exception DWTException <ul> + * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> + * </ul> + */ +public void getClipping(Region region) { + if (handle is null) DWT.error(DWT.ERROR_GRAPHIC_DISPOSED); + if (region is null) DWT.error(DWT.ERROR_NULL_ARGUMENT); + if (region.isDisposed()) DWT.error(DWT.ERROR_INVALID_ARGUMENT); + region.subtract(region); + NSRect rect = null; + if (data.view !is null) { + rect = data.view.bounds(); + } else { + rect = new NSRect(); + if (data.image !is null) { + NSSize size = data.image.handle.size(); + rect.width = size.width; + rect.height = size.height; + } else if (data.size !is null) { + rect.width = data.size.width; + rect.height = data.size.height; + } + } + region.add((int)rect.x, (int)rect.y, (int)rect.width, (int)rect.height); + NSRect paintRect = data.paintRect; + if (paintRect !is null) { + region.intersect((int)paintRect.x, (int)paintRect.y, (int)paintRect.width, (int)paintRect.height); + } + if (data.clipPath !is null) { + NSBezierPath clip = data.clipPath.bezierPathByFlatteningPath(); + int count = clip.elementCount(); + int pointCount = 0; + Region clipRgn = new Region(device); + int[] pointArray = new int[count * 2]; + int points = OS.malloc(NSPoint.sizeof); + if (points is 0) DWT.error(DWT.ERROR_NO_HANDLES); + NSPoint pt = new NSPoint(); + for (int i = 0; i < count; i++) { + int element = clip.elementAtIndex_associatedPoints_(i, points); + switch (element) { + case OS.NSMoveToBezierPathElement: + if (pointCount !is 0) clipRgn.add(pointArray, pointCount); + pointCount = 0; + OS.memmove(pt, points, NSPoint.sizeof); + pointArray[pointCount++] = (int)pt.x; + pointArray[pointCount++] = (int)pt.y; + break; + case OS.NSLineToBezierPathElement: + OS.memmove(pt, points, NSPoint.sizeof); + pointArray[pointCount++] = (int)pt.x; + pointArray[pointCount++] = (int)pt.y; + break; + case OS.NSClosePathBezierPathElement: + if (pointCount !is 0) clipRgn.add(pointArray, pointCount); + pointCount = 0; + break; + } + } + if (pointCount !is 0) clipRgn.add(pointArray, pointCount); + OS.free(points); + region.intersect(clipRgn); + clipRgn.dispose(); + } + if (data.inverseTransform !is null) { + region.convertRgn(data.inverseTransform); + } +} + +/** + * Returns the receiver's fill rule, which will be one of + * <code>DWT.FILL_EVEN_ODD</code> or <code>DWT.FILL_WINDING</code>. + * + * @return the receiver's fill rule + * + * @exception DWTException <ul> + * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> + * </ul> + * + * @since 3.1 + */ +public int getFillRule() { + if (handle is null) DWT.error(DWT.ERROR_GRAPHIC_DISPOSED); + return data.fillRule; +} + +/** + * Returns the font currently being used by the receiver + * to draw and measure text. + * + * @return the receiver's font + * + * @exception DWTException <ul> + * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> + * </ul> + */ +public Font getFont() { + if (handle is null) DWT.error(DWT.ERROR_GRAPHIC_DISPOSED); + return data.font; +} + +/** + * Returns a FontMetrics which contains information + * about the font currently being used by the receiver + * to draw and measure text. + * + * @return font metrics for the receiver's font + * + * @exception DWTException <ul> + * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> + * </ul> + */ +public FontMetrics getFontMetrics() { + if (handle is null) DWT.error(DWT.ERROR_GRAPHIC_DISPOSED); + checkGC(FONT); + NSFont font = data.font.handle; + int ascent = (int)(0.5f + font.ascender()); + int descent = (int)(0.5f + (-font.descender() + font.leading())); + String s = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; + int averageCharWidth = stringExtent(s).x / s.length(); + return FontMetrics.cocoa_new(ascent, descent, averageCharWidth, 0, ascent + descent); +} + +/** + * Returns the receiver's foreground color. + * + * @return the color used for drawing foreground things + * + * @exception DWTException <ul> + * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> + * </ul> + */ +public Color getForeground() { + if (handle is null) DWT.error(DWT.ERROR_WIDGET_DISPOSED); + return Color.cocoa_new(data.device, data.foreground); +} + +/** + * Returns the foreground pattern. The default value is + * <code>null</code>. + * + * @return the receiver's foreground pattern + * + * @exception DWTException <ul> + * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> + * </ul> + * + * @see Pattern + * + * @since 3.1 + */ +public Pattern getForegroundPattern() { + if (handle is null) DWT.error(DWT.ERROR_WIDGET_DISPOSED); + return data.foregroundPattern; +} + +/** + * Returns the GCData. + * <p> + * <b>IMPORTANT:</b> This method is <em>not</em> part of the public + * API for <code>GC</code>. It is marked public only so that it + * can be shared within the packages provided by DWT. It is not + * available on all platforms, and should never be called from + * application code. + * </p> + * + * @return the receiver's GCData + * + * @exception DWTException <ul> + * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> + * </ul> + * + * @see GCData + * + * @since 3.2 + */ +public GCData getGCData() { + if (handle is null) DWT.error(DWT.ERROR_WIDGET_DISPOSED); + return data; +} + +/** + * Returns the receiver's interpolation setting, which will be one of + * <code>DWT.DEFAULT</code>, <code>DWT.NONE</code>, + * <code>DWT.LOW</code> or <code>DWT.HIGH</code>. + * + * @return the receiver's interpolation setting + * + * @exception DWTException <ul> + * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> + * </ul> + * + * @since 3.1 + */ +public int getInterpolation() { + if (handle is null) DWT.error(DWT.ERROR_GRAPHIC_DISPOSED); + int interpolation = handle.imageInterpolation(); + switch (interpolation) { + case OS.NSImageInterpolationDefault: return DWT.DEFAULT; + case OS.NSImageInterpolationNone: return DWT.NONE; + case OS.NSImageInterpolationLow: return DWT.LOW; + case OS.NSImageInterpolationHigh: return DWT.HIGH; + } + return DWT.DEFAULT; +} + +/** + * Returns the receiver's line attributes. + * + * @return the line attributes used for drawing lines + * + * @exception DWTException <ul> + * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> + * </ul> + * + * @since 3.3 + */ +public LineAttributes getLineAttributes() { + if (handle is null) DWT.error(DWT.ERROR_GRAPHIC_DISPOSED); + float[] dashes = null; + if (data.lineDashes !is null) { + dashes = new float[data.lineDashes.length]; + System.arraycopy(data.lineDashes, 0, dashes, 0, dashes.length); + } + return new LineAttributes(data.lineWidth, data.lineCap, data.lineJoin, data.lineStyle, dashes, data.lineDashesOffset, data.lineMiterLimit); +} + +/** + * Returns the receiver's line cap style, which will be one + * of the constants <code>DWT.CAP_FLAT</code>, <code>DWT.CAP_ROUND</code>, + * or <code>DWT.CAP_SQUARE</code>. + * + * @return the cap style used for drawing lines + * + * @exception DWTException <ul> + * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> + * </ul> + * + * @since 3.1 + */ +public int getLineCap() { + if (handle is null) DWT.error(DWT.ERROR_GRAPHIC_DISPOSED); + return data.lineCap; +} + +/** + * Returns the receiver's line dash style. The default value is + * <code>null</code>. + * + * @return the line dash style used for drawing lines + * + * @exception DWTException <ul> + * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> + * </ul> + * + * @since 3.1 + */ +public int[] getLineDash() { + if (handle is null) DWT.error(DWT.ERROR_GRAPHIC_DISPOSED); + if (data.lineDashes is null) return null; + int[] lineDashes = new int[data.lineDashes.length]; + for (int i = 0; i < lineDashes.length; i++) { + lineDashes[i] = (int)data.lineDashes[i]; + } + return lineDashes; +} + +/** + * Returns the receiver's line join style, which will be one + * of the constants <code>DWT.JOIN_MITER</code>, <code>DWT.JOIN_ROUND</code>, + * or <code>DWT.JOIN_BEVEL</code>. + * + * @return the join style used for drawing lines + * + * @exception DWTException <ul> + * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> + * </ul> + * + * @since 3.1 + */ +public int getLineJoin() { + if (handle is null) DWT.error(DWT.ERROR_GRAPHIC_DISPOSED); + return data.lineJoin; +} + +/** + * Returns the receiver's line style, which will be one + * of the constants <code>DWT.LINE_SOLID</code>, <code>DWT.LINE_DASH</code>, + * <code>DWT.LINE_DOT</code>, <code>DWT.LINE_DASHDOT</code> or + * <code>DWT.LINE_DASHDOTDOT</code>. + * + * @return the style used for drawing lines + * + * @exception DWTException <ul> + * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> + * </ul> + */ +public int getLineStyle() { + if (handle is null) DWT.error(DWT.ERROR_GRAPHIC_DISPOSED); + return data.lineStyle; +} + +/** + * Returns the width that will be used when drawing lines + * for all of the figure drawing operations (that is, + * <code>drawLine</code>, <code>drawRectangle</code>, + * <code>drawPolyline</code>, and so forth. + * + * @return the receiver's line width + * + * @exception DWTException <ul> + * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> + * </ul> + */ +public int getLineWidth() { + if (handle is null) DWT.error(DWT.ERROR_GRAPHIC_DISPOSED); + return (int)data.lineWidth; +} + +/** + * Returns the receiver's style information. + * <p> + * Note that the value which is returned by this method <em>may + * not match</em> the value which was provided to the constructor + * when the receiver was created. This can occur when the underlying + * operating system does not support a particular combination of + * requested styles. + * </p> + * + * @return the style bits + * + * @exception DWTException <ul> + * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> + * </ul> + * + * @since 2.1.2 + */ +public int getStyle () { + if (handle is null) DWT.error(DWT.ERROR_GRAPHIC_DISPOSED); + return data.style; +} + +/** + * Returns the receiver's text drawing anti-aliasing setting value, + * which will be one of <code>DWT.DEFAULT</code>, <code>DWT.OFF</code> or + * <code>DWT.ON</code>. Note that this controls anti-aliasing + * <em>only</em> for text drawing operations. + * + * @return the anti-aliasing setting + * + * @exception DWTException <ul> + * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> + * </ul> + * + * @see #getAntialias + * + * @since 3.1 + */ +public int getTextAntialias() { + if (handle is null) DWT.error(DWT.ERROR_GRAPHIC_DISPOSED); + return data.textAntialias; +} + +/** + * Sets the parameter to the transform that is currently being + * used by the receiver. + * + * @param transform the destination to copy the transform into + * + * @exception IllegalArgumentException <ul> + * <li>ERROR_NULL_ARGUMENT - if the parameter is null</li> + * <li>ERROR_INVALID_ARGUMENT - if the parameter has been disposed</li> + * </ul> + * @exception DWTException <ul> + * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> + * </ul> + * + * @see Transform + * + * @since 3.1 + */ +public void getTransform (Transform transform) { + if (handle is null) DWT.error(DWT.ERROR_GRAPHIC_DISPOSED); + if (transform is null) DWT.error(DWT.ERROR_NULL_ARGUMENT); + if (transform.isDisposed()) DWT.error(DWT.ERROR_INVALID_ARGUMENT); + NSAffineTransform cmt = data.transform; + if (cmt !is null) { + NSAffineTransformStruct struct = cmt.transformStruct(); + transform.handle.setTransformStruct(struct); + } else { + transform.setElements(1, 0, 0, 1, 0, 0); + } +} + +/** + * Returns <code>true</code> if this GC is drawing in the mode + * where the resulting color in the destination is the + * <em>exclusive or</em> of the color values in the source + * and the destination, and <code>false</code> if it is + * drawing in the mode where the destination color is being + * replaced with the source color value. + * + * @return <code>true</code> true if the receiver is in XOR mode, and false otherwise + * + * @exception DWTException <ul> + * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> + * </ul> + */ +public bool getXORMode() { + if (handle is null) DWT.error(DWT.ERROR_GRAPHIC_DISPOSED); + return data.xorMode; +} + +/** + * Returns an integer hash code for the receiver. Any two + * objects that return <code>true</code> when passed to + * <code>equals</code> must return the same value for this + * method. + * + * @return the receiver's hash + * + * @exception DWTException <ul> + * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> + * </ul> + * + * @see #equals + */ +public int hashCode() { + return handle !is null ? handle.id : 0; +} + +void init(Drawable drawable, GCData data, int context) { + if (data.foreground !is null) data.state &= ~(FOREGROUND | FOREGROUND_FILL); + if (data.background !is null) data.state &= ~BACKGROUND; + if (data.font !is null) data.state &= ~FONT; + data.state &= ~DRAW_OFFSET; + + Image image = data.image; + if (image !is null) image.memGC = this; + this.drawable = drawable; + this.data = data; + handle = new NSGraphicsContext(context); + handle.retain(); + handle.saveGraphicsState(); + data.path = NSBezierPath.bezierPath(); + data.path.setWindingRule(data.fillRule is DWT.FILL_WINDING ? OS.NSNonZeroWindingRule : OS.NSEvenOddWindingRule); + data.path.retain(); +} + +/** + * Returns <code>true</code> if the receiver has a clipping + * region set into it, and <code>false</code> otherwise. + * If this method returns false, the receiver will draw on all + * available space in the destination. If it returns true, + * it will draw only in the area that is covered by the region + * that can be accessed with <code>getClipping(region)</code>. + * + * @return <code>true</code> if the GC has a clipping region, and <code>false</code> otherwise + * + * @exception DWTException <ul> + * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> + * </ul> + */ +public bool isClipped() { + if (handle is null) DWT.error(DWT.ERROR_GRAPHIC_DISPOSED); + return data.clipPath !is null; +} + +/** + * Returns <code>true</code> if the GC has been disposed, + * and <code>false</code> otherwise. + * <p> + * This method gets the dispose state for the GC. + * When a GC has been disposed, it is an error to + * invoke any other method using the GC. + * + * @return <code>true</code> when the GC is disposed and <code>false</code> otherwise + */ +public bool isDisposed() { + return handle is null; +} + +bool isIdentity(float[] transform) { + return transform[0] is 1 && transform[1] is 0 && transform[2] is 0 + && transform[3] is 1 && transform[4] is 0 && transform[5] is 0; +} + +/** + * Sets the receiver to always use the operating system's advanced graphics + * subsystem for all graphics operations if the argument is <code>true</code>. + * If the argument is <code>false</code>, the advanced graphics subsystem is + * no longer used, advanced graphics state is cleared and the normal graphics + * subsystem is used from now on. + * <p> + * Normally, the advanced graphics subsystem is invoked automatically when + * any one of the alpha, antialias, patterns, interpolation, paths, clipping + * or transformation operations in the receiver is requested. When the receiver + * is switched into advanced mode, the advanced graphics subsystem performs both + * advanced and normal graphics operations. Because the two subsystems are + * different, their output may differ. Switching to advanced graphics before + * any graphics operations are performed ensures that the output is consistent. + * </p><p> + * Advanced graphics may not be installed for the operating system. In this + * case, this operation does nothing. Some operating system have only one + * graphics subsystem, so switching from normal to advanced graphics does + * nothing. However, switching from advanced to normal graphics will always + * clear the advanced graphics state, even for operating systems that have + * only one graphics subsystem. + * </p> + * + * @param advanced the new advanced graphics state + * + * @exception DWTException <ul> + * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> + * </ul> + * + * @see #setAlpha + * @see #setAntialias + * @see #setBackgroundPattern + * @see #setClipping(Path) + * @see #setForegroundPattern + * @see #setLineAttributes + * @see #setInterpolation + * @see #setTextAntialias + * @see #setTransform + * @see #getAdvanced + * + * @since 3.1 + */ +public void setAdvanced(bool advanced) { + if (handle is null) DWT.error(DWT.ERROR_GRAPHIC_DISPOSED); + if (!advanced) { + setAlpha(0xFF); + setAntialias(DWT.DEFAULT); + setBackgroundPattern(null); + setClipping((Rectangle)null); + setForegroundPattern(null); + setInterpolation(DWT.DEFAULT); + setTextAntialias(DWT.DEFAULT); + setTransform(null); + } +} + +/** + * Sets the receiver's alpha value. + * <p> + * This operation requires the operating system's advanced + * graphics subsystem which may not be available on some + * platforms. + * </p> + * @param alpha the alpha value + * + * @exception DWTException <ul> + * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> + * <li>ERROR_NO_GRAPHICS_LIBRARY - if advanced graphics are not available</li> + * </ul> + * + * @see #getAdvanced + * @see #setAdvanced + * + * @since 3.1 + */ +public void setAlpha(int alpha) { + if (handle is null) DWT.error(DWT.ERROR_GRAPHIC_DISPOSED); + data.alpha = alpha & 0xFF; + data.state &= ~(BACKGROUND | FOREGROUND | FOREGROUND_FILL); + +} + +/** + * Sets the receiver's anti-aliasing value to the parameter, + * which must be one of <code>DWT.DEFAULT</code>, <code>DWT.OFF</code> + * or <code>DWT.ON</code>. Note that this controls anti-aliasing for all + * <em>non-text drawing</em> operations. + * <p> + * This operation requires the operating system's advanced + * graphics subsystem which may not be available on some + * platforms. + * </p> + * + * @param antialias the anti-aliasing setting + * + * @exception IllegalArgumentException <ul> + * <li>ERROR_INVALID_ARGUMENT - if the parameter is not one of <code>DWT.DEFAULT</code>, + * <code>DWT.OFF</code> or <code>DWT.ON</code></li> + * </ul> + * @exception DWTException <ul> + * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> + * <li>ERROR_NO_GRAPHICS_LIBRARY - if advanced graphics are not available</li> + * </ul> + * + * @see #getAdvanced + * @see #setAdvanced + * @see #setTextAntialias + * + * @since 3.1 + */ +public void setAntialias(int antialias) { + if (handle is null) DWT.error(DWT.ERROR_GRAPHIC_DISPOSED); + bool mode = true; + switch (antialias) { + case DWT.DEFAULT: + /* Printer is off by default */ +// if (data.window is 0 && data.control is 0 && data.image is null) mode = false; + mode = true; + break; + case DWT.OFF: mode = false; break; + case DWT.ON: mode = true; break; + default: + DWT.error(DWT.ERROR_INVALID_ARGUMENT); + } + data.antialias = antialias; + handle.setShouldAntialias(mode); +} + +/** + * Sets the background color. The background color is used + * for fill operations and as the background color when text + * is drawn. + * + * @param color the new background color for the receiver + * + * @exception IllegalArgumentException <ul> + * <li>ERROR_NULL_ARGUMENT - if the color is null</li> + * <li>ERROR_INVALID_ARGUMENT - if the color has been disposed</li> + * </ul> + * @exception DWTException <ul> + * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> + * </ul> + */ +public void setBackground(Color color) { + if (handle is null) DWT.error(DWT.ERROR_GRAPHIC_DISPOSED); + if (color is null) DWT.error(DWT.ERROR_NULL_ARGUMENT); + if (color.isDisposed()) DWT.error(DWT.ERROR_INVALID_ARGUMENT); + data.background = color.handle; + data.backgroundPattern = null; + data.state &= ~BACKGROUND; +} + +/** + * Sets the background pattern. The default value is <code>null</code>. + * <p> + * This operation requires the operating system's advanced + * graphics subsystem which may not be available on some + * platforms. + * </p> + * + * @param pattern the new background pattern + * + * @exception IllegalArgumentException <ul> + * <li>ERROR_INVALID_ARGUMENT - if the parameter has been disposed</li> + * </ul> + * @exception DWTException <ul> + * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> + * <li>ERROR_NO_GRAPHICS_LIBRARY - if advanced graphics are not available</li> + * </ul> + * + * @see Pattern + * @see #getAdvanced + * @see #setAdvanced + * + * @since 3.1 + */ +public void setBackgroundPattern(Pattern pattern) { + if (handle is null) DWT.error(DWT.ERROR_GRAPHIC_DISPOSED); + if (pattern !is null && pattern.isDisposed()) DWT.error(DWT.ERROR_INVALID_ARGUMENT); + if (data.backgroundPattern is pattern) return; + data.backgroundPattern = pattern; + data.state &= ~BACKGROUND; +} + +/** + * Sets the area of the receiver which can be changed + * by drawing operations to the rectangular area specified + * by the arguments. + * + * @param x the x coordinate of the clipping rectangle + * @param y the y coordinate of the clipping rectangle + * @param width the width of the clipping rectangle + * @param height the height of the clipping rectangle + * + * @exception DWTException <ul> + * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> + * </ul> + */ +public void setClipping(int x, int y, int width, int height) { + if (handle is null) DWT.error(DWT.ERROR_GRAPHIC_DISPOSED); + if (width < 0) { + x = x + width; + width = -width; + } + if (height < 0) { + y = y + height; + height = -height; + } + NSRect rect = new NSRect(); + rect.x = x; + rect.y = y; + rect.width = width; + rect.height = height; + NSBezierPath path = NSBezierPath.bezierPathWithRect(rect); + path.retain(); + setClipping(path); +} + +/** + * Sets the area of the receiver which can be changed + * by drawing operations to the path specified + * by the argument. + * <p> + * This operation requires the operating system's advanced + * graphics subsystem which may not be available on some + * platforms. + * </p> + * + * @param path the clipping path. + * + * @exception IllegalArgumentException <ul> + * <li>ERROR_INVALID_ARGUMENT - if the path has been disposed</li> + * </ul> + * @exception DWTException <ul> + * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> + * <li>ERROR_NO_GRAPHICS_LIBRARY - if advanced graphics are not available</li> + * </ul> + * + * @see Path + * @see #getAdvanced + * @see #setAdvanced + * + * @since 3.1 + */ +public void setClipping(Path path) { + if (handle is null) DWT.error(DWT.ERROR_GRAPHIC_DISPOSED); + if (path !is null && path.isDisposed()) DWT.error(DWT.ERROR_INVALID_ARGUMENT); + setClipping(new NSBezierPath(path.handle.copy().id)); +} + +/** + * Sets the area of the receiver which can be changed + * by drawing operations to the rectangular area specified + * by the argument. Specifying <code>null</code> for the + * rectangle reverts the receiver's clipping area to its + * original value. + * + * @param rect the clipping rectangle or <code>null</code> + * + * @exception DWTException <ul> + * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> + * </ul> + */ +public void setClipping(Rectangle rect) { + if (handle is null) DWT.error(DWT.ERROR_GRAPHIC_DISPOSED); + if (rect is null) { + setClipping((NSBezierPath)null); + } else { + setClipping(rect.x, rect.y, rect.width, rect.height); + } +} + +/** + * Sets the area of the receiver which can be changed + * by drawing operations to the region specified + * by the argument. Specifying <code>null</code> for the + * region reverts the receiver's clipping area to its + * original value. + * + * @param region the clipping region or <code>null</code> + * + * @exception IllegalArgumentException <ul> + * <li>ERROR_INVALID_ARGUMENT - if the region has been disposed</li> + * </ul> + * @exception DWTException <ul> + * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> + * </ul> + */ +public void setClipping(Region region) { + if (handle is null) DWT.error(DWT.ERROR_GRAPHIC_DISPOSED); + if (region !is null && region.isDisposed()) DWT.error(DWT.ERROR_INVALID_ARGUMENT); + setClipping(region !is null ? region.getPath() : null); +} + +void setClipping(NSBezierPath path) { + if (data.clipPath !is null) { + data.clipPath.release(); + data.clipPath = null; + } + if (path !is null) { + data.clipPath = path; + if (data.transform !is null) { + data.clipPath.transformUsingAffineTransform(data.transform); + } + } + data.state &= ~CLIPPING; +} + +/** + * Sets the receiver's fill rule to the parameter, which must be one of + * <code>DWT.FILL_EVEN_ODD</code> or <code>DWT.FILL_WINDING</code>. + * + * @param rule the new fill rule + * + * @exception IllegalArgumentException <ul> + * <li>ERROR_INVALID_ARGUMENT - if the rule is not one of <code>DWT.FILL_EVEN_ODD</code> + * or <code>DWT.FILL_WINDING</code></li> + * </ul> + * @exception DWTException <ul> + * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> + * </ul> + * + * @since 3.1 + */ +public void setFillRule(int rule) { + if (handle is null) DWT.error(DWT.ERROR_GRAPHIC_DISPOSED); + switch (rule) { + case DWT.FILL_WINDING: + case DWT.FILL_EVEN_ODD: break; + default: + DWT.error(DWT.ERROR_INVALID_ARGUMENT); + } + data.fillRule = rule; + data.path.setWindingRule(rule is DWT.FILL_WINDING ? OS.NSNonZeroWindingRule : OS.NSEvenOddWindingRule); +} + +/** + * Sets the font which will be used by the receiver + * to draw and measure text to the argument. If the + * argument is null, then a default font appropriate + * for the platform will be used instead. + * + * @param font the new font for the receiver, or null to indicate a default font + * + * @exception IllegalArgumentException <ul> + * <li>ERROR_INVALID_ARGUMENT - if the font has been disposed</li> + * </ul> + * @exception DWTException <ul> + * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> + * </ul> + */ +public void setFont(Font font) { + if (handle is null) DWT.error(DWT.ERROR_GRAPHIC_DISPOSED); + if (font !is null && font.isDisposed()) DWT.error(DWT.ERROR_INVALID_ARGUMENT); + data.font = font !is null ? font : data.device.systemFont; + data.state &= ~FONT; +} + +/** + * Sets the foreground color. The foreground color is used + * for drawing operations including when text is drawn. + * + * @param color the new foreground color for the receiver + * + * @exception IllegalArgumentException <ul> + * <li>ERROR_NULL_ARGUMENT - if the color is null</li> + * <li>ERROR_INVALID_ARGUMENT - if the color has been disposed</li> + * </ul> + * @exception DWTException <ul> + * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> + * </ul> + */ +public void setForeground(Color color) { + if (handle is null) DWT.error(DWT.ERROR_GRAPHIC_DISPOSED); + if (color is null) DWT.error(DWT.ERROR_NULL_ARGUMENT); + if (color.isDisposed()) DWT.error(DWT.ERROR_INVALID_ARGUMENT); + data.foreground = color.handle; + data.foregroundPattern = null; + data.state &= ~(FOREGROUND | FOREGROUND_FILL); +} + +/** + * Sets the foreground pattern. The default value is <code>null</code>. + * <p> + * This operation requires the operating system's advanced + * graphics subsystem which may not be available on some + * platforms. + * </p> + * @param pattern the new foreground pattern + * + * @exception IllegalArgumentException <ul> + * <li>ERROR_INVALID_ARGUMENT - if the parameter has been disposed</li> + * </ul> + * @exception DWTException <ul> + * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> + * <li>ERROR_NO_GRAPHICS_LIBRARY - if advanced graphics are not available</li> + * </ul> + * + * @see Pattern + * @see #getAdvanced + * @see #setAdvanced + * + * @since 3.1 + */ +public void setForegroundPattern(Pattern pattern) { + if (handle is null) DWT.error(DWT.ERROR_GRAPHIC_DISPOSED); + if (pattern !is null && pattern.isDisposed()) DWT.error(DWT.ERROR_INVALID_ARGUMENT); + if (data.foregroundPattern is pattern) return; + data.foregroundPattern = pattern; + data.state &= ~(FOREGROUND | FOREGROUND_FILL); +} + +/** + * Sets the receiver's interpolation setting to the parameter, which + * must be one of <code>DWT.DEFAULT</code>, <code>DWT.NONE</code>, + * <code>DWT.LOW</code> or <code>DWT.HIGH</code>. + * <p> + * This operation requires the operating system's advanced + * graphics subsystem which may not be available on some + * platforms. + * </p> + * + * @param interpolation the new interpolation setting + * + * @exception IllegalArgumentException <ul> + * <li>ERROR_INVALID_ARGUMENT - if the rule is not one of <code>DWT.DEFAULT</code>, + * <code>DWT.NONE</code>, <code>DWT.LOW</code> or <code>DWT.HIGH</code> + * </ul> + * @exception DWTException <ul> + * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> + * <li>ERROR_NO_GRAPHICS_LIBRARY - if advanced graphics are not available</li> + * </ul> + * + * @see #getAdvanced + * @see #setAdvanced + * + * @since 3.1 + */ +public void setInterpolation(int interpolation) { + if (handle is null) DWT.error(DWT.ERROR_GRAPHIC_DISPOSED); + int quality = 0; + switch (interpolation) { + case DWT.DEFAULT: quality = OS.NSImageInterpolationDefault; break; + case DWT.NONE: quality = OS.NSImageInterpolationNone; break; + case DWT.LOW: quality = OS.NSImageInterpolationLow; break; + case DWT.HIGH: quality = OS.NSImageInterpolationHigh; break; + default: + DWT.error(DWT.ERROR_INVALID_ARGUMENT); + } + handle.setImageInterpolation(quality); +} + +/** + * Sets the receiver's line attributes. + * <p> + * This operation requires the operating system's advanced + * graphics subsystem which may not be available on some + * platforms. + * </p> + * @param attributes the line attributes + * + * @exception IllegalArgumentException <ul> + * <li>ERROR_NULL_ARGUMENT - if the attributes is null</li> + * <li>ERROR_INVALID_ARGUMENT - if any of the line attributes is not valid</li> + * </ul> + * @exception DWTException <ul> + * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> + * <li>ERROR_NO_GRAPHICS_LIBRARY - if advanced graphics are not available</li> + * </ul> + * + * @see LineAttributes + * @see #getAdvanced + * @see #setAdvanced + * + * @since 3.3 + */ +public void setLineAttributes(LineAttributes attributes) { + if (handle is null) DWT.error(DWT.ERROR_GRAPHIC_DISPOSED); + if (attributes is null) DWT.error(DWT.ERROR_NULL_ARGUMENT); + int mask = 0; + float lineWidth = attributes.width; + if (lineWidth !is data.lineWidth) { + mask |= LINE_WIDTH | DRAW_OFFSET; + } + int lineStyle = attributes.style; + if (lineStyle !is data.lineStyle) { + mask |= LINE_STYLE; + switch (lineStyle) { + case DWT.LINE_SOLID: + case DWT.LINE_DASH: + case DWT.LINE_DOT: + case DWT.LINE_DASHDOT: + case DWT.LINE_DASHDOTDOT: + break; + case DWT.LINE_CUSTOM: + if (attributes.dash is null) lineStyle = DWT.LINE_SOLID; + break; + default: + DWT.error(DWT.ERROR_INVALID_ARGUMENT); + } + } + int join = attributes.join; + if (join !is data.lineJoin) { + mask |= LINE_JOIN; + switch (join) { + case DWT.CAP_ROUND: + case DWT.CAP_FLAT: + case DWT.CAP_SQUARE: + break; + default: + DWT.error(DWT.ERROR_INVALID_ARGUMENT); + } + } + int cap = attributes.cap; + if (cap !is data.lineCap) { + mask |= LINE_CAP; + switch (cap) { + case DWT.JOIN_MITER: + case DWT.JOIN_ROUND: + case DWT.JOIN_BEVEL: + break; + default: + DWT.error(DWT.ERROR_INVALID_ARGUMENT); + } + } + float[] dashes = attributes.dash; + float[] lineDashes = data.lineDashes; + if (dashes !is null && dashes.length > 0) { + bool changed = lineDashes is null || lineDashes.length !is dashes.length; + for (int i = 0; i < dashes.length; i++) { + float dash = dashes[i]; + if (dash <= 0) DWT.error(DWT.ERROR_INVALID_ARGUMENT); + if (!changed && lineDashes[i] !is dash) changed = true; + } + if (changed) { + float[] newDashes = new float[dashes.length]; + System.arraycopy(dashes, 0, newDashes, 0, dashes.length); + dashes = newDashes; + mask |= LINE_STYLE; + } else { + dashes = lineDashes; + } + } else { + if (lineDashes !is null && lineDashes.length > 0) { + mask |= LINE_STYLE; + } else { + dashes = lineDashes; + } + } + float dashOffset = attributes.dashOffset; + if (dashOffset !is data.lineDashesOffset) { + mask |= LINE_STYLE; + } + float miterLimit = attributes.miterLimit; + if (miterLimit !is data.lineMiterLimit) { + mask |= LINE_MITERLIMIT; + } + if (mask is 0) return; + data.lineWidth = lineWidth; + data.lineStyle = lineStyle; + data.lineCap = cap; + data.lineJoin = join; + data.lineDashes = dashes; + data.lineDashesOffset = dashOffset; + data.lineMiterLimit = miterLimit; + data.state &= ~mask; +} + +/** + * Sets the receiver's line cap style to the argument, which must be one + * of the constants <code>DWT.CAP_FLAT</code>, <code>DWT.CAP_ROUND</code>, + * or <code>DWT.CAP_SQUARE</code>. + * + * @param cap the cap style to be used for drawing lines + * + * @exception IllegalArgumentException <ul> + * <li>ERROR_INVALID_ARGUMENT - if the style is not valid</li> + * </ul> + * @exception DWTException <ul> + * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> + * </ul> + * + * @since 3.1 + */ +public void setLineCap(int cap) { + if (handle is null) DWT.error(DWT.ERROR_GRAPHIC_DISPOSED); + if (data.lineCap is cap) return; + switch (cap) { + case DWT.CAP_ROUND: + case DWT.CAP_FLAT: + case DWT.CAP_SQUARE: + break; + default: + DWT.error(DWT.ERROR_INVALID_ARGUMENT); + } + data.lineCap = cap; + data.state &= ~LINE_CAP; +} + +/** + * Sets the receiver's line dash style to the argument. The default + * value is <code>null</code>. If the argument is not <code>null</code>, + * the receiver's line style is set to <code>DWT.LINE_CUSTOM</code>, otherwise + * it is set to <code>DWT.LINE_SOLID</code>. + * + * @param dashes the dash style to be used for drawing lines + * + * @exception IllegalArgumentException <ul> + * <li>ERROR_INVALID_ARGUMENT - if any of the values in the array is less than or equal 0</li> + * </ul> + * @exception DWTException <ul> + * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> + * </ul> + * + * @since 3.1 + */ +public void setLineDash(int[] dashes) { + if (handle is null) DWT.error(DWT.ERROR_GRAPHIC_DISPOSED); + float[] lineDashes = data.lineDashes; + if (dashes !is null && dashes.length > 0) { + bool changed = data.lineStyle !is DWT.LINE_CUSTOM || lineDashes is null || lineDashes.length !is dashes.length; + for (int i = 0; i < dashes.length; i++) { + int dash = dashes[i]; + if (dash <= 0) DWT.error(DWT.ERROR_INVALID_ARGUMENT); + if (!changed && lineDashes[i] !is dash) changed = true; + } + if (!changed) return; + data.lineDashes = new float[dashes.length]; + for (int i = 0; i < dashes.length; i++) { + data.lineDashes[i] = dashes[i]; + } + data.lineStyle = DWT.LINE_CUSTOM; + } else { + if (data.lineStyle is DWT.LINE_SOLID && (lineDashes is null || lineDashes.length is 0)) return; + data.lineDashes = null; + data.lineStyle = DWT.LINE_SOLID; + } + data.state &= ~LINE_STYLE; +} + +/** + * Sets the receiver's line join style to the argument, which must be one + * of the constants <code>DWT.JOIN_MITER</code>, <code>DWT.JOIN_ROUND</code>, + * or <code>DWT.JOIN_BEVEL</code>. + * + * @param join the join style to be used for drawing lines + * + * @exception IllegalArgumentException <ul> + * <li>ERROR_INVALID_ARGUMENT - if the style is not valid</li> + * </ul> + * @exception DWTException <ul> + * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> + * </ul> + * + * @since 3.1 + */ +public void setLineJoin(int join) { + if (handle is null) DWT.error(DWT.ERROR_GRAPHIC_DISPOSED); + if (data.lineJoin is join) return; + switch (join) { + case DWT.JOIN_MITER: + case DWT.JOIN_ROUND: + case DWT.JOIN_BEVEL: + break; + default: + DWT.error(DWT.ERROR_INVALID_ARGUMENT); + } + data.lineJoin = join; + data.state &= ~LINE_JOIN; +} + +/** + * Sets the receiver's line style to the argument, which must be one + * of the constants <code>DWT.LINE_SOLID</code>, <code>DWT.LINE_DASH</code>, + * <code>DWT.LINE_DOT</code>, <code>DWT.LINE_DASHDOT</code> or + * <code>DWT.LINE_DASHDOTDOT</code>. + * + * @param lineStyle the style to be used for drawing lines + * + * @exception IllegalArgumentException <ul> + * <li>ERROR_INVALID_ARGUMENT - if the style is not valid</li> + * </ul> + * @exception DWTException <ul> + * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> + * </ul> + */ +public void setLineStyle(int lineStyle) { + if (handle is null) DWT.error(DWT.ERROR_GRAPHIC_DISPOSED); + if (data.lineStyle is lineStyle) return; + switch (lineStyle) { + case DWT.LINE_SOLID: + case DWT.LINE_DASH: + case DWT.LINE_DOT: + case DWT.LINE_DASHDOT: + case DWT.LINE_DASHDOTDOT: + break; + case DWT.LINE_CUSTOM: + if (data.lineDashes is null) lineStyle = DWT.LINE_SOLID; + break; + default: + DWT.error(DWT.ERROR_INVALID_ARGUMENT); + } + data.lineStyle = lineStyle; + data.state &= ~LINE_STYLE; +} + +/** + * Sets the width that will be used when drawing lines + * for all of the figure drawing operations (that is, + * <code>drawLine</code>, <code>drawRectangle</code>, + * <code>drawPolyline</code>, and so forth. + * <p> + * Note that line width of zero is used as a hint to + * indicate that the fastest possible line drawing + * algorithms should be used. This means that the + * output may be different from line width one. + * </p> + * + * @param lineWidth the width of a line + * + * @exception DWTException <ul> + * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> + * </ul> + */ +public void setLineWidth(int lineWidth) { + if (handle is null) DWT.error(DWT.ERROR_GRAPHIC_DISPOSED); + if (data.lineWidth is lineWidth) return; + data.lineWidth = lineWidth; + data.state &= ~(LINE_WIDTH | DRAW_OFFSET); +} + +/** + * If the argument is <code>true</code>, puts the receiver + * in a drawing mode where the resulting color in the destination + * is the <em>exclusive or</em> of the color values in the source + * and the destination, and if the argument is <code>false</code>, + * puts the receiver in a drawing mode where the destination color + * is replaced with the source color value. + * <p> + * Note that this mode in fundamentally unsupportable on certain + * platforms, notably Carbon (Mac OS X). Clients that want their + * code to run on all platforms need to avoid this method. + * </p> + * + * @param xor if <code>true</code>, then <em>xor</em> mode is used, otherwise <em>source copy</em> mode is used + * + * @exception DWTException <ul> + * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> + * </ul> + * + * @deprecated this functionality is not supported on some platforms + */ +public void setXORMode(bool xor) { + if (handle is null) DWT.error(DWT.ERROR_GRAPHIC_DISPOSED); + data.xorMode = xor; +} + +/** + * Sets the receiver's text anti-aliasing value to the parameter, + * which must be one of <code>DWT.DEFAULT</code>, <code>DWT.OFF</code> + * or <code>DWT.ON</code>. Note that this controls anti-aliasing only + * for all <em>text drawing</em> operations. + * <p> + * This operation requires the operating system's advanced + * graphics subsystem which may not be available on some + * platforms. + * </p> + * + * @param antialias the anti-aliasing setting + * + * @exception IllegalArgumentException <ul> + * <li>ERROR_INVALID_ARGUMENT - if the parameter is not one of <code>DWT.DEFAULT</code>, + * <code>DWT.OFF</code> or <code>DWT.ON</code></li> + * </ul> + * @exception DWTException <ul> + * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> + * <li>ERROR_NO_GRAPHICS_LIBRARY - if advanced graphics are not available</li> + * </ul> + * + * @see #getAdvanced + * @see #setAdvanced + * @see #setAntialias + * + * @since 3.1 + */ +public void setTextAntialias(int antialias) { + if (handle is null) DWT.error(DWT.ERROR_GRAPHIC_DISPOSED); + switch (antialias) { + case DWT.DEFAULT: + case DWT.OFF: + case DWT.ON: + break; + default: + DWT.error(DWT.ERROR_INVALID_ARGUMENT); + } + data.textAntialias = antialias; +} + +/** + * Sets the transform that is currently being used by the receiver. If + * the argument is <code>null</code>, the current transform is set to + * the identity transform. + * <p> + * This operation requires the operating system's advanced + * graphics subsystem which may not be available on some + * platforms. + * </p> + * + * @param transform the transform to set + * + * @exception IllegalArgumentException <ul> + * <li>ERROR_INVALID_ARGUMENT - if the parameter has been disposed</li> + * </ul> + * @exception DWTException <ul> + * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> + * <li>ERROR_NO_GRAPHICS_LIBRARY - if advanced graphics are not available</li> + * </ul> + * + * @see Transform + * @see #getAdvanced + * @see #setAdvanced + * + * @since 3.1 + */ +public void setTransform(Transform transform) { + if (handle is null) DWT.error(DWT.ERROR_GRAPHIC_DISPOSED); + if (transform !is null && transform.isDisposed()) DWT.error(DWT.ERROR_INVALID_ARGUMENT); + if (transform !is null) { + if (data.transform !is null) data.transform.release(); + if (data.inverseTransform !is null) data.inverseTransform.release(); + data.transform = ((NSAffineTransform)new NSAffineTransform().alloc()).initWithTransform(transform.handle); + data.inverseTransform = ((NSAffineTransform)new NSAffineTransform().alloc()).initWithTransform(transform.handle); + NSAffineTransformStruct struct = data.inverseTransform.transformStruct(); + if ((struct.m11 * struct.m22 - struct.m12 * struct.m21) !is 0) { + data.inverseTransform.invert(); + } + } else { + data.transform = data.inverseTransform = null; + } + data.state &= ~(TRANSFORM | DRAW_OFFSET); +} + +/** + * Returns the extent of the given string. No tab + * expansion or carriage return processing will be performed. + * <p> + * The <em>extent</em> of a string is the width and height of + * the rectangular area it would cover if drawn in a particular + * font (in this case, the current font in the receiver). + * </p> + * + * @param string the string to measure + * @return a point containing the extent of the string + * + * @exception IllegalArgumentException <ul> + * <li>ERROR_NULL_ARGUMENT - if the string is null</li> + * </ul> + * @exception DWTException <ul> + * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> + * </ul> + */ +public Point stringExtent(String string) { + return textExtent(string, 0); +} + +/** + * Returns the extent of the given string. Tab expansion and + * carriage return processing are performed. + * <p> + * The <em>extent</em> of a string is the width and height of + * the rectangular area it would cover if drawn in a particular + * font (in this case, the current font in the receiver). + * </p> + * + * @param string the string to measure + * @return a point containing the extent of the string + * + * @exception IllegalArgumentException <ul> + * <li>ERROR_NULL_ARGUMENT - if the string is null</li> + * </ul> + * @exception DWTException <ul> + * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> + * </ul> + */ +public Point textExtent(String string) { + return textExtent(string, DWT.DRAW_DELIMITER | DWT.DRAW_TAB); +} + +/** + * Returns the extent of the given string. Tab expansion, line + * delimiter and mnemonic processing are performed according to + * the specified flags, which can be a combination of: + * <dl> + * <dt><b>DRAW_DELIMITER</b></dt> + * <dd>draw multiple lines</dd> + * <dt><b>DRAW_TAB</b></dt> + * <dd>expand tabs</dd> + * <dt><b>DRAW_MNEMONIC</b></dt> + * <dd>underline the mnemonic character</dd> + * <dt><b>DRAW_TRANSPARENT</b></dt> + * <dd>transparent background</dd> + * </dl> + * <p> + * The <em>extent</em> of a string is the width and height of + * the rectangular area it would cover if drawn in a particular + * font (in this case, the current font in the receiver). + * </p> + * + * @param string the string to measure + * @param flags the flags specifying how to process the text + * @return a point containing the extent of the string + * + * @exception IllegalArgumentException <ul> + * <li>ERROR_NULL_ARGUMENT - if the string is null</li> + * </ul> + * @exception DWTException <ul> + * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> + * </ul> + */ +public Point textExtent(String string, int flags) { + if (handle is null) DWT.error(DWT.ERROR_GRAPHIC_DISPOSED); + if (string is null) DWT.error(DWT.ERROR_NULL_ARGUMENT); + checkGC(FONT); + NSAttributedString str = createString(string, flags); + NSSize size = str.size(); + return new Point((int)size.width, (int)size.height); +} + +/** + * Returns a string containing a concise, human-readable + * description of the receiver. + * + * @return a string representation of the receiver + */ +public String toString () { + if (isDisposed()) return "GC {*DISPOSED*}"; + return "GC {" + handle + "}"; +} + +}