blob: 451e4074c393c2f3745bcbf04160fa1843abd510 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2000, 2012 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.swt.graphics;
import org.eclipse.swt.*;
import org.eclipse.swt.internal.*;
import org.eclipse.swt.internal.cocoa.*;
/**
* Class <code>GC</code> is where all of the drawing capabilities that are
* supported by SWT 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 SWT 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>
* The result of drawing on an image that was created with an indexed
* palette using a color that is not in the palette is platform specific.
* Some platforms will match to the nearest color while other will draw
* the color itself. This happens because the allocated image might use
* a direct palette on platforms that do not support indexed palette.
* </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 org.eclipse.swt.events.PaintEvent
* @see <a href="http://www.eclipse.org/swt/snippets/#gc">GC snippets</a>
* @see <a href="http://www.eclipse.org/swt/examples.php">SWT Examples: GraphicsExample, PaintExample</a>
* @see <a href="http://www.eclipse.org/swt/">Sample code and further information</a>
*/
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 SWT
* public API. It is marked public only so that it can be shared
* within the packages provided by SWT. It is not available on all
* platforms and should never be accessed from application code.
* </p>
*
* @noreference This field is not intended to be referenced by clients.
*/
public NSGraphicsContext handle;
Drawable drawable;
GCData data;
CGPathElement element;
int count, typeCount;
byte[] types;
float /*double*/[] points;
float /*double*/ [] point;
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 VISIBLE_REGION = 1 << 12;
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 SWTError <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 SWTError <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 == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
NSAutoreleasePool pool = null;
if (!NSThread.isMainThread()) pool = (NSAutoreleasePool) new NSAutoreleasePool().alloc().init();
try {
GCData data = new GCData();
data.style = checkStyle(style);
int /*long*/ contextId = drawable.internal_new_GC(data);
Device device = data.device;
if (device == null) device = Device.getDevice();
if (device == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
this.device = data.device = device;
init(drawable, data, contextId);
init();
} finally {
if (pool != null) pool.release();
}
}
static int checkStyle (int style) {
if ((style & SWT.LEFT_TO_RIGHT) != 0) style &= ~SWT.RIGHT_TO_LEFT;
return style & (SWT.LEFT_TO_RIGHT | SWT.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 SWT. 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>
*
* @noreference This method is not intended to be referenced by clients.
*/
public static GC cocoa_new(Drawable drawable, GCData data) {
GC gc = new GC();
int /*long*/ context = drawable.internal_new_GC(data);
gc.device = data.device;
gc.init(drawable, data, context);
return gc;
}
int /*long*/ applierFunc(int /*long*/ info, int /*long*/ elementPtr) {
OS.memmove(element, elementPtr, CGPathElement.sizeof);
int type = 0, length = 1;
switch (element.type) {
case OS.kCGPathElementMoveToPoint: type = SWT.PATH_MOVE_TO; break;
case OS.kCGPathElementAddLineToPoint: type = SWT.PATH_LINE_TO; break;
case OS.kCGPathElementAddQuadCurveToPoint: type = SWT.PATH_QUAD_TO; length = 2; break;
case OS.kCGPathElementAddCurveToPoint: type = SWT.PATH_CUBIC_TO; length = 3; break;
case OS.kCGPathElementCloseSubpath: type = SWT.PATH_CLOSE; length = 0; break;
}
if (types != null) {
types[typeCount] = (byte)type;
if (length > 0) {
OS.memmove(point, element.points, length * CGPoint.sizeof);
System.arraycopy(point, 0, points, count, length * 2);
}
}
typeCount++;
count += length * 2;
return 0;
}
NSAutoreleasePool checkGC (int mask) {
NSAutoreleasePool pool = null;
if (!NSThread.isMainThread()) pool = (NSAutoreleasePool) new NSAutoreleasePool().alloc().init();
if (data.flippedContext != null && !handle.isEqual(NSGraphicsContext.currentContext())) {
data.restoreContext = true;
NSGraphicsContext.static_saveGraphicsState();
NSGraphicsContext.setCurrentContext(handle);
}
if ((mask & (CLIPPING | TRANSFORM)) != 0) {
NSView view = data.view;
if ((data.state & CLIPPING) == 0 || (data.state & TRANSFORM) == 0 || (data.state & VISIBLE_REGION) == 0) {
boolean antialias = handle.shouldAntialias();
handle.restoreGraphicsState();
handle.saveGraphicsState();
handle.setShouldAntialias(antialias);
if (view != null && (data.paintRect == null || !view.isFlipped())) {
NSAffineTransform transform = NSAffineTransform.transform();
NSRect rect = view.convertRect_toView_(view.bounds(), null);
if (data.paintRect == null) {
transform.translateXBy(rect.x, rect.y + rect.height);
float /*double*/ userSpaceScaleFactor = view.window().userSpaceScaleFactor();
transform.scaleXBy(userSpaceScaleFactor, userSpaceScaleFactor);
} else {
transform.translateXBy(0, rect.height);
}
transform.scaleXBy(1, -1);
transform.concat();
if (data.visibleRgn != 0) {
if (data.visiblePath == null || (data.state & VISIBLE_REGION) == 0) {
if (data.visiblePath != null) data.visiblePath.release();
data.visiblePath = Region.cocoa_new(device, data.visibleRgn).getPath();
}
data.visiblePath.addClip();
data.state |= VISIBLE_REGION;
}
}
if (data.clipPath != null) data.clipPath.addClip();
if (data.transform != null) data.transform.concat();
mask &= ~(TRANSFORM | CLIPPING);
data.state |= TRANSFORM | CLIPPING;
data.state &= ~(BACKGROUND | FOREGROUND);
}
}
OS.CGContextSetBlendMode(handle.graphicsPort(), data.xorMode ? OS.kCGBlendModeDifference : OS.kCGBlendModeNormal);
int state = data.state;
if ((state & mask) == mask) return pool;
state = (state ^ mask) & mask;
data.state |= mask;
if ((state & FOREGROUND) != 0) {
Pattern pattern = data.foregroundPattern;
if (pattern != null) {
if (pattern.color != null) pattern.color.setStroke();
} else {
float /*double*/ [] color = data.foreground;
if (data.fg != null) data.fg.release();
NSColor fg = data.fg = NSColor.colorWithDeviceRed(color[0], color[1], color[2], data.alpha / 255f);
fg.retain();
fg.setStroke();
}
}
if ((state & FOREGROUND_FILL) != 0) {
Pattern pattern = data.foregroundPattern;
if (pattern != null) {
if (pattern.color != null) pattern.color.setFill();
} else {
float /*double*/ [] color = data.foreground;
if (data.fg != null) data.fg.release();
NSColor fg = data.fg = NSColor.colorWithDeviceRed(color[0], color[1], color[2], data.alpha / 255f);
fg.retain();
fg.setFill();
}
data.state &= ~BACKGROUND;
}
if ((state & BACKGROUND) != 0) {
Pattern pattern = data.backgroundPattern;
if (pattern != null) {
if (pattern.color != null) pattern.color.setFill();
} else {
float /*double*/ [] color = data.background;
if (data.bg != null) data.bg.release();
NSColor bg = data.bg = NSColor.colorWithDeviceRed(color[0], color[1], color[2], data.alpha / 255f);
bg.retain();
bg.setFill();
}
data.state &= ~FOREGROUND_FILL;
}
NSBezierPath path = data.path;
if ((state & LINE_WIDTH) != 0) {
path.setLineWidth(data.lineWidth == 0 ? 1 : data.lineWidth);
switch (data.lineStyle) {
case SWT.LINE_DOT:
case SWT.LINE_DASH:
case SWT.LINE_DASHDOT:
case SWT.LINE_DASHDOTDOT:
state |= LINE_STYLE;
}
}
if ((state & LINE_STYLE) != 0) {
float[] dashes = null;
float width = data.lineWidth;
switch (data.lineStyle) {
case SWT.LINE_SOLID: break;
case SWT.LINE_DASH: dashes = width != 0 ? LINE_DASH : LINE_DASH_ZERO; break;
case SWT.LINE_DOT: dashes = width != 0 ? LINE_DOT : LINE_DOT_ZERO; break;
case SWT.LINE_DASHDOT: dashes = width != 0 ? LINE_DASHDOT : LINE_DASHDOT_ZERO; break;
case SWT.LINE_DASHDOTDOT: dashes = width != 0 ? LINE_DASHDOTDOT : LINE_DASHDOTDOT_ZERO; break;
case SWT.LINE_CUSTOM: dashes = data.lineDashes; break;
}
if (dashes != null) {
float /*double*/[] lengths = new float /*double*/[dashes.length];
for (int i = 0; i < lengths.length; i++) {
lengths[i] = width == 0 || data.lineStyle == SWT.LINE_CUSTOM ? dashes[i] : dashes[i] * width;
}
path.setLineDash(lengths, lengths.length, data.lineDashesOffset);
} else {
path.setLineDash(null, 0, 0);
}
}
if ((state & LINE_MITERLIMIT) != 0) {
path.setMiterLimit(data.lineMiterLimit);
}
if ((state & LINE_JOIN) != 0) {
int joinStyle = 0;
switch (data.lineJoin) {
case SWT.JOIN_MITER: joinStyle = OS.NSMiterLineJoinStyle; break;
case SWT.JOIN_ROUND: joinStyle = OS.NSRoundLineJoinStyle; break;
case SWT.JOIN_BEVEL: joinStyle = OS.NSBevelLineJoinStyle; break;
}
path.setLineJoinStyle(joinStyle);
}
if ((state & LINE_CAP) != 0) {
int capStyle = 0;
switch (data.lineCap) {
case SWT.CAP_ROUND: capStyle = OS.NSRoundLineCapStyle; break;
case SWT.CAP_FLAT: capStyle = OS.NSButtLineCapStyle; break;
case SWT.CAP_SQUARE: capStyle = OS.NSSquareLineCapStyle; break;
}
path.setLineCapStyle(capStyle);
}
if ((state & DRAW_OFFSET) != 0) {
data.drawXOffset = data.drawYOffset = 0;
NSSize size = new NSSize();
size.width = size.height = 1;
if (data.transform != null) {
size = data.transform.transformSize(size);
}
float /*double*/ scaling = size.width;
if (scaling < 0) scaling = -scaling;
float /*double*/ strokeWidth = data.lineWidth * scaling;
if (strokeWidth == 0 || ((int)strokeWidth % 2) == 1) {
data.drawXOffset = 0.5f / scaling;
}
scaling = size.height;
if (scaling < 0) scaling = -scaling;
strokeWidth = data.lineWidth * scaling;
if (strokeWidth == 0 || ((int)strokeWidth % 2) == 1) {
data.drawYOffset = 0.5f / scaling;
}
}
return pool;
}
/**
* Copies a rectangular area of the receiver at the specified
* position into the image, which must be of type <code>SWT.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 SWTException <ul>
* <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
* </ul>
*/
public void copyArea(Image image, int x, int y) {
if (handle == null) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
if (image == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
if (image.type != SWT.BITMAP || image.isDisposed()) SWT.error(SWT.ERROR_INVALID_ARGUMENT);
NSAutoreleasePool pool = checkGC(TRANSFORM | CLIPPING);
try {
if (data.image != null) {
int srcX = x, srcY = y, destX = 0, destY = 0;
NSSize srcSize = data.image.handle.size();
int imgHeight = (int)srcSize.height;
int destWidth = (int)srcSize.width - x, destHeight = (int)srcSize.height - y;
int srcWidth = destWidth, srcHeight = destHeight;
NSGraphicsContext context = NSGraphicsContext.graphicsContextWithBitmapImageRep(image.getRepresentation());
NSGraphicsContext.static_saveGraphicsState();
NSGraphicsContext.setCurrentContext(context);
NSAffineTransform transform = NSAffineTransform.transform();
NSSize size = image.handle.size();
transform.translateXBy(0, size.height-(destHeight + 2 * destY));
transform.concat();
NSRect srcRect = new NSRect();
srcRect.x = srcX;
srcRect.y = imgHeight - (srcY + srcHeight);
srcRect.width = srcWidth;
srcRect.height = srcHeight;
NSRect destRect = new NSRect();
destRect.x = destX;
destRect.y = destY;
destRect.width = destWidth;
destRect.height = destHeight;
data.image.handle.drawInRect(destRect, srcRect, OS.NSCompositeCopy, 1);
NSGraphicsContext.static_restoreGraphicsState();
return;
}
if (data.view != null) {
NSPoint pt = new NSPoint();
pt.x = x;
pt.y = y;
NSWindow window = data.view.window();
pt = data.view.convertPoint_toView_(pt, window.contentView().superview());
NSRect frame = window.frame();
pt.y = frame.height - pt.y;
NSSize size = image.handle.size();
CGRect destRect = new CGRect();
destRect.size.width = size.width;
destRect.size.height = size.height;
CGRect srcRect = new CGRect();
srcRect.origin.x = pt.x;
srcRect.origin.y = pt.y;
srcRect.size.width = size.width;
srcRect.size.height = size.height;
NSBitmapImageRep imageRep = image.getRepresentation();
NSGraphicsContext context = NSGraphicsContext.graphicsContextWithBitmapImageRep(imageRep);
NSGraphicsContext.static_saveGraphicsState();
NSGraphicsContext.setCurrentContext(context);
int /*long*/ contextID = OS.objc_msgSend(NSApplication.sharedApplication().id, OS.sel_contextID);
OS.CGContextCopyWindowContentsToRect(context.graphicsPort(), destRect, contextID, window.windowNumber(), srcRect);
NSGraphicsContext.static_restoreGraphicsState();
return;
}
if (handle.isDrawingToScreen()) {
NSImage imageHandle = image.handle;
NSSize size = imageHandle.size();
CGRect rect = new CGRect();
rect.origin.x = x;
rect.origin.y = y;
rect.size.width = size.width;
rect.size.height = size.height;
int displayCount = 16;
int /*long*/ displays = OS.malloc(4 * displayCount), countPtr = OS.malloc(4);
if (OS.CGGetDisplaysWithRect(rect, displayCount, displays, countPtr) != 0) return;
int[] count = new int[1], display = new int[1];
OS.memmove(count, countPtr, OS.PTR_SIZEOF);
for (int i = 0; i < count[0]; i++) {
OS.memmove(display, displays + (i * 4), 4);
OS.CGDisplayBounds(display[0], rect);
int /*long*/ srcImage = 0;
int /*long*/ address = OS.VERSION >= 0x1070 ? 0 : OS.CGDisplayBaseAddress(display[0]);
if (address != 0) {
int /*long*/ width = OS.CGDisplayPixelsWide(display[0]);
int /*long*/ height = OS.CGDisplayPixelsHigh(display[0]);
int /*long*/ bpr = OS.CGDisplayBytesPerRow(display[0]);
int /*long*/ bpp = OS.CGDisplayBitsPerPixel(display[0]);
int /*long*/ bps = OS.CGDisplayBitsPerSample(display[0]);
int bitmapInfo = OS.kCGImageAlphaNoneSkipFirst;
switch ((int)/*63*/bpp) {
case 16: bitmapInfo |= OS.kCGBitmapByteOrder16Host; break;
case 32: bitmapInfo |= OS.kCGBitmapByteOrder32Host; break;
}
if (OS.__BIG_ENDIAN__() && OS.VERSION >= 0x1040) {
int /*long*/ colorspace = OS.CGColorSpaceCreateDeviceRGB();
int /*long*/ context = OS.CGBitmapContextCreate(address, width, height, bps, bpr, colorspace, bitmapInfo);
OS.CGColorSpaceRelease(colorspace);
srcImage = OS.CGBitmapContextCreateImage(context);
OS.CGContextRelease(context);
} else {
int /*long*/ provider = OS.CGDataProviderCreateWithData(0, address, bpr * height, 0);
int /*long*/ colorspace = OS.CGColorSpaceCreateDeviceRGB();
srcImage = OS.CGImageCreate(width, height, bps, bpp, bpr, colorspace, bitmapInfo, provider, 0, true, 0);
OS.CGColorSpaceRelease(colorspace);
OS.CGDataProviderRelease(provider);
}
} else {
if (OS.VERSION >= 0x1060) srcImage = OS.CGDisplayCreateImage(display[0]);
}
if (srcImage != 0) {
copyArea(image, x - (int)rect.origin.x, y - (int)rect.origin.y, srcImage);
OS.CGImageRelease(srcImage);
}
}
OS.free(displays);
OS.free(countPtr);
}
} finally {
uncheckGC(pool);
}
}
void copyArea (Image image, int x, int y, int /*long*/ srcImage) {
if (srcImage == 0) return;
NSBitmapImageRep rep = image.getRepresentation();
int /*long*/ bpc = rep.bitsPerSample();
int /*long*/ width = rep.pixelsWide();
int /*long*/ height = rep.pixelsHigh();
int /*long*/ bpr = rep.bytesPerRow();
int /*long*/ data = rep.bitmapData();
int /*long*/ format = rep.bitmapFormat();
int alphaInfo;
if (rep.hasAlpha()) {
alphaInfo = (format & OS.NSAlphaFirstBitmapFormat) != 0 ? OS.kCGImageAlphaFirst : OS.kCGImageAlphaLast;
} else {
alphaInfo = (format & OS.NSAlphaFirstBitmapFormat) != 0 ? OS.kCGImageAlphaNoneSkipFirst : OS.kCGImageAlphaNoneSkipLast;
}
int /*long*/ colorspace = OS.CGColorSpaceCreateDeviceRGB();
int /*long*/ context = OS.CGBitmapContextCreate(data, width, height, bpc, bpr, colorspace, alphaInfo);
OS.CGColorSpaceRelease(colorspace);
if (context != 0) {
CGRect rect = new CGRect();
rect.origin.x = -x;
rect.origin.y = y;
rect.size.width = OS.CGImageGetWidth(srcImage);
rect.size.height = OS.CGImageGetHeight(srcImage);
OS.CGContextTranslateCTM(context, 0, -(rect.size.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 SWTException <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 SWTException <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, boolean paint) {
if (handle == null) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
if (width <= 0 || height <= 0) return;
int deltaX = destX - srcX, deltaY = destY - srcY;
if (deltaX == 0 && deltaY == 0) return;
NSAutoreleasePool pool = checkGC(TRANSFORM | CLIPPING);
try {
Image image = data.image;
if (image != null) {
NSImage imageHandle = image.handle;
NSSize size = imageHandle.size();
int imgHeight = (int)size.height;
handle.saveGraphicsState();
NSAffineTransform transform = NSAffineTransform.transform();
transform.scaleXBy(1, -1);
transform.translateXBy(0, -(height + 2 * destY));
transform.concat();
NSRect srcRect = new NSRect();
srcRect.x = srcX;
srcRect.y = imgHeight - (srcY + height);
srcRect.width = width;
srcRect.height = height;
NSRect destRect = new NSRect();
destRect.x = destX;
destRect.y = destY;
destRect.width = width;
destRect.height = height;
imageHandle.drawInRect(destRect, srcRect, OS.NSCompositeCopy, 1);
handle.restoreGraphicsState();
return;
}
if (data.view != null) {
NSView view = data.view;
NSRect visibleRect = view.visibleRect();
if (visibleRect.width <= 0 || visibleRect.height <= 0) return;
NSRect damage = new NSRect();
damage.x = srcX;
damage.y = srcY;
damage.width = width;
damage.height = height;
NSPoint dest = new NSPoint();
dest.x = destX;
dest.y = destY;
view.lockFocus();
OS.NSCopyBits(0, damage , dest);
view.unlockFocus();
if (paint) {
boolean disjoint = (destX + width < srcX) || (srcX + width < destX) || (destY + height < srcY) || (srcY + height < destY);
if (disjoint) {
view.setNeedsDisplayInRect(damage);
} else {
if (deltaX != 0) {
int newX = destX - deltaX;
if (deltaX < 0) newX = destX + width;
damage.x = newX;
damage.width = Math.abs(deltaX);
view.setNeedsDisplayInRect(damage);
}
if (deltaY != 0) {
int newY = destY - deltaY;
if (deltaY < 0) newY = destY + height;
damage.x = srcX;
damage.y = newY;
damage.width = width;
damage.height = Math.abs (deltaY);
view.setNeedsDisplayInRect(damage);
}
}
NSRect srcRect = new NSRect();
srcRect.x = srcX;
srcRect.y = srcY;
srcRect.width = width;
srcRect.height = height;
OS.NSIntersectionRect(visibleRect, visibleRect, srcRect);
if (!OS.NSEqualRects(visibleRect, srcRect)) {
if (srcRect.x != visibleRect.x) {
damage.x = srcRect.x + deltaX;
damage.y = srcRect.y + deltaY;
damage.width = visibleRect.x - srcRect.x;
damage.height = srcRect.height;
view.setNeedsDisplayInRect(damage);
}
if (visibleRect.x + visibleRect.width != srcRect.x + srcRect.width) {
damage.x = srcRect.x + visibleRect.width + deltaX;
damage.y = srcRect.y + deltaY;
damage.width = srcRect.width - visibleRect.width;
damage.height = srcRect.height;
view.setNeedsDisplayInRect(damage);
}
if (visibleRect.y != srcRect.y) {
damage.x = visibleRect.x + deltaX;
damage.y = srcRect.y + deltaY;
damage.width = visibleRect.width;
damage.height = visibleRect.y - srcRect.y;
view.setNeedsDisplayInRect(damage);
}
if (visibleRect.y + visibleRect.height != srcRect.y + srcRect.height) {
damage.x = visibleRect.x + deltaX;
damage.y = visibleRect.y + visibleRect.height + deltaY;
damage.width = visibleRect.width;
damage.height = srcRect.y + srcRect.height - (visibleRect.y + visibleRect.height);
view.setNeedsDisplayInRect(damage);
}
}
}
return;
}
} finally {
uncheckGC(pool);
}
}
static int /*long*/ createCGPathRef(NSBezierPath nsPath) {
int /*long*/ count = nsPath.elementCount();
if (count > 0) {
int /*long*/ cgPath = OS.CGPathCreateMutable();
if (cgPath == 0) SWT.error(SWT.ERROR_NO_HANDLES);
int /*long*/ points = OS.malloc(NSPoint.sizeof * 3);
if (points == 0) SWT.error(SWT.ERROR_NO_HANDLES);
float /*double*/ [] pt = new float /*double*/ [6];
for (int i = 0; i < count; i++) {
int element = (int)/*64*/nsPath.elementAtIndex(i, points);
switch (element) {
case OS.NSMoveToBezierPathElement:
OS.memmove(pt, points, NSPoint.sizeof);
OS.CGPathMoveToPoint(cgPath, 0, pt[0], pt[1]);
break;
case OS.NSLineToBezierPathElement:
OS.memmove(pt, points, NSPoint.sizeof);
OS.CGPathAddLineToPoint(cgPath, 0, pt[0], pt[1]);
break;
case OS.NSCurveToBezierPathElement:
OS.memmove(pt, points, NSPoint.sizeof * 3);
OS.CGPathAddCurveToPoint(cgPath, 0, pt[0], pt[1], pt[2], pt[3], pt[4], pt[5]);
break;
case OS.NSClosePathBezierPathElement:
OS.CGPathCloseSubpath(cgPath);
break;
}
}
OS.free(points);
return cgPath;
}
return 0;
}
void createLayout () {
NSSize size = new NSSize();
size.width = OS.MAX_TEXT_CONTAINER_SIZE;
size.height = OS.MAX_TEXT_CONTAINER_SIZE;
NSTextStorage textStorage = (NSTextStorage)new NSTextStorage().alloc().init();
NSLayoutManager layoutManager = (NSLayoutManager)new NSLayoutManager().alloc().init();
layoutManager.setBackgroundLayoutEnabled(NSThread.isMainThread());
NSTextContainer textContainer = (NSTextContainer)new NSTextContainer().alloc();
textContainer = textContainer.initWithContainerSize(size);
textContainer.setLineFragmentPadding(0);
textStorage.addLayoutManager(layoutManager);
layoutManager.addTextContainer(textContainer);
layoutManager.release();
textContainer.release();
data.textContainer = textContainer;
data.layoutManager = layoutManager;
data.textStorage = textStorage;
}
NSAttributedString createString(String string, int flags, boolean draw) {
NSMutableDictionary dict = ((NSMutableDictionary)new NSMutableDictionary().alloc()).initWithCapacity(5);
Font font = data.font;
dict.setObject(font.handle, OS.NSFontAttributeName);
font.addTraits(dict);
if (draw) {
Pattern pattern = data.foregroundPattern;
if (pattern != null) {
if (pattern.color != null) dict.setObject(pattern.color, OS.NSForegroundColorAttributeName);
} else {
NSColor fg = data.fg;
if (fg == null) {
float /*double*/ [] color = data.foreground;
fg = data.fg = NSColor.colorWithDeviceRed(color[0], color[1], color[2], data.alpha / 255f);
fg.retain();
}
dict.setObject(fg, OS.NSForegroundColorAttributeName);
}
}
if ((flags & SWT.DRAW_TAB) == 0) {
dict.setObject(device.paragraphStyle, OS.NSParagraphStyleAttributeName);
}
int length = string.length();
char[] chars = new char[length];
string.getChars(0, length, chars, 0);
if ((flags & SWT.DRAW_MNEMONIC) !=0 || (flags & SWT.DRAW_DELIMITER) == 0) {
int i=0, j=0;
while (i < chars.length) {
char c = chars [j++] = chars [i++];
switch (c) {
case '&': {
if ((flags & SWT.DRAW_MNEMONIC) != 0) {
if (i == chars.length) {continue;}
if (chars [i] == '&') {i++; continue;}
j--;
}
break;
}
case '\r':
case '\n': {
if ((flags & SWT.DRAW_DELIMITER) == 0) {
if (c == '\r' && i != chars.length && chars[i] == '\n') i++;
j--;
}
break;
}
}
}
length = j;
}
NSString str = ((NSString)new NSString().alloc()).initWithCharacters(chars, length);
NSAttributedString attribStr = ((NSAttributedString)new NSAttributedString().alloc()).initWithString(str, dict);
dict.release();
str.release();
return attribStr;
}
NSBezierPath createNSBezierPath (int /*long*/ cgPath) {
Callback callback = new Callback(this, "applierFunc", 2);
int /*long*/ proc = callback.getAddress();
if (proc == 0) SWT.error(SWT.ERROR_NO_MORE_CALLBACKS);
count = typeCount = 0;
element = new CGPathElement();
OS.CGPathApply(cgPath, 0, proc);
types = new byte[typeCount];
points = new float /*double*/ [count];
point = new float /*double*/ [6];
count = typeCount = 0;
OS.CGPathApply(cgPath, 0, proc);
callback.dispose();
NSBezierPath bezierPath = NSBezierPath.bezierPath();
NSPoint nsPoint = new NSPoint(), nsPoint2 = new NSPoint(), nsPoint3 = new NSPoint();
for (int i = 0, j = 0; i < types.length; i++) {
switch (types[i]) {
case SWT.PATH_MOVE_TO:
nsPoint.x = points[j++];
nsPoint.y = points[j++];
bezierPath.moveToPoint(nsPoint);
break;
case SWT.PATH_LINE_TO:
nsPoint.x = points[j++];
nsPoint.y = points[j++];
bezierPath.lineToPoint(nsPoint);
break;
case SWT.PATH_CUBIC_TO:
nsPoint2.x = points[j++];
nsPoint2.y = points[j++];
nsPoint3.x = points[j++];
nsPoint3.y = points[j++];
nsPoint.x = points[j++];
nsPoint.y = points[j++];
bezierPath.curveToPoint(nsPoint, nsPoint2, nsPoint3);
break;
case SWT.PATH_QUAD_TO:
float /*double*/ currentX = nsPoint.x;
float /*double*/ currentY = nsPoint.y;
nsPoint2.x = points[j++];
nsPoint2.y = points[j++];
nsPoint.x = points[j++];
nsPoint.y = points[j++];
float /*double*/ x0 = currentX;
float /*double*/ y0 = currentY;
float /*double*/ cx1 = x0 + 2 * (nsPoint2.x - x0) / 3;
float /*double*/ cy1 = y0 + 2 * (nsPoint2.y - y0) / 3;
float /*double*/ cx2 = cx1 + (nsPoint.x - x0) / 3;
float /*double*/ cy2 = cy1 + (nsPoint.y - y0) / 3;
nsPoint2.x = cx1;
nsPoint2.y = cy1;
nsPoint3.x = cx2;
nsPoint3.y = cy2;
bezierPath.curveToPoint(nsPoint, nsPoint2, nsPoint3);
break;
case SWT.PATH_CLOSE:
bezierPath.closePath();
break;
default:
dispose();
SWT.error(SWT.ERROR_INVALID_ARGUMENT);
}
}
element = null;
types = null;
points = null;
nsPoint = null;
return bezierPath;
}
void destroy() {
/* Free resources */
Image image = data.image;
if (image != null) {
image.memGC = null;
image.createAlpha();
}
if (data.textStorage != null) data.textStorage.release();
data.textStorage = null;
data.layoutManager = null;
data.textContainer = null;
if (data.fg != null) data.fg.release();
if (data.bg != null) data.bg.release();
if (data.path != null) data.path.release();
if (data.clipPath != null) data.clipPath.release();
if (data.visiblePath != null) data.visiblePath.release();
if (data.transform != null) data.transform.release();
if (data.inverseTransform != null) data.inverseTransform.release();
data.path = data.clipPath = data.visiblePath = null;
data.transform = data.inverseTransform = null;
data.fg = data.bg = null;
/* Dispose the GC */
if (drawable != 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 SWTException <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 == null) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
if (width < 0) {
x = x + width;
width = -width;
}
if (height < 0) {
y = y + height;
height = -height;
}
if (width == 0 || height == 0 || arcAngle == 0) return;
NSAutoreleasePool pool = checkGC(DRAW);
try {
handle.saveGraphicsState();
NSAffineTransform transform = NSAffineTransform.transform();
float /*double*/ 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(center, 1, sAngle, eAngle, arcAngle>0);
path.transformUsingAffineTransform(transform);
Pattern pattern = data.foregroundPattern;
if (pattern != null) setPatternPhase(pattern);
if (pattern != null && pattern.gradient != null) {
strokePattern(path, pattern);
} else {
path.stroke();
}
path.removeAllPoints();
handle.restoreGraphicsState();
} finally {
uncheckGC(pool);
}
}
/**
* 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 SWTException <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 == null) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
NSAutoreleasePool pool = checkGC(CLIPPING | TRANSFORM);
try {
int[] metric = new int[1];
OS.GetThemeMetric(OS.kThemeMetricFocusRectOutset, metric);
CGRect rect = new CGRect();
rect.origin.x = x + metric[0];
rect.origin.y = y + metric[0];
rect.size.width = width - metric[0] * 2;
rect.size.height = height - metric[0] * 2;
OS.HIThemeDrawFocusRect(rect, true, handle.graphicsPort(), OS.kHIThemeOrientationNormal);
} finally {
uncheckGC(pool);
}
}
/**
* 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 SWTException <ul>
* <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
* </ul>
* @exception SWTError <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 == null) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
if (image == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
if (image.isDisposed()) SWT.error(SWT.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 SWTException <ul>
* <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
* </ul>
* @exception SWTError <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 == null) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
if (srcWidth == 0 || srcHeight == 0 || destWidth == 0 || destHeight == 0) return;
if (srcX < 0 || srcY < 0 || srcWidth < 0 || srcHeight < 0 || destWidth < 0 || destHeight < 0) {
SWT.error (SWT.ERROR_INVALID_ARGUMENT);
}
if (image == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
if (image.isDisposed()) SWT.error(SWT.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, boolean simple) {
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 == 0 && srcY == 0 &&
srcWidth == destWidth && destWidth == imgWidth &&
srcHeight == destHeight && destHeight == imgHeight;
if (srcX + srcWidth > imgWidth || srcY + srcHeight > imgHeight) {
SWT.error(SWT.ERROR_INVALID_ARGUMENT);
}
}
NSAutoreleasePool pool = checkGC(CLIPPING | TRANSFORM);
try {
if (srcImage.memGC != 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 = imgHeight - (srcY + srcHeight);
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, data.alpha / 255f);
handle.restoreGraphicsState();
} finally {
uncheckGC(pool);
}
}
/**
* 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 SWTException <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 == null) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
if (x1 == x2 && y1 == y2 && data.lineWidth <= 1) {
drawPoint(x1, y1);
return;
}
NSAutoreleasePool pool = checkGC(DRAW);
try {
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);
Pattern pattern = data.foregroundPattern;
if (pattern != null) setPatternPhase(pattern);
if (pattern != null && pattern.gradient != null) {
strokePattern(path, pattern);
} else {
path.stroke();
}
path.removeAllPoints();
} finally {
uncheckGC(pool);
}
}
/**
* 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 SWTException <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 == null) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
NSAutoreleasePool pool = checkGC(DRAW);
try {
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);
Pattern pattern = data.foregroundPattern;
if (pattern != null) setPatternPhase(pattern);
if (pattern != null && pattern.gradient != null) {
strokePattern(path, pattern);
} else {
path.stroke();
}
path.removeAllPoints();
} finally {
uncheckGC(pool);
}
}
/**
* 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 SWTException <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 == null) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
if (path == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
if (path.handle == null) SWT.error(SWT.ERROR_INVALID_ARGUMENT);
NSAutoreleasePool pool = checkGC(DRAW);
try {
handle.saveGraphicsState();
NSAffineTransform transform = NSAffineTransform.transform();
transform.translateXBy(data.drawXOffset, data.drawYOffset);
transform.concat();
NSBezierPath drawPath = data.path;
drawPath.appendBezierPath(path.handle);
Pattern pattern = data.foregroundPattern;
if (pattern != null) setPatternPhase(pattern);
if (pattern != null && pattern.gradient != null) {
strokePattern(drawPath, pattern);
} else {
drawPath.stroke();
}
drawPath.removeAllPoints();
handle.restoreGraphicsState();
} finally {
uncheckGC(pool);
}
}
/**
* 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 SWTException <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 == null) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
NSAutoreleasePool pool = checkGC(FOREGROUND_FILL | CLIPPING | TRANSFORM);
try {
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();
} finally {
uncheckGC(pool);
}
}
/**
* 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 SWTException <ul>
* <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
* </ul>
*/
public void drawPolygon(int[] pointArray) {
if (handle == null) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
if (pointArray == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
if (pointArray.length < 4) return;
NSAutoreleasePool pool = checkGC(DRAW);
try {
float /*double*/ 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();
Pattern pattern = data.foregroundPattern;
if (pattern != null) setPatternPhase(pattern);
if (pattern != null && pattern.gradient != null) {
strokePattern(path, pattern);
} else {
path.stroke();
}
path.removeAllPoints();
} finally {
uncheckGC(pool);
}
}
/**
* 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 SWTException <ul>
* <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
* </ul>
*/
public void drawPolyline(int[] pointArray) {
if (handle == null) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
if (pointArray == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
if (pointArray.length < 4) return;
NSAutoreleasePool pool = checkGC(DRAW);
try {
float /*double*/ 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);
}
Pattern pattern = data.foregroundPattern;
if (pattern != null) setPatternPhase(pattern);
if (pattern != null && pattern.gradient != null) {
strokePattern(path, pattern);
} else {
path.stroke();
}
path.removeAllPoints();
} finally {
uncheckGC(pool);
}
}
/**
* 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 SWTException <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 == null) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
NSAutoreleasePool pool = checkGC(DRAW);
try {
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);
Pattern pattern = data.foregroundPattern;
if (pattern != null) setPatternPhase(pattern);
if (pattern != null && pattern.gradient != null) {
strokePattern(path, pattern);
} else {
path.stroke();
}
path.removeAllPoints();
} finally {
uncheckGC(pool);
}
}
/**
* 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 SWTException <ul>
* <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
* </ul>
*/
public void drawRectangle(Rectangle rect) {
if (handle == null) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
if (rect == null) SWT.error(SWT.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 SWTException <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 == null) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
if (arcWidth == 0 || arcHeight == 0) {
drawRectangle(x, y, width, height);
return;
}
NSAutoreleasePool pool = checkGC(DRAW);
try {
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 / 2f, arcHeight / 2f);
Pattern pattern = data.foregroundPattern;
if (pattern != null) setPatternPhase(pattern);
if (pattern != null && pattern.gradient != null) {
strokePattern(path, pattern);
} else {
path.stroke();
}
path.removeAllPoints();
} finally {
uncheckGC(pool);
}
}
/**
* 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 SWTException <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 SWTException <ul>
* <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
* </ul>
*/
public void drawString(String string, int x, int y, boolean isTransparent) {
drawText(string, x, y, isTransparent ? SWT.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 SWTException <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, SWT.DRAW_DELIMITER | SWT.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 SWTException <ul>
* <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
* </ul>
*/
public void drawText(String string, int x, int y, boolean isTransparent) {
int flags = SWT.DRAW_DELIMITER | SWT.DRAW_TAB;
if (isTransparent) flags |= SWT.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 SWTException <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 == null) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
if (string == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
NSAutoreleasePool pool = checkGC(CLIPPING | TRANSFORM | FONT | FOREGROUND_FILL);
try {
int length = string.length();
if (length == 0) return;
boolean mode = true;
switch (data.textAntialias) {
case SWT.DEFAULT:
/* Printer is off by default */
if (!handle.isDrawingToScreen()) mode = false;
break;
case SWT.OFF: mode = false; break;
case SWT.ON: mode = true; break;
}
handle.saveGraphicsState();
handle.setShouldAntialias(mode);
if (data.textStorage == null) createLayout();
NSAttributedString attribStr = createString(string, flags, true);
data.textStorage.setAttributedString(attribStr);
attribStr.release();
NSPoint pt = new NSPoint();
pt.x = x;
pt.y = y;
NSRange range = data.layoutManager.glyphRangeForTextContainer(data.textContainer);
if ((flags & SWT.DRAW_TRANSPARENT) == 0) {
NSRect rect = data.layoutManager.usedRectForTextContainer(data.textContainer);
rect.x = x;
rect.y = y;
Pattern pattern = data.backgroundPattern;
if (pattern != null) setPatternPhase(pattern);
if (pattern != null && pattern.gradient != null) {
NSBezierPath path = NSBezierPath.bezierPathWithRect(rect);
fillPattern(path, pattern);
} else {
NSColor bg = data.bg;
if (bg == null) {
float /*double*/ [] color = data.background;
bg = data.bg = NSColor.colorWithDeviceRed(color[0], color[1], color[2], data.alpha / 255f);
bg.retain();
}
bg.setFill();
NSBezierPath.fillRect(rect);
}
}
data.layoutManager.drawGlyphsForGlyphRange(range, pt);
handle.restoreGraphicsState();
} finally {
uncheckGC(pool);
}
}
/**
* 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 boolean equals(Object object) {
if (object == this) return true;
if (!(object instanceof GC)) return false;
return handle == ((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 SWTException <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 == null) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
if (width < 0) {
x = x + width;
width = -width;
}
if (height < 0) {
y = y + height;
height = -height;
}
if (width == 0 || height == 0 || arcAngle == 0) return;
NSAutoreleasePool pool = checkGC(FILL);
try {
handle.saveGraphicsState();
NSAffineTransform transform = NSAffineTransform.transform();
float /*double*/ 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(center, 1, sAngle, eAngle, arcAngle>0);
path.closePath();
path.transformUsingAffineTransform(transform);
Pattern pattern = data.backgroundPattern;
if (pattern != null) setPatternPhase(pattern);
if (pattern != null && pattern.gradient != null) {
fillPattern(path, pattern);
} else {
path.fill();
}
path.removeAllPoints();
handle.restoreGraphicsState();
} finally {
uncheckGC(pool);
}
}
/**
* 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 SWTException <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, boolean vertical) {
if (handle == null) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
if ((width == 0) || (height == 0)) return;
NSAutoreleasePool pool = checkGC(CLIPPING | TRANSFORM);
try {
RGB backgroundRGB, foregroundRGB;
backgroundRGB = getBackground().getRGB();
foregroundRGB = getForeground().getRGB();
RGB fromRGB, toRGB;
fromRGB = foregroundRGB;
toRGB = backgroundRGB;
boolean 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(rect, vertical ? 90 : 0);
gradient.release();
}
} finally {
uncheckGC(pool);
}
}
/**
* 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 SWTException <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 == null) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
NSAutoreleasePool pool = checkGC(FILL);
try {
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 != null) setPatternPhase(pattern);
if (pattern != null && pattern.gradient != null) {
fillPattern(path, pattern);
} else {
path.fill();
}
path.removeAllPoints();
} finally {
uncheckGC(pool);
}
}
void fillPattern(NSBezierPath path, Pattern pattern) {
handle.saveGraphicsState();
path.addClip();
NSRect bounds = path.bounds();
NSPoint start = new NSPoint();
start.x = pattern.pt1.x;
start.y = pattern.pt1.y;
NSPoint end = new NSPoint();
end.x = pattern.pt2.x;
end.y = pattern.pt2.y;
float /*double*/ difx = end.x - start.x;
float /*double*/ dify = end.y - start.y;
if (difx == 0 && dify == 0) {
float /*double*/ [] color = pattern.color1;
NSColor.colorWithDeviceRed(color[0], color[1], color[2], data.alpha / 255f).setFill();
path.fill();
handle.restoreGraphicsState();
return;
}
float /*double*/ startx, starty, endx, endy;
if (difx == 0 || dify == 0) {
startx = bounds.x;
starty = bounds.y;
endx = bounds.x + bounds.width;
endy = bounds.y + bounds.height;
if (difx < 0 || dify < 0) {
startx = endx;
starty = endy;
endx = bounds.x;
endy = bounds.y;
}
} else {
float /*double*/ m = (end.y-start.y)/(end.x - start.x);
float /*double*/ b = end.y - (m * end.x);
float /*double*/ m2 = -1/m; //perpendicular slope
float /*double*/ b2 = bounds.y - (m2 * bounds.x);
startx = endx = (b - b2) / (m2 - m);
b2 = (bounds.y + bounds.height) - (m2 * bounds.x);
float /*double*/ x2 = (b - b2) / (m2 - m);
startx = difx > 0 ? Math.min(startx, x2) : Math.max(startx, x2);
endx = difx < 0 ? Math.min(endx, x2) : Math.max(endx, x2);
b2 = bounds.y - (m2 * (bounds.x + bounds.width));
x2 = (b - b2) / (m2 - m);
startx = difx > 0 ? Math.min(startx, x2) : Math.max(startx, x2);
endx = difx < 0 ? Math.min(endx, x2) : Math.max(endx, x2);
b2 = (bounds.y + bounds.height) - (m2 * (bounds.x + bounds.width));
x2 = (b - b2) / (m2 - m);
startx = difx > 0 ? Math.min(startx, x2) : Math.max(startx, x2);
endx = difx < 0 ? Math.min(endx, x2) : Math.max(endx, x2);
starty = (m * startx) + b;
endy = (m * endx) + b;
}
if (difx != 0) {
while ((difx > 0 && start.x >= startx) || (difx < 0 && start.x <= startx)) {
start.x -= difx;
start.y -= dify;
}
} else {
while ((dify > 0 && start.y >= starty) || (dify < 0 && start.y <= starty)) {
start.x -= difx;
start.y -= dify;
}
}
end.x = start.x;
end.y = start.y;
do {
end.x += difx;
end.y += dify;
pattern.gradient.drawFromPoint(start, end, 0);
start.x = end.x;
start.y = end.y;
} while (
(difx > 0 && end.x <= endx) ||
(difx < 0 && end.x >= endx) ||
(difx == 0 && ((dify > 0 && end.y <= endy) || (dify < 0 && end.y >= endy)))
);
handle.restoreGraphicsState();
}
/**
* 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 SWTException <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 == null) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
if (path == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
if (path.handle == null) SWT.error(SWT.ERROR_INVALID_ARGUMENT);
NSAutoreleasePool pool = checkGC(FILL);
try {
NSBezierPath drawPath = data.path;
drawPath.appendBezierPath(path.handle);
Pattern pattern = data.backgroundPattern;
if (pattern != null) setPatternPhase(pattern);
if (pattern != null && pattern.gradient != null) {
fillPattern(drawPath, pattern);
} else {
drawPath.fill();
}
drawPath.removeAllPoints();
} finally {
uncheckGC(pool);
}
}
/**
* 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 SWTException <ul>
* <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
* </ul>
*
* @see #drawPolygon
*/
public void fillPolygon(int[] pointArray) {
if (handle == null) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
if (pointArray == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
if (pointArray.length < 4) return;
NSAutoreleasePool pool = checkGC(FILL);
try {
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 != null) setPatternPhase(pattern);
if (pattern != null && pattern.gradient != null) {
fillPattern(path, pattern);
} else {
path.fill();
}
path.removeAllPoints();
} finally {
uncheckGC(pool);
}
}
/**
* 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 SWTException <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 == null) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
NSAutoreleasePool pool = checkGC(FILL);
try {
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 != null) setPatternPhase(pattern);
if (pattern != null && pattern.gradient != null) {
fillPattern(path, pattern);
} else {
path.fill();
}
path.removeAllPoints();
} finally {
uncheckGC(pool);
}
}
/**
* 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 SWTException <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 == null) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
if (rect == null) SWT.error(SWT.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 SWTException <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 == null) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
if (arcWidth == 0 || arcHeight == 0) {
fillRectangle(x, y, width, height);
return;
}
NSAutoreleasePool pool = checkGC(FILL);
try {
NSBezierPath path = data.path;
NSRect rect = new NSRect();
rect.x = x;
rect.y = y;
rect.width = width;
rect.height = height;
path.appendBezierPathWithRoundedRect(rect, arcWidth / 2f, arcHeight / 2f);
Pattern pattern = data.backgroundPattern;
if (pattern != null) setPatternPhase(pattern);
if (pattern != null && pattern.gradient != null) {
fillPattern(path, pattern);
} else {
path.fill();
}
path.removeAllPoints();
} finally {
uncheckGC(pool);
}
}
void strokePattern(NSBezierPath path, Pattern pattern) {
handle.saveGraphicsState();
int /*long*/ cgPath = createCGPathRef(path);
int /*long*/ cgContext = handle.graphicsPort();
OS.CGContextSaveGState(cgContext);
initCGContext(cgContext);
OS.CGContextAddPath(cgContext, cgPath);
OS.CGContextReplacePathWithStrokedPath(cgContext);
OS.CGPathRelease(cgPath);
cgPath = 0;
cgPath = OS.CGContextCopyPath(cgContext);
if (cgPath == 0) SWT.error(SWT.ERROR_NO_HANDLES);
OS.CGContextRestoreGState(cgContext);
NSBezierPath strokePath = createNSBezierPath(cgPath);
OS.CGPathRelease(cgPath);
fillPattern(strokePath, pattern);
handle.restoreGraphicsState();
}
void flush () {
handle.flushGraphics();
}
/**
* 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 SWTException <ul>
* <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
* </ul>
*/
public int getAdvanceWidth(char ch) {
if (handle == null) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
//NOT DONE
return stringExtent(new String(new char[]{ch})).x;
}
/**
* Returns the background color.
*
* @return the receiver's background color
*
* @exception SWTException <ul>
* <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
* </ul>
*/
public Color getBackground() {
if (handle == null) SWT.error(SWT.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 SWTException <ul>
* <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
* </ul>
*
* @see Pattern
*
* @since 3.1
*/
public Pattern getBackgroundPattern() {
if (handle == null) SWT.error(SWT.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 SWTException <ul>
* <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
* </ul>
*
* @see #setAdvanced
*
* @since 3.1
*/
public boolean getAdvanced() {
if (handle == null) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
return true;
}
/**
* Returns the receiver's alpha value. The alpha value
* is between 0 (transparent) and 255 (opaque).
*
* @return the alpha value
*
* @exception SWTException <ul>
* <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
* </ul>
*
* @since 3.1
*/
public int getAlpha() {
if (handle == null) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
return data.alpha;
}
/**
* Returns the receiver's anti-aliasing setting value, which will be
* one of <code>SWT.DEFAULT</code>, <code>SWT.OFF</code> or
* <code>SWT.ON</code>. Note that this controls anti-aliasing for all
* <em>non-text drawing</em> operations.
*
* @return the anti-aliasing setting
*
* @exception SWTException <ul>
* <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
* </ul>
*
* @see #getTextAntialias
*
* @since 3.1
*/
public int getAntialias() {
if (handle == null) SWT.error(SWT.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 SWTException <ul>
* <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
* </ul>
*/
public int getCharWidth(char ch) {
if (handle == null) SWT.error(SWT.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 SWTException <ul>
* <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
* </ul>
*/
public Rectangle getClipping() {
if (handle == null) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
NSAutoreleasePool pool = null;
if (!NSThread.isMainThread()) pool = (NSAutoreleasePool) new NSAutoreleasePool().alloc().init();
try {
NSRect rect = null;
if (data.view != null) {
rect = data.view.visibleRect();
} else {
rect = new NSRect();
if (data.image != null) {
NSSize size = data.image.handle.size();
rect.width = size.width;
rect.height = size.height;
} else if (data.size != null) {
rect.width = data.size.width;
rect.height = data.size.height;
}
}
if (data.paintRect != null || data.clipPath != null || data.inverseTransform != null) {
if (data.paintRect != null) {
OS.NSIntersectionRect(rect, rect, data.paintRect);
}
if (data.clipPath != null) {
NSRect clip = data.clipPath.bounds();
clip.x = (int)clip.x;
clip.y = (int)clip.y;
OS.NSIntersectionRect(rect, rect, clip);
}
if (data.inverseTransform != 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);
} finally {
if (pool != null) pool.release();
}
}
/**
* 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 SWTException <ul>
* <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
* </ul>
*/
public void getClipping(Region region) {
if (handle == null) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
if (region == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
if (region.isDisposed()) SWT.error(SWT.ERROR_INVALID_ARGUMENT);
NSAutoreleasePool pool = null;
if (!NSThread.isMainThread()) pool = (NSAutoreleasePool) new NSAutoreleasePool().alloc().init();
try {
region.subtract(region);
NSRect rect = null;
if (data.view != null) {
rect = data.view.visibleRect();
} else {
rect = new NSRect();
if (data.image != null) {
NSSize size = data.image.handle.size();
rect.width = size.width;
rect.height = size.height;
} else if (data.size != 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 != null) {
region.intersect((int)paintRect.x, (int)paintRect.y, (int)paintRect.width, (int)paintRect.height);
}
if (data.clipPath != null) {
NSBezierPath clip = data.clipPath.bezierPathByFlatteningPath();
int count = (int)/*64*/clip.elementCount();
int pointCount = 0;
Region clipRgn = new Region(device);
int[] pointArray = new int[count * 2];
int /*long*/ points = OS.malloc(NSPoint.sizeof);
if (points == 0) SWT.error(SWT.ERROR_NO_HANDLES);
NSPoint pt = new NSPoint();
for (int i = 0; i < count; i++) {
int element = (int)/*64*/clip.elementAtIndex(i, points);
switch (element) {
case OS.NSMoveToBezierPathElement:
if (pointCount != 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 != 0) clipRgn.add(pointArray, pointCount);
pointCount = 0;
break;
}
}
if (pointCount != 0) clipRgn.add(pointArray, pointCount);
OS.free(points);
region.intersect(clipRgn);
clipRgn.dispose();
}
if (data.inverseTransform != null) {
region.convertRgn(data.inverseTransform);
}
} finally {
if (pool != null) pool.release();
}
}
/**
* Returns the receiver's fill rule, which will be one of
* <code>SWT.FILL_EVEN_ODD</code> or <code>SWT.FILL_WINDING</code>.
*
* @return the receiver's fill rule
*
* @exception SWTException <ul>
* <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
* </ul>
*
* @since 3.1
*/
public int getFillRule() {
if (handle == null) SWT.error(SWT.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 SWTException <ul>
* <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
* </ul>
*/
public Font getFont() {
if (handle == null) SWT.error(SWT.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 SWTException <ul>
* <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
* </ul>
*/
public FontMetrics getFontMetrics() {
if (handle == null) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
NSAutoreleasePool pool = checkGC(FONT);
try {
if (data.textStorage == null) createLayout();
if (data.font.metrics == null) {
String s = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; //$NON-NLS-1$
NSMutableDictionary dict = ((NSMutableDictionary)new NSMutableDictionary().alloc()).initWithCapacity(3);
dict.setObject(data.font.handle, OS.NSFontAttributeName);
data.font.addTraits(dict);
NSAttributedString attribStr = ((NSAttributedString)new NSAttributedString().alloc()).initWithString(NSString.stringWith(s), dict);
data.textStorage.setAttributedString(attribStr);
attribStr.release();
dict.release();
NSLayoutManager layoutManager = data.layoutManager;
layoutManager.glyphRangeForTextContainer(data.textContainer);
NSRect rect = layoutManager.usedRectForTextContainer(data.textContainer);
int avgWidth = (int) Math.ceil(rect.width) / s.length();
int ascent = (int)layoutManager.defaultBaselineOffsetForFont(data.font.handle);
int height = (int)layoutManager.defaultLineHeightForFont(data.font.handle);
data.font.metrics = FontMetrics.cocoa_new(ascent, height - ascent, avgWidth, 0, height);
}
return data.font.metrics;
} finally {
uncheckGC(pool);
}
}
/**
* Returns the receiver's foreground color.
*
* @return the color used for drawing foreground things
*
* @exception SWTException <ul>
* <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
* </ul>
*/
public Color getForeground() {
if (handle == null) SWT.error(SWT.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 SWTException <ul>
* <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
* </ul>
*
* @see Pattern
*
* @since 3.1
*/
public Pattern getForegroundPattern() {
if (handle == null) SWT.error(SWT.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 SWT. It is not
* available on all platforms, and should never be called from
* application code.
* </p>
*
* @return the receiver's GCData
*
* @exception SWTException <ul>
* <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
* </ul>
*
* @see GCData
*
* @noreference This method is not intended to be referenced by clients.
*
* @since 3.2
*/
public GCData getGCData() {
if (handle == null) SWT.error(SWT.ERROR_WIDGET_DISPOSED);
NSAutoreleasePool pool = checkGC(TRANSFORM | CLIPPING);
uncheckGC(pool);
return data;
}
/**
* Returns the receiver's interpolation setting, which will be one of
* <code>SWT.DEFAULT</code>, <code>SWT.NONE</code>,
* <code>SWT.LOW</code> or <code>SWT.HIGH</code>.
*
* @return the receiver's interpolation setting
*
* @exception SWTException <ul>
* <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
* </ul>
*
* @since 3.1
*/
public int getInterpolation() {
if (handle == null) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
int interpolation = (int)/*64*/handle.imageInterpolation();
switch (interpolation) {
case OS.NSImageInterpolationDefault: return SWT.DEFAULT;
case OS.NSImageInterpolationNone: return SWT.NONE;
case OS.NSImageInterpolationLow: return SWT.LOW;
case OS.NSImageInterpolationHigh: return SWT.HIGH;
}
return SWT.DEFAULT;
}
/**
* Returns the receiver's line attributes.
*
* @return the line attributes used for drawing lines
*
* @exception SWTException <ul>
* <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
* </ul>
*
* @since 3.3
*/
public LineAttributes getLineAttributes() {
if (handle == null) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
float[] dashes = null;
if (data.lineDashes != 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>SWT.CAP_FLAT</code>, <code>SWT.CAP_ROUND</code>,
* or <code>SWT.CAP_SQUARE</code>.
*
* @return the cap style used for drawing lines
*
* @exception SWTException <ul>
* <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
* </ul>
*
* @since 3.1
*/
public int getLineCap() {
if (handle == null) SWT.error(SWT.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 SWTException <ul>
* <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
* </ul>
*
* @since 3.1
*/
public int[] getLineDash() {
if (handle == null) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
if (data.lineDashes == 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>SWT.JOIN_MITER</code>, <code>SWT.JOIN_ROUND</code>,
* or <code>SWT.JOIN_BEVEL</code>.
*
* @return the join style used for drawing lines
*
* @exception SWTException <ul>
* <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
* </ul>
*
* @since 3.1
*/
public int getLineJoin() {
if (handle == null) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
return data.lineJoin;
}
/**
* Returns the receiver's line style, which will be one
* of the constants <code>SWT.LINE_SOLID</code>, <code>SWT.LINE_DASH</code>,
* <code>SWT.LINE_DOT</code>, <code>SWT.LINE_DASHDOT</code> or
* <code>SWT.LINE_DASHDOTDOT</code>.
*
* @return the style used for drawing lines
*
* @exception SWTException <ul>
* <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
* </ul>
*/
public int getLineStyle() {
if (handle == null) SWT.error(SWT.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 SWTException <ul>
* <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
* </ul>
*/
public int getLineWidth() {
if (handle == null) SWT.error(SWT.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 SWTException <ul>
* <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
* </ul>
*
* @since 2.1.2
*/
public int getStyle () {
if (handle == null) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
return data.style;
}
/**
* Returns the receiver's text drawing anti-aliasing setting value,
* which will be one of <code>SWT.DEFAULT</code>, <code>SWT.OFF</code> or
* <code>SWT.ON</code>. Note that this controls anti-aliasing
* <em>only</em> for text drawing operations.
*
* @return the anti-aliasing setting
*
* @exception SWTException <ul>
* <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
* </ul>
*
* @see #getAntialias
*
* @since 3.1
*/
public int getTextAntialias() {
if (handle == null) SWT.error(SWT.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 SWTException <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 == null) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
if (transform == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
if (transform.isDisposed()) SWT.error(SWT.ERROR_INVALID_ARGUMENT);
NSAffineTransform cmt = data.transform;
if (cmt != 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 SWTException <ul>
* <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
* </ul>
*/
public boolean getXORMode() {
if (handle == null) SWT.error(SWT.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 SWTException <ul>
* <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
* </ul>
*
* @see #equals
*/
public int hashCode() {
return handle != null ? (int)/*64*/handle.id : 0;
}
void init(Drawable drawable, GCData data, int /*long*/ context) {
if (data.foreground != null) data.state &= ~(FOREGROUND | FOREGROUND_FILL);
if (data.background != null) data.state &= ~BACKGROUND;
if (data.font != null) data.state &= ~FONT;
data.state &= ~DRAW_OFFSET;
Image image = data.image;
if (image != 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 == SWT.FILL_WINDING ? OS.NSNonZeroWindingRule : OS.NSEvenOddWindingRule);
data.path.retain();
}
void initCGContext(int /*long*/ cgContext) {
int state = data.state;
if ((state & LINE_WIDTH) != 0) {
OS.CGContextSetLineWidth(cgContext, data.lineWidth == 0 ? 1 : data.lineWidth);
switch (data.lineStyle) {
case SWT.LINE_DOT:
case SWT.LINE_DASH:
case SWT.LINE_DASHDOT:
case SWT.LINE_DASHDOTDOT:
state |= LINE_STYLE;
}
}
if ((state & LINE_STYLE) != 0) {
float[] dashes = null;
float width = data.lineWidth;
switch (data.lineStyle) {
case SWT.LINE_SOLID: break;
case SWT.LINE_DASH: dashes = width != 0 ? LINE_DASH : LINE_DASH_ZERO; break;
case SWT.LINE_DOT: dashes = width != 0 ? LINE_DOT : LINE_DOT_ZERO; break;
case SWT.LINE_DASHDOT: dashes = width != 0 ? LINE_DASHDOT : LINE_DASHDOT_ZERO; break;
case SWT.LINE_DASHDOTDOT: dashes = width != 0 ? LINE_DASHDOTDOT : LINE_DASHDOTDOT_ZERO; break;
case SWT.LINE_CUSTOM: dashes = data.lineDashes; break;
}
if (dashes != null) {
float[] lengths = new float[dashes.length];
for (int i = 0; i < lengths.length; i++) {
lengths[i] = width == 0 || data.lineStyle == SWT.LINE_CUSTOM ? dashes[i] : dashes[i] * width;
}
OS.CGContextSetLineDash(cgContext, data.lineDashesOffset, lengths, lengths.length);
} else {
OS.CGContextSetLineDash(cgContext, 0, null, 0);
}
}
if ((state & LINE_MITERLIMIT) != 0) {
OS.CGContextSetMiterLimit(cgContext, data.lineMiterLimit);
}
if ((state & LINE_JOIN) != 0) {
int joinStyle = 0;
switch (data.lineJoin) {
case SWT.JOIN_MITER: joinStyle = OS.kCGLineJoinMiter; break;
case SWT.JOIN_ROUND: joinStyle = OS.kCGLineJoinRound; break;
case SWT.JOIN_BEVEL: joinStyle = OS.kCGLineJoinBevel; break;
}
OS.CGContextSetLineJoin(cgContext, joinStyle);
}
if ((state & LINE_CAP) != 0) {
int capStyle = 0;
switch (data.lineCap) {
case SWT.CAP_ROUND: capStyle = OS.kCGLineCapRound; break;
case SWT.CAP_FLAT: capStyle = OS.kCGLineCapButt; break;
case SWT.CAP_SQUARE: capStyle = OS.kCGLineCapSquare; break;
}
OS.CGContextSetLineCap(cgContext, capStyle);
}
}
/**
* 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 SWTException <ul>
* <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
* </ul>
*/
public boolean isClipped() {
if (handle == null) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
return data.clipPath != 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 (except {@link #dispose()}) using the GC.
*
* @return <code>true</code> when the GC is disposed and <code>false</code> otherwise
*/
public boolean isDisposed() {
return handle == null;
}
boolean isIdentity(float[] transform) {
return transform[0] == 1 && transform[1] == 0 && transform[2] == 0
&& transform[3] == 1 && transform[4] == 0 && transform[5] == 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 SWTException <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(boolean advanced) {
if (handle == null) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
if (!advanced) {
setAlpha(0xFF);
setAntialias(SWT.DEFAULT);
setBackgroundPattern(null);
setClipping((Rectangle)null);
setForegroundPattern(null);
setInterpolation(SWT.DEFAULT);
setTextAntialias(SWT.DEFAULT);
setTransform(null);
}
}
/**
* Sets the receiver's alpha value which must be
* between 0 (transparent) and 255 (opaque).
* <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 SWTException <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 == null) SWT.error(SWT.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>SWT.DEFAULT</code>, <code>SWT.OFF</code>
* or <code>SWT.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>SWT.DEFAULT</code>,
* <code>SWT.OFF</code> or <code>SWT.ON</code></li>
* </ul>
* @exception SWTException <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 == null) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
boolean mode = true;
switch (antialias) {
case SWT.DEFAULT:
/* Printer is off by default */
if (!handle.isDrawingToScreen()) mode = false;
break;
case SWT.OFF: mode = false; break;
case SWT.ON: mode = true; break;
default:
SWT.error(SWT.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 SWTException <ul>
* <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
* </ul>
*/
public void setBackground(Color color) {
if (handle == null) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
if (color == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
if (color.isDisposed()) SWT.error(SWT.ERROR_INVALID_ARGUMENT);
data.background = color.handle;
data.backgroundPattern = null;
if (data.bg != null) data.bg.release();
data.bg = 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 SWTException <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 == null) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
if (pattern != null && pattern.isDisposed()) SWT.error(SWT.ERROR_INVALID_ARGUMENT);
if (data.backgroundPattern == 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 SWTException <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 == null) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
NSAutoreleasePool pool = null;
if (!NSThread.isMainThread()) pool = (NSAutoreleasePool) new NSAutoreleasePool().alloc().init();
try {
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);
} finally {
if (pool != null) pool.release();
}
}
/**
* 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 SWTException <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 == null) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
if (path != null && path.isDisposed()) SWT.error(SWT.ERROR_INVALID_ARGUMENT);
NSAutoreleasePool pool = null;
if (!NSThread.isMainThread()) pool = (NSAutoreleasePool) new NSAutoreleasePool().alloc().init();
try {
setClipping(new NSBezierPath(path.handle.copy().id));
} finally {
if (pool != null) pool.release();
}
}
/**
* 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 SWTException <ul>
* <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
* </ul>
*/
public void setClipping(Rectangle rect) {
if (handle == null) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
if (rect == 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 SWTException <ul>
* <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
* </ul>
*/
public void setClipping(Region region) {
if (handle == null) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
if (region != null && region.isDisposed()) SWT.error(SWT.ERROR_INVALID_ARGUMENT);
NSAutoreleasePool pool = null;
if (!NSThread.isMainThread()) pool = (NSAutoreleasePool) new NSAutoreleasePool().alloc().init();
try {
setClipping(region != null ? region.getPath() : null);
} finally {
if (pool != null) pool.release();
}
}
void setClipping(NSBezierPath path) {
if (data.clipPath != null) {
data.clipPath.release();
data.clipPath = null;
}
if (path != null) {
data.clipPath = path;
if (data.transform != null) {
data.clipPath.transformUsingAffineTransform(data.transform);
}
}
data.state &= ~CLIPPING;
}
/**
* Sets the receiver's fill rule to the parameter, which must be one of
* <code>SWT.FILL_EVEN_ODD</code> or <code>SWT.FILL_WINDING</code>.
*
* @param rule the new fill rule
*
* @exception IllegalArgumentException <ul>
* <li>ERROR_INVALID_ARGUMENT - if the rule is not one of <code>SWT.FILL_EVEN_ODD</code>
* or <code>SWT.FILL_WINDING</code></li>
* </ul>
* @exception SWTException <ul>
* <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
* </ul>
*
* @since 3.1
*/
public void setFillRule(int rule) {
if (handle == null) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
switch (rule) {
case SWT.FILL_WINDING:
case SWT.FILL_EVEN_ODD: break;
default:
SWT.error(SWT.ERROR_INVALID_ARGUMENT);
}
data.fillRule = rule;
data.path.setWindingRule(rule == SWT.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 SWTException <ul>
* <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
* </ul>
*/
public void setFont(Font font) {
if (handle == null) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
if (font != null && font.isDisposed()) SWT.error(SWT.ERROR_INVALID_ARGUMENT);
data.font = font != 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 SWTException <ul>
* <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
* </ul>
*/
public void setForeground(Color color) {
if (handle == null) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
if (color == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
if (color.isDisposed()) SWT.error(SWT.ERROR_INVALID_ARGUMENT);
data.foreground = color.handle;
data.foregroundPattern = null;
if (data.fg != null) data.fg.release();
data.fg = 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 SWTException <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 == null) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
if (pattern != null && pattern.isDisposed()) SWT.error(SWT.ERROR_INVALID_ARGUMENT);
if (data.foregroundPattern == 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>SWT.DEFAULT</code>, <code>SWT.NONE</code>,
* <code>SWT.LOW</code> or <code>SWT.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>SWT.DEFAULT</code>,
* <code>SWT.NONE</code>, <code>SWT.LOW</code> or <code>SWT.HIGH</code>
* </ul>
* @exception SWTException <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 == null) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
int quality = 0;
switch (interpolation) {
case SWT.DEFAULT: quality = OS.NSImageInterpolationDefault; break;
case SWT.NONE: quality = OS.NSImageInterpolationNone; break;
case SWT.LOW: quality = OS.NSImageInterpolationLow; break;
case SWT.HIGH: quality = OS.NSImageInterpolationHigh; break;
default:
SWT.error(SWT.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 SWTException <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 == null) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
if (attributes == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
int mask = 0;
float lineWidth = attributes.width;
if (lineWidth != data.lineWidth) {
mask |= LINE_WIDTH | DRAW_OFFSET;
}
int lineStyle = attributes.style;
if (lineStyle != data.lineStyle) {
mask |= LINE_STYLE;
switch (lineStyle) {
case SWT.LINE_SOLID:
case SWT.LINE_DASH:
case SWT.LINE_DOT:
case SWT.LINE_DASHDOT:
case SWT.LINE_DASHDOTDOT:
break;
case SWT.LINE_CUSTOM:
if (attributes.dash == null) lineStyle = SWT.LINE_SOLID;
break;
default:
SWT.error(SWT.ERROR_INVALID_ARGUMENT);
}
}
int join = attributes.join;
if (join != data.lineJoin) {
mask |= LINE_JOIN;
switch (join) {
case SWT.JOIN_MITER:
case SWT.JOIN_ROUND:
case SWT.JOIN_BEVEL:
break;
default:
SWT.error(SWT.ERROR_INVALID_ARGUMENT);
}
}
int cap = attributes.cap;
if (cap != data.lineCap) {
mask |= LINE_CAP;
switch (cap) {
case SWT.CAP_FLAT:
case SWT.CAP_ROUND:
case SWT.CAP_SQUARE:
break;
default:
SWT.error(SWT.ERROR_INVALID_ARGUMENT);
}
}
float[] dashes = attributes.dash;
float[] lineDashes = data.lineDashes;
if (dashes != null && dashes.length > 0) {
boolean changed = lineDashes == null || lineDashes.length != dashes.length;
for (int i = 0; i < dashes.length; i++) {
float dash = dashes[i];
if (dash <= 0) SWT.error(SWT.ERROR_INVALID_ARGUMENT);
if (!changed && lineDashes[i] != 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 != null && lineDashes.length > 0) {
mask |= LINE_STYLE;
} else {
dashes = lineDashes;
}
}
float dashOffset = attributes.dashOffset;
if (dashOffset != data.lineDashesOffset) {
mask |= LINE_STYLE;
}
float miterLimit = attributes.miterLimit;
if (miterLimit != data.lineMiterLimit) {
mask |= LINE_MITERLIMIT;
}
if (mask == 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>SWT.CAP_FLAT</code>, <code>SWT.CAP_ROUND</code>,
* or <code>SWT.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 SWTException <ul>
* <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
* </ul>
*
* @since 3.1
*/
public void setLineCap(int cap) {
if (handle == null) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
if (data.lineCap == cap) return;
switch (cap) {
case SWT.CAP_ROUND:
case SWT.CAP_FLAT:
case SWT.CAP_SQUARE:
break;
default:
SWT.error(SWT.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>SWT.LINE_CUSTOM</code>, otherwise
* it is set to <code>SWT.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 SWTException <ul>
* <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
* </ul>
*
* @since 3.1
*/
public void setLineDash(int[] dashes) {
if (handle == null) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
float[] lineDashes = data.lineDashes;
if (dashes != null && dashes.length > 0) {
boolean changed = data.lineStyle != SWT.LINE_CUSTOM || lineDashes == null || lineDashes.length != dashes.length;
for (int i = 0; i < dashes.length; i++) {
int dash = dashes[i];
if (dash <= 0) SWT.error(SWT.ERROR_INVALID_ARGUMENT);
if (!changed && lineDashes[i] != 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 = SWT.LINE_CUSTOM;
} else {
if (data.lineStyle == SWT.LINE_SOLID && (lineDashes == null || lineDashes.length == 0)) return;
data.lineDashes = null;
data.lineStyle = SWT.LINE_SOLID;
}
data.state &= ~LINE_STYLE;
}
/**
* Sets the receiver's line join style to the argument, which must be one
* of the constants <code>SWT.JOIN_MITER</code>, <code>SWT.JOIN_ROUND</code>,
* or <code>SWT.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 SWTException <ul>
* <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
* </ul>
*
* @since 3.1
*/
public void setLineJoin(int join) {
if (handle == null) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
if (data.lineJoin == join) return;
switch (join) {
case SWT.JOIN_MITER:
case SWT.JOIN_ROUND:
case SWT.JOIN_BEVEL:
break;
default:
SWT.error(SWT.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>SWT.LINE_SOLID</code>, <code>SWT.LINE_DASH</code>,
* <code>SWT.LINE_DOT</code>, <code>SWT.LINE_DASHDOT</code> or
* <code>SWT.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 SWTException <ul>
* <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
* </ul>
*/
public void setLineStyle(int lineStyle) {
if (handle == null) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
if (data.lineStyle == lineStyle) return;
switch (lineStyle) {
case SWT.LINE_SOLID:
case SWT.LINE_DASH:
case SWT.LINE_DOT:
case SWT.LINE_DASHDOT:
case SWT.LINE_DASHDOTDOT:
break;
case SWT.LINE_CUSTOM:
if (data.lineDashes == null) lineStyle = SWT.LINE_SOLID;
break;
default:
SWT.error(SWT.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 SWTException <ul>
* <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
* </ul>
*/
public void setLineWidth(int lineWidth) {
if (handle == null) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
if (data.lineWidth == lineWidth) return;
data.lineWidth = lineWidth;
data.state &= ~(LINE_WIDTH | DRAW_OFFSET);
}
void setPatternPhase(Pattern pattern) {
if (pattern.image == null) return;
NSPoint phase = new NSPoint();
if (data.image != null) {
phase.y += data.image.handle.size().height - pattern.image.handle.size().height;
} else if (data.view != null) {
NSView view = data.view;
if (!view.isFlipped()) {
phase.y = view.bounds().height;
}
NSView contentView = view.window().contentView();
phase = view.convertPoint_toView_(phase, contentView);
phase.y = contentView.bounds().height - phase.y;
} else if (data.size != null) {
phase.y += data.size.height - pattern.image.handle.size().height;
}
handle.setPatternPhase(phase);
}
/**
* 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 SWTException <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(boolean xor) {
if (handle == null) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
data.xorMode = xor;
}
/**
* Sets the receiver's text anti-aliasing value to the parameter,
* which must be one of <code>SWT.DEFAULT</code>, <code>SWT.OFF</code>
* or <code>SWT.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>SWT.DEFAULT</code>,
* <code>SWT.OFF</code> or <code>SWT.ON</code></li>
* </ul>
* @exception SWTException <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 == null) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
switch (antialias) {
case SWT.DEFAULT:
case SWT.OFF:
case SWT.ON:
break;
default:
SWT.error(SWT.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 SWTException <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 == null) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
if (transform != null && transform.isDisposed()) SWT.error(SWT.ERROR_INVALID_ARGUMENT);
if (transform != null) {
if (data.transform != null) data.transform.release();
if (data.inverseTransform != 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) != 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 SWTException <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 SWTException <ul>
* <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
* </ul>
*/
public Point textExtent(String string) {
return textExtent(string, SWT.DRAW_DELIMITER | SWT.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 SWTException <ul>
* <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
* </ul>
*/
public Point textExtent(String string, int flags) {
if (handle == null) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
if (string == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
NSAutoreleasePool pool = checkGC(FONT);
try {
int length = string.length();
if (data.textStorage == null) createLayout();
NSAttributedString attribStr = createString(length == 0 ? " " : string, flags, false); //$NON-NLS-1$
data.textStorage.setAttributedString(attribStr);
attribStr.release();
data.layoutManager.glyphRangeForTextContainer(data.textContainer);
NSRect rect = data.layoutManager.usedRectForTextContainer(data.textContainer);
return new Point(length == 0 ? 0 : (int)Math.ceil(rect.width), (int)Math.ceil(rect.height));
} finally {
uncheckGC(pool);
}
}
/**
* 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 + "}";
}
void uncheckGC(NSAutoreleasePool pool) {
if (data.flippedContext != null && data.restoreContext) {
NSGraphicsContext.static_restoreGraphicsState();
data.restoreContext = false;
}
NSView view = data.view;
if (view != null && data.paintRect == null) {
if (data.thread != Thread.currentThread()) flush();
}
if (pool != null) pool.release();
}
}