diff options
author | Felipe Heidrich <fheidric> | 2007-01-26 23:24:43 +0000 |
---|---|---|
committer | Felipe Heidrich <fheidric> | 2007-01-26 23:24:43 +0000 |
commit | 1c3e108eb7a60138c073a4a35f43be1e228cc3ec (patch) | |
tree | 9f9b0aae2e521d730026dfeb0c78f9bb0e0c3e53 /bundles/org.eclipse.swt/Eclipse SWT/wpf/org/eclipse | |
parent | 9e9b7c1991c514a5ce2c57186a01ce1662a5d135 (diff) | |
download | eclipse.platform.swt-1c3e108eb7a60138c073a4a35f43be1e228cc3ec.tar.gz eclipse.platform.swt-1c3e108eb7a60138c073a4a35f43be1e228cc3ec.tar.xz eclipse.platform.swt-1c3e108eb7a60138c073a4a35f43be1e228cc3ec.zip |
initial wpf release
Diffstat (limited to 'bundles/org.eclipse.swt/Eclipse SWT/wpf/org/eclipse')
15 files changed, 9875 insertions, 0 deletions
diff --git a/bundles/org.eclipse.swt/Eclipse SWT/wpf/org/eclipse/swt/graphics/Color.java b/bundles/org.eclipse.swt/Eclipse SWT/wpf/org/eclipse/swt/graphics/Color.java new file mode 100644 index 0000000000..824fb33fc7 --- /dev/null +++ b/bundles/org.eclipse.swt/Eclipse SWT/wpf/org/eclipse/swt/graphics/Color.java @@ -0,0 +1,285 @@ +/******************************************************************************* + * Copyright (c) 2000, 2005 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.internal.wpf.*; +import org.eclipse.swt.*; + +/** + * Instances of this class manage the operating system resources that + * implement SWT's RGB color model. To create a color you can either + * specify the individual color components as integers in the range + * 0 to 255 or provide an instance of an <code>RGB</code>. + * <p> + * Application code must explicitly invoke the <code>Color.dispose()</code> + * method to release the operating system resources managed by each instance + * when those instances are no longer required. + * </p> + * + * @see RGB + * @see Device#getSystemColor + */ + +public final class Color extends Resource { + + /** + * the handle to the OS color resource + * (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> + */ + public int handle; + +/** + * Prevents uninitialized instances from being created outside the package. + */ +Color() { +} + +/** + * Constructs a new instance of this class given a device and the + * desired red, green and blue values expressed as ints in the range + * 0 to 255 (where 0 is black and 255 is full brightness). On limited + * color devices, the color instance created by this call may not have + * the same RGB values as the ones specified by the arguments. The + * RGB values on the returned instance will be the color values of + * the operating system color. + * <p> + * You must dispose the color when it is no longer required. + * </p> + * + * @param device the device on which to allocate the color + * @param red the amount of red in the color + * @param green the amount of green in the color + * @param blue the amount of blue in the color + * + * @exception IllegalArgumentException <ul> + * <li>ERROR_NULL_ARGUMENT - if device is null and there is no current device</li> + * <li>ERROR_INVALID_ARGUMENT - if the red, green or blue argument is not between 0 and 255</li> + * </ul> + * + * @see #dispose + */ +public Color (Device device, int red, int green, int blue) { + if (device == null) device = Device.getDevice(); + if (device == null) SWT.error(SWT.ERROR_NULL_ARGUMENT); + init(device, red, green, blue); + if (device.tracking) device.new_Object(this); +} + +/** + * Constructs a new instance of this class given a device and an + * <code>RGB</code> describing the desired red, green and blue values. + * On limited color devices, the color instance created by this call + * may not have the same RGB values as the ones specified by the + * argument. The RGB values on the returned instance will be the color + * values of the operating system color. + * <p> + * You must dispose the color when it is no longer required. + * </p> + * + * @param device the device on which to allocate the color + * @param rgb the RGB values of the desired color + * + * @exception IllegalArgumentException <ul> + * <li>ERROR_NULL_ARGUMENT - if device is null and there is no current device</li> + * <li>ERROR_NULL_ARGUMENT - if the rgb argument is null</li> + * <li>ERROR_INVALID_ARGUMENT - if the red, green or blue components of the argument are not between 0 and 255</li> + * </ul> + * + * @see #dispose + */ +public Color (Device device, RGB rgb) { + if (device == null) device = Device.getDevice(); + if (device == null) SWT.error(SWT.ERROR_NULL_ARGUMENT); + if (rgb == null) SWT.error(SWT.ERROR_NULL_ARGUMENT); + init(device, rgb.red, rgb.green, rgb.blue); + if (device.tracking) device.new_Object(this); +} + +/** + * Disposes of the operating system resources associated with + * the color. Applications must dispose of all colors which + * they allocate. + */ +public void dispose() { + if (handle == 0) return; + if (device.isDisposed()) return; + OS.GCHandle_Free(handle); + handle = 0; + if (device.tracking) device.dispose_Object(this); + device = null; +} + +/** + * 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 Color)) return false; + Color color = (Color) object; + return device == color.device && (handle & 0xFFFFFF) == (color.handle & 0xFFFFFF); +} + +/** + * Returns the amount of blue in the color, from 0 to 255. + * + * @return the blue component of the color + * + * @exception SWTException <ul> + * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> + * </ul> + */ +public int getBlue () { + if (isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); + return OS.Color_B(handle) & 0xFF; +} + +/** + * Returns the amount of green in the color, from 0 to 255. + * + * @return the green component of the color + * + * @exception SWTException <ul> + * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> + * </ul> + */ +public int getGreen () { + if (isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); + return OS.Color_G(handle) & 0xFF; +} + +/** + * Returns the amount of red in the color, from 0 to 255. + * + * @return the red component of the color + * + * @exception SWTException <ul> + * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> + * </ul> + */ +public int getRed () { + if (isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); + return OS.Color_R(handle) & 0xFF; +} + +/** + * Returns an <code>RGB</code> representing the receiver. + * + * @return the RGB for the color + * + * @exception SWTException <ul> + * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> + * </ul> + */ +public RGB getRGB () { + if (isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); + return new RGB(OS.Color_R(handle) & 0xFF, OS.Color_G(handle) & 0xFF, OS.Color_B(handle) & 0xFF); +} + +/** + * 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 + * + * @see #equals + */ +public int hashCode () { + return handle; +} + +/** + * Allocates the operating system resources associated + * with the receiver. + * + * @param device the device on which to allocate the color + * @param red the amount of red in the color + * @param green the amount of green in the color + * @param blue the amount of blue in the color + * + * @exception IllegalArgumentException <ul> + * <li>ERROR_INVALID_ARGUMENT - if the red, green or blue argument is not between 0 and 255</li> + * </ul> + * + * @see #dispose + */ +void init(Device device, int red, int green, int blue) { + if (red > 255 || red < 0 || green > 255 || green < 0 || blue > 255 || blue < 0) { + SWT.error(SWT.ERROR_INVALID_ARGUMENT); + } + this.device = device; + handle = OS.Color_FromArgb((byte)0xFF, (byte)red, (byte)green, (byte)blue); + if (handle == 0) SWT.error(SWT.ERROR_NO_HANDLES); +} + +/** + * Returns <code>true</code> if the color has been disposed, + * and <code>false</code> otherwise. + * <p> + * This method gets the dispose state for the color. + * When a color has been disposed, it is an error to + * invoke any other method using the color. + * + * @return <code>true</code> when the color is disposed and <code>false</code> otherwise + */ +public boolean isDisposed() { + return handle == 0; +} + +/** + * 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 "Color {*DISPOSED*}"; //$NON-NLS-1$ + return "Color {" + getRed() + ", " + getGreen() + ", " + getBlue() + "}"; //$NON-NLS-1$//$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ +} + +/** + * Invokes platform specific functionality to allocate a new color. + * <p> + * <b>IMPORTANT:</b> This method is <em>not</em> part of the public + * API for <code>Color</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 device the device on which to allocate the color + * @param handle the handle for the color + * @return a new color object containing the specified device and handle + */ +public static Color wpf_new(Device device, int handle) { + if (device == null) device = Device.getDevice(); + Color color = new Color(); + color.handle = handle; + color.device = device; + return color; +} + +} diff --git a/bundles/org.eclipse.swt/Eclipse SWT/wpf/org/eclipse/swt/graphics/Cursor.java b/bundles/org.eclipse.swt/Eclipse SWT/wpf/org/eclipse/swt/graphics/Cursor.java new file mode 100644 index 0000000000..4d59e0abf6 --- /dev/null +++ b/bundles/org.eclipse.swt/Eclipse SWT/wpf/org/eclipse/swt/graphics/Cursor.java @@ -0,0 +1,478 @@ +/******************************************************************************* + * Copyright (c) 2000, 2005 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.internal.wpf.*; +import org.eclipse.swt.*; + +/** + * Instances of this class manage operating system resources that + * specify the appearance of the on-screen pointer. To create a + * cursor you specify the device and either a simple cursor style + * describing one of the standard operating system provided cursors + * or the image and mask data for the desired appearance. + * <p> + * Application code must explicitly invoke the <code>Cursor.dispose()</code> + * method to release the operating system resources managed by each instance + * when those instances are no longer required. + * </p> + * <dl> + * <dt><b>Styles:</b></dt> + * <dd> + * CURSOR_ARROW, CURSOR_WAIT, CURSOR_CROSS, CURSOR_APPSTARTING, CURSOR_HELP, + * CURSOR_SIZEALL, CURSOR_SIZENESW, CURSOR_SIZENS, CURSOR_SIZENWSE, CURSOR_SIZEWE, + * CURSOR_SIZEN, CURSOR_SIZES, CURSOR_SIZEE, CURSOR_SIZEW, CURSOR_SIZENE, CURSOR_SIZESE, + * CURSOR_SIZESW, CURSOR_SIZENW, CURSOR_UPARROW, CURSOR_IBEAM, CURSOR_NO, CURSOR_HAND + * </dd> + * </dl> + * <p> + * Note: Only one of the above styles may be specified. + * </p> + */ + +public final class Cursor extends Resource { + + /** + * the handle to the OS cursor resource + * (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> + */ + public int handle; + +/** + * Prevents uninitialized instances from being created outside the package. + */ +Cursor() { +} + +/** + * Constructs a new cursor given a device and a style + * constant describing the desired cursor appearance. + * <p> + * You must dispose the cursor when it is no longer required. + * </p> + * + * @param device the device on which to allocate the cursor + * @param style the style of cursor to allocate + * + * @exception IllegalArgumentException <ul> + * <li>ERROR_NULL_ARGUMENT - if device is null and there is no current device</li> + * <li>ERROR_INVALID_ARGUMENT - when an unknown style is specified</li> + * </ul> + * @exception SWTError <ul> + * <li>ERROR_NO_HANDLES - if a handle could not be obtained for cursor creation</li> + * </ul> + * + * @see SWT#CURSOR_ARROW + * @see SWT#CURSOR_WAIT + * @see SWT#CURSOR_CROSS + * @see SWT#CURSOR_APPSTARTING + * @see SWT#CURSOR_HELP + * @see SWT#CURSOR_SIZEALL + * @see SWT#CURSOR_SIZENESW + * @see SWT#CURSOR_SIZENS + * @see SWT#CURSOR_SIZENWSE + * @see SWT#CURSOR_SIZEWE + * @see SWT#CURSOR_SIZEN + * @see SWT#CURSOR_SIZES + * @see SWT#CURSOR_SIZEE + * @see SWT#CURSOR_SIZEW + * @see SWT#CURSOR_SIZENE + * @see SWT#CURSOR_SIZESE + * @see SWT#CURSOR_SIZESW + * @see SWT#CURSOR_SIZENW + * @see SWT#CURSOR_UPARROW + * @see SWT#CURSOR_IBEAM + * @see SWT#CURSOR_NO + * @see SWT#CURSOR_HAND + */ +public Cursor(Device device, int style) { + if (device == null) device = Device.getDevice(); + if (device == null) SWT.error(SWT.ERROR_NULL_ARGUMENT); + this.device = device; + switch (style) { + case SWT.CURSOR_HAND: handle = OS.Cursors_Hand(); break; + case SWT.CURSOR_ARROW: handle = OS.Cursors_Arrow(); break; + case SWT.CURSOR_WAIT: handle = OS.Cursors_Wait(); break; + case SWT.CURSOR_CROSS: handle = OS.Cursors_Cross(); break; + case SWT.CURSOR_APPSTARTING: handle = OS.Cursors_AppStarting(); break; + case SWT.CURSOR_HELP: handle = OS.Cursors_Help(); break; + case SWT.CURSOR_SIZEALL: handle = OS.Cursors_SizeAll(); break; + case SWT.CURSOR_SIZENESW: handle = OS.Cursors_SizeNESW(); break; + case SWT.CURSOR_SIZENS: handle = OS.Cursors_SizeNS(); break; + case SWT.CURSOR_SIZENWSE: handle = OS.Cursors_SizeNWSE(); break; + case SWT.CURSOR_SIZEWE: handle = OS.Cursors_SizeWE(); break; + case SWT.CURSOR_SIZEN: handle = OS.Cursors_ScrollN(); break; + case SWT.CURSOR_SIZES: handle = OS.Cursors_ScrollS(); break; + case SWT.CURSOR_SIZEE: handle = OS.Cursors_ScrollE(); break; + case SWT.CURSOR_SIZEW: handle = OS.Cursors_ScrollW(); break; + case SWT.CURSOR_SIZENE: handle = OS.Cursors_ScrollNE(); break; + case SWT.CURSOR_SIZESE: handle = OS.Cursors_ScrollSE(); break; + case SWT.CURSOR_SIZESW: handle = OS.Cursors_ScrollSW(); break; + case SWT.CURSOR_SIZENW: handle = OS.Cursors_ScrollNW(); break; + case SWT.CURSOR_UPARROW: handle = OS.Cursors_UpArrow(); break; + case SWT.CURSOR_IBEAM: handle = OS.Cursors_IBeam(); break; + case SWT.CURSOR_NO: handle = OS.Cursors_No(); break; + default: + SWT.error(SWT.ERROR_INVALID_ARGUMENT); + } + if (handle == 0) SWT.error(SWT.ERROR_NO_HANDLES); + if (device.tracking) device.new_Object(this); +} + +/** + * Constructs a new cursor given a device, image and mask + * data describing the desired cursor appearance, and the x + * and y coordinates of the <em>hotspot</em> (that is, the point + * within the area covered by the cursor which is considered + * to be where the on-screen pointer is "pointing"). + * <p> + * The mask data is allowed to be null, but in this case the source + * must be an ImageData representing an icon that specifies both + * color data and mask data. + * <p> + * You must dispose the cursor when it is no longer required. + * </p> + * + * @param device the device on which to allocate the cursor + * @param source the color data for the cursor + * @param mask the mask data for the cursor (or null) + * @param hotspotX the x coordinate of the cursor's hotspot + * @param hotspotY the y coordinate of the cursor's hotspot + * + * @exception IllegalArgumentException <ul> + * <li>ERROR_NULL_ARGUMENT - if device is null and there is no current device</li> + * <li>ERROR_NULL_ARGUMENT - if the source is null</li> + * <li>ERROR_NULL_ARGUMENT - if the mask is null and the source does not have a mask</li> + * <li>ERROR_INVALID_ARGUMENT - if the source and the mask are not the same + * size, or if the hotspot is outside the bounds of the image</li> + * </ul> + * @exception SWTError <ul> + * <li>ERROR_NO_HANDLES - if a handle could not be obtained for cursor creation</li> + * </ul> + */ +public Cursor(Device device, ImageData source, ImageData mask, int hotspotX, int hotspotY) { + if (device == null) device = Device.getDevice(); + if (device == null) SWT.error(SWT.ERROR_NULL_ARGUMENT); + this.device = device; + if (source == null) SWT.error(SWT.ERROR_NULL_ARGUMENT); + if (mask == null) { + if (source.getTransparencyType() != SWT.TRANSPARENCY_MASK) { + SWT.error(SWT.ERROR_NULL_ARGUMENT); + } + mask = source.getTransparencyMask(); + } + /* Check the bounds. Mask must be the same size as source */ + if (mask.width != source.width || mask.height != source.height) { + SWT.error(SWT.ERROR_INVALID_ARGUMENT); + } + /* Check the hotspots */ + if (hotspotX >= source.width || hotspotX < 0 || + hotspotY >= source.height || hotspotY < 0) { + SWT.error(SWT.ERROR_INVALID_ARGUMENT); + } + /* Convert depth to 1 */ + mask = ImageData.convertMask(mask); + source = ImageData.convertMask(source); + + /* Make sure source and mask scanline pad is 2 */ + byte[] sourceData = ImageData.convertPad(source.data, source.width, source.height, source.depth, source.scanlinePad, 2); + byte[] maskData = ImageData.convertPad(mask.data, mask.width, mask.height, mask.depth, mask.scanlinePad, 2); + + /* Create the cursor */ + int hInst = OS.GetModuleHandleW(null); + int cursor = OS.CreateCursor(hInst, hotspotX, hotspotY, source.width, source.height, sourceData, maskData); + if (cursor == 0) SWT.error(SWT.ERROR_NO_HANDLES); + int safeHandle = OS.gcnew_SWTSafeHandle(cursor, false); + if (safeHandle == 0) SWT.error(SWT.ERROR_NO_HANDLES); + handle = OS.CursorInteropHelper_Create(safeHandle); + if (handle == 0) SWT.error(SWT.ERROR_NO_HANDLES); + OS.GCHandle_Free(safeHandle); + if (device.tracking) device.new_Object(this); +} + +/** + * Constructs a new cursor given a device, image data describing + * the desired cursor appearance, and the x and y coordinates of + * the <em>hotspot</em> (that is, the point within the area + * covered by the cursor which is considered to be where the + * on-screen pointer is "pointing"). + * <p> + * You must dispose the cursor when it is no longer required. + * </p> + * + * @param device the device on which to allocate the cursor + * @param source the image data for the cursor + * @param hotspotX the x coordinate of the cursor's hotspot + * @param hotspotY the y coordinate of the cursor's hotspot + * + * @exception IllegalArgumentException <ul> + * <li>ERROR_NULL_ARGUMENT - if device is null and there is no current device</li> + * <li>ERROR_NULL_ARGUMENT - if the image is null</li> + * <li>ERROR_INVALID_ARGUMENT - if the hotspot is outside the bounds of the + * image</li> + * </ul> + * @exception SWTError <ul> + * <li>ERROR_NO_HANDLES - if a handle could not be obtained for cursor creation</li> + * </ul> + * + * @since 3.0 + */ +public Cursor(Device device, ImageData source, int hotspotX, int hotspotY) { + if (device == null) device = Device.getDevice(); + if (device == null) SWT.error(SWT.ERROR_NULL_ARGUMENT); + this.device = device; + if (source == null) SWT.error(SWT.ERROR_NULL_ARGUMENT); + /* Check the hotspots */ + if (hotspotX >= source.width || hotspotX < 0 || + hotspotY >= source.height || hotspotY < 0) { + SWT.error(SWT.ERROR_INVALID_ARGUMENT); + } + PaletteData palette = source.palette; + if (!(((source.depth == 1 || source.depth == 2 || source.depth == 4 || source.depth == 8) && !palette.isDirect) || + ((source.depth == 8) || (source.depth == 16 || source.depth == 24 || source.depth == 32) && palette.isDirect))) + SWT.error (SWT.ERROR_UNSUPPORTED_DEPTH); + this.device = device; + int width = source.width; + int height = source.height; + int redMask = palette.redMask; + int greenMask = palette.greenMask; + int blueMask = palette.blueMask; + ImageData newData = null; + int pixelFormat = 0; + boolean transparent = source.maskData != null || source.transparentPixel != -1 || source.alpha != -1 || source.alphaData != null; + if (transparent) { + pixelFormat = OS.PixelFormat_Format32bppArgb; + if (!(palette.isDirect && source.depth == 32 && redMask == 0xFF00 && greenMask == 0xFF0000 && blueMask == 0xFF000000)) { + newData = new ImageData(width, height, 32, new PaletteData(0xFF00, 0xFF0000, 0xFF000000)); + } + } else { + switch (source.depth) { + case 1: + case 2: + case 4: + case 8: + pixelFormat = OS.PixelFormat_Format24bppRgb; + newData = new ImageData(source.width, source.height, 24, new PaletteData(0xFF, 0xFF00, 0xFF0000)); + break; + case 16: + if (redMask == 0x7C00 && greenMask == 0x3E0 && blueMask == 0x1F) { + pixelFormat = OS.PixelFormat_Format16bppRgb555; + } else if (redMask == 0xF800 && greenMask == 0x7E0 && blueMask == 0x1F) { + pixelFormat = OS.PixelFormat_Format16bppRgb565; + } else { + pixelFormat = OS.PixelFormat_Format16bppRgb555; + newData = new ImageData(source.width, source.height, 16, new PaletteData(0x7C00, 0x3E0, 0x1F)); + } + break; + case 24: + if (redMask == 0xFF && greenMask == 0xFF00 && blueMask == 0xFF0000) { + pixelFormat = OS.PixelFormat_Format24bppRgb; + } else { + pixelFormat = OS.PixelFormat_Format24bppRgb; + newData = new ImageData(source.width, source.height, 24, new PaletteData(0xFF, 0xFF00, 0xFF0000)); + } + break; + case 32: + if (redMask == 0xFF00 && greenMask == 0xFF0000 && blueMask == 0xFF000000) { + pixelFormat = OS.PixelFormat_Format32bppRgb; + } else { + pixelFormat = OS.PixelFormat_Format32bppRgb; + newData = new ImageData(source.width, source.height, 32, new PaletteData(0xFF00, 0xFF0000, 0xFF000000)); + } + break; + } + } + if (newData != null) { + PaletteData newPalette = newData.palette; + if (palette.isDirect) { + ImageData.blit(ImageData.BLIT_SRC, + source.data, source.depth, source.bytesPerLine, source.getByteOrder(), 0, 0, width, height, redMask, greenMask, blueMask, + ImageData.ALPHA_OPAQUE, null, 0, 0, 0, + newData.data, newData.depth, newData.bytesPerLine, newData.getByteOrder(), 0, 0, width, height, newPalette.redMask, newPalette.greenMask, newPalette.blueMask, + false, false); + } else { + RGB[] rgbs = palette.getRGBs(); + int length = rgbs.length; + byte[] srcReds = new byte[length]; + byte[] srcGreens = new byte[length]; + byte[] srcBlues = new byte[length]; + for (int i = 0; i < rgbs.length; i++) { + RGB rgb = rgbs[i]; + if (rgb == null) continue; + srcReds[i] = (byte)rgb.red; + srcGreens[i] = (byte)rgb.green; + srcBlues[i] = (byte)rgb.blue; + } + ImageData.blit(ImageData.BLIT_SRC, + source.data, source.depth, source.bytesPerLine, source.getByteOrder(), 0, 0, width, height, srcReds, srcGreens, srcBlues, + ImageData.ALPHA_OPAQUE, null, 0, 0, 0, + newData.data, newData.depth, newData.bytesPerLine, newData.getByteOrder(), 0, 0, width, height, newPalette.redMask, newPalette.greenMask, newPalette.blueMask, + false, false); + } + if (source.transparentPixel != -1) { + newData.transparentPixel = newPalette.getPixel(palette.getRGB(source.transparentPixel)); + } + newData.maskPad = source.maskPad; + newData.maskData = source.maskData; + newData.alpha = source.alpha; + newData.alphaData = source.alphaData; + source = newData; + palette = source.palette; + } + if (transparent) { + if (source.maskData != null || source.transparentPixel != -1) { + ImageData maskImage = source.getTransparencyMask(); + byte[] maskData = maskImage.data; + int maskBpl = maskImage.bytesPerLine; + int offset = 3, maskOffset = 0; + for (int y = 0; y<height; y++) { + for (int x = 0; x<width; x++) { + source.data[offset] = ((maskData[maskOffset + (x >> 3)]) & (1 << (7 - (x & 0x7)))) != 0 ? (byte)0xff : 0; + offset += 4; + } + maskOffset += maskBpl; + } + } else if (source.alpha != -1) { + byte alpha = (byte)source.alpha; + for (int i = 3, j = 0; i < source.data.length; i+=4, j++) { + source.data[i] = alpha; + } + } else { + for (int i = 3, j = 0; i < source.data.length; i+=4, j++) { + source.data[i] = source.alphaData[j]; + } + } + } + int bitmap = OS.gcnew_Bitmap(source.width, source.height, source.bytesPerLine, pixelFormat, source.data); + if (bitmap == 0) SWT.error(SWT.ERROR_NO_HANDLES); + int hIcon = OS.Bitmap_GetHicon(bitmap); + if (hIcon == 0) SWT.error(SWT.ERROR_NO_HANDLES); + ICONINFO info = new ICONINFO(); + OS.GetIconInfo(hIcon, info); + info.fIcon = false; + info.xHotspot = hotspotX; + info.yHotspot = hotspotY; + OS.DestroyIcon(hIcon); + hIcon = OS.CreateIconIndirect(info); + if (info.hbmColor != 0) OS.DeleteObject(info.hbmColor); + if (info.hbmMask != 0)OS.DeleteObject(info.hbmMask); + if (hIcon == 0) SWT.error(SWT.ERROR_NO_HANDLES); + + /* Create the cursor */ + int safeHandle = OS.gcnew_SWTSafeHandle(hIcon, true); + if (safeHandle == 0) SWT.error(SWT.ERROR_NO_HANDLES); + handle = OS.CursorInteropHelper_Create(safeHandle); + if (handle == 0) SWT.error(SWT.ERROR_NO_HANDLES); + OS.GCHandle_Free(safeHandle); + OS.GCHandle_Free(bitmap); + if (device.tracking) device.new_Object(this); +} + +/** + * Disposes of the operating system resources associated with + * the cursor. Applications must dispose of all cursors which + * they allocate. + */ +public void dispose () { + if (handle == 0) return; + if (device.isDisposed()) return; + OS.GCHandle_Free(handle); + handle = 0; + if (device.tracking) device.dispose_Object(this); + device = null; +} + +/** + * 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 Cursor)) return false; + Cursor cursor = (Cursor) object; + return device == cursor.device && handle == cursor.handle; +} + +/** + * 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 + * + * @see #equals + */ +public int hashCode () { + return handle; +} + +/** + * Returns <code>true</code> if the cursor has been disposed, + * and <code>false</code> otherwise. + * <p> + * This method gets the dispose state for the cursor. + * When a cursor has been disposed, it is an error to + * invoke any other method using the cursor. + * + * @return <code>true</code> when the cursor is disposed and <code>false</code> otherwise + */ +public boolean isDisposed() { + return handle == 0; +} + +/** + * 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 "Cursor {*DISPOSED*}"; + return "Cursor {" + handle + "}"; +} + +/** + * Invokes platform specific functionality to allocate a new cursor. + * <p> + * <b>IMPORTANT:</b> This method is <em>not</em> part of the public + * API for <code>Cursor</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 device the device on which to allocate the color + * @param handle the handle for the cursor + * @return a new cursor object containing the specified device and handle + */ +public static Cursor wpf_new(Device device, int handle) { + if (device == null) device = Device.getDevice(); + Cursor cursor = new Cursor(); + cursor.handle = handle; + cursor.device = device; + return cursor; +} + +} diff --git a/bundles/org.eclipse.swt/Eclipse SWT/wpf/org/eclipse/swt/graphics/Device.java b/bundles/org.eclipse.swt/Eclipse SWT/wpf/org/eclipse/swt/graphics/Device.java new file mode 100644 index 0000000000..a1c637ad42 --- /dev/null +++ b/bundles/org.eclipse.swt/Eclipse SWT/wpf/org/eclipse/swt/graphics/Device.java @@ -0,0 +1,588 @@ +/******************************************************************************* + * Copyright (c) 2000, 2005 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.internal.wpf.*; +import org.eclipse.swt.*; + +/** + * This class is the abstract superclass of all device objects, + * such as the Display device and the Printer device. Devices + * can have a graphics context (GC) created for them, and they + * can be drawn on by sending messages to the associated GC. + */ +public abstract class Device implements Drawable { + + /* Debugging */ + public static boolean DEBUG; + boolean debug = DEBUG; + boolean tracking = DEBUG; + Error [] errors; + Object [] objects; + + Color[] colors; + + /* System Font */ + Font systemFont; + + boolean disposed; + + final static Object CREATE_LOCK = new Object(); + + /* + * TEMPORARY CODE. When a graphics object is + * created and the device parameter is null, + * the current Display is used. This presents + * a problem because SWT graphics does not + * reference classes in SWT widgets. The correct + * fix is to remove this feature. Unfortunately, + * too many application programs rely on this + * feature. + * + * This code will be removed in the future. + */ + protected static Device CurrentDevice; + protected static Runnable DeviceFinder; + static { + try { + Class.forName ("org.eclipse.swt.widgets.Display"); //$NON-NLS-1$ + } catch (Throwable e) {} + } + +/* +* TEMPORARY CODE. +*/ +static synchronized Device getDevice () { + if (DeviceFinder != null) DeviceFinder.run(); + Device device = CurrentDevice; + CurrentDevice = null; + return device; +} + +/** + * Constructs a new instance of this class. + * <p> + * You must dispose the device when it is no longer required. + * </p> + * + * @see #create + * @see #init + * + * @since 3.1 + */ +public Device() { + this(null); +} + +/** + * Constructs a new instance of this class. + * <p> + * You must dispose the device when it is no longer required. + * </p> + * + * @param data the DeviceData which describes the receiver + * + * @see #create + * @see #init + * @see DeviceData + */ +public Device(DeviceData data) { + synchronized (CREATE_LOCK) { + if (data != null) { + debug = data.debug; + tracking = data.tracking; + } + create (data); + init (); + if (tracking) { + errors = new Error [128]; + objects = new Object [128]; + } + + /* Initialize the system font slot */ + int fontFamily = OS.SystemFonts_MessageFontFamily(); + int style = OS.SystemFonts_MessageFontStyle(); + int weight = OS.SystemFonts_MessageFontWeight(); + double size = OS.SystemFonts_MessageFontSize(); + int typeface = OS.gcnew_Typeface(fontFamily, style, weight, OS.FontStretches_Normal); + OS.GCHandle_Free(fontFamily); + OS.GCHandle_Free(style); + OS.GCHandle_Free(weight); + systemFont = Font.wpf_new(this, typeface, size); + } +} + +/** + * Throws an <code>SWTException</code> if the receiver can not + * be accessed by the caller. This may include both checks on + * the state of the receiver and more generally on the entire + * execution context. This method <em>should</em> be called by + * device implementors to enforce the standard SWT invariants. + * <p> + * Currently, it is an error to invoke any method (other than + * <code>isDisposed()</code> and <code>dispose()</code>) on a + * device that has had its <code>dispose()</code> method called. + * </p><p> + * In future releases of SWT, there may be more or fewer error + * checks and exceptions may be thrown for different reasons. + * <p> + * + * @exception SWTException <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> + * </ul> + */ +protected void checkDevice () { + if (disposed) SWT.error(SWT.ERROR_DEVICE_DISPOSED); +} + +/** + * Creates the device in the operating system. If the device + * does not have a handle, this method may do nothing depending + * on the device. + * <p> + * This method is called before <code>init</code>. + * </p><p> + * Subclasses are supposed to reimplement this method and not + * call the <code>super</code> implementation. + * </p> + * + * @param data the DeviceData which describes the receiver + * + * @see #init + */ +protected void create (DeviceData data) { +} + +/** + * Destroys the device in the operating system and releases + * the device's handle. If the device does not have a handle, + * this method may do nothing depending on the device. + * <p> + * This method is called after <code>release</code>. + * </p><p> + * Subclasses are supposed to reimplement this method and not + * call the <code>super</code> implementation. + * </p> + * + * @see #dispose + * @see #release + */ +protected void destroy () { +} + +/** + * Disposes of the operating system resources associated with + * the receiver. After this method has been invoked, the receiver + * will answer <code>true</code> when sent the message + * <code>isDisposed()</code>. + * + * @see #release + * @see #destroy + * @see #checkDevice + */ +public void dispose () { + if (isDisposed()) return; + checkDevice (); + release (); + destroy (); + disposed = true; + if (tracking) { + objects = null; + errors = null; + } +} + +void dispose_Object (Object object) { + for (int i=0; i<objects.length; i++) { + if (objects [i] == object) { + objects [i] = null; + errors [i] = null; + return; + } + } +} + +/** + * Returns a rectangle describing the receiver's size and location. + * + * @return the bounding rectangle + * + * @exception SWTException <ul> + * <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li> + * </ul> + */ +public Rectangle getBounds () { + checkDevice (); + int width = (int) OS.SystemParameters_PrimaryScreenWidth(); + int height = (int) OS.SystemParameters_PrimaryScreenHeight(); + return new Rectangle (0, 0, width, height); +} + +/** + * Returns a <code>DeviceData</code> based on the receiver. + * Modifications made to this <code>DeviceData</code> will not + * affect the receiver. + * + * @return a <code>DeviceData</code> containing the device's data and attributes + * + * @exception SWTException <ul> + * <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li> + * </ul> + * + * @see DeviceData + */ +public DeviceData getDeviceData () { + checkDevice(); + DeviceData data = new DeviceData (); + data.debug = debug; + data.tracking = tracking; + int count = 0, length = 0; + if (tracking) length = objects.length; + for (int i=0; i<length; i++) { + if (objects [i] != null) count++; + } + int index = 0; + data.objects = new Object [count]; + data.errors = new Error [count]; + for (int i=0; i<length; i++) { + if (objects [i] != null) { + data.objects [index] = objects [i]; + data.errors [index] = errors [i]; + index++; + } + } + return data; +} + +/** + * Returns a rectangle which describes the area of the + * receiver which is capable of displaying data. + * + * @return the client area + * + * @exception SWTException <ul> + * <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li> + * </ul> + * + * @see #getBounds + */ +public Rectangle getClientArea () { + return getBounds (); +} + +/** + * Returns the bit depth of the screen, which is the number of + * bits it takes to represent the number of unique colors that + * the screen is currently capable of displaying. This number + * will typically be one of 1, 8, 15, 16, 24 or 32. + * + * @return the depth of the screen + * + * @exception SWTException <ul> + * <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li> + * </ul> + */ +public int getDepth () { + checkDevice (); + //TODO - implement getDepth + return 32; +} + +/** + * Returns a point whose x coordinate is the horizontal + * dots per inch of the display, and whose y coordinate + * is the vertical dots per inch of the display. + * + * @return the horizontal and vertical DPI + * + * @exception SWTException <ul> + * <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li> + * </ul> + */ +public Point getDPI () { + checkDevice (); + //TODO implement getDPI + return new Point(96, 96); +} + +/** + * Returns <code>FontData</code> objects which describe + * the fonts that match the given arguments. If the + * <code>faceName</code> is null, all fonts will be returned. + * + * @param faceName the name of the font to look for, or null + * @param scalable if true only scalable fonts are returned, otherwise only non-scalable fonts are returned. + * @return the matching font data + * + * @exception SWTException <ul> + * <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li> + * </ul> + */ +public FontData [] getFontList (String faceName, boolean scalable) { + checkDevice (); + if (!scalable) return new FontData[0]; + int typefaces; + if (faceName != null) { + int length = faceName.length(); + char[] chars = new char[length + 1]; + faceName.getChars(0, length, chars, 0); + int str = OS.gcnew_String(chars); + int fontFamily = OS.gcnew_FontFamily(str); + typefaces = OS.FontFamily_GetTypefaces(fontFamily); + OS.GCHandle_Free(fontFamily); + OS.GCHandle_Free(str); + } else { + typefaces = OS.Fonts_SystemTypefaces(); + } + int count = OS.TypefaceCollection_Count(typefaces); + int index = 0; + FontData[] result = new FontData[count]; + int enumerator = OS.TypefaceCollection_GetEnumerator(typefaces); + while (OS.IEnumerator_MoveNext(enumerator)) { + int typeface = OS.TypefaceCollection_Current(enumerator); + int fontFamily = OS.Typeface_FontFamily(typeface); + int style = OS.Typeface_Style(typeface); + int weight = OS.Typeface_Weight(typeface); + int stretch = OS.Typeface_Stretch(typeface); + int str = OS.FontFamily_Source(fontFamily); + int charArray = OS.String_ToCharArray(str); + char[] chars = new char[OS.String_Length(str)]; + OS.memmove(chars, charArray, chars.length * 2); + int fontStyle = OS.FontStyles_Normal; + if (OS.Object_Equals(style, OS.FontStyles_Italic)) fontStyle = OS.FontStyles_Italic; + if (OS.Object_Equals(style, OS.FontStyles_Oblique)) fontStyle = OS.FontStyles_Oblique; + FontData data = FontData.wpf_new(new String(chars), fontStyle, + OS.FontWeight_ToOpenTypeWeight(weight), OS.FontStretch_ToOpenTypeStretch(stretch), 0); + OS.GCHandle_Free(charArray); + OS.GCHandle_Free(str); + OS.GCHandle_Free(fontFamily); + OS.GCHandle_Free(style); + OS.GCHandle_Free(weight); + OS.GCHandle_Free(stretch); + OS.GCHandle_Free(typeface); + result[index++] = data; + } + OS.GCHandle_Free(enumerator); + OS.GCHandle_Free(typefaces); + return result; +} + +/** + * Returns the matching standard color for the given + * constant, which should be one of the color constants + * specified in class <code>SWT</code>. Any value other + * than one of the SWT color constants which is passed + * in will result in the color black. This color should + * not be freed because it was allocated by the system, + * not the application. + * + * @param id the color constant + * @return the matching color + * + * @exception SWTException <ul> + * <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li> + * </ul> + * + * @see SWT + */ +public Color getSystemColor (int id) { + checkDevice (); + if (0 <= id && id < colors.length) { + return colors[id]; + } + return colors[0]; +} + +/** + * Returns a reasonable font for applications to use. + * On some platforms, this will match the "default font" + * or "system font" if such can be found. This font + * should not be freed because it was allocated by the + * system, not the application. + * <p> + * Typically, applications which want the default look + * should simply not set the font on the widgets they + * create. Widgets are always created with the correct + * default font for the class of user-interface component + * they represent. + * </p> + * + * @return a font + * + * @exception SWTException <ul> + * <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li> + * </ul> + */ +public Font getSystemFont () { + checkDevice (); + return systemFont; +} + +/** + * Returns <code>true</code> if the underlying window system prints out + * warning messages on the console, and <code>setWarnings</code> + * had previously been called with <code>true</code>. + * + * @return <code>true</code>if warnings are being handled, and <code>false</code> otherwise + * + * @exception SWTException <ul> + * <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li> + * </ul> + */ +public boolean getWarnings () { + checkDevice (); + return false; +} + +/** + * Initializes any internal resources needed by the + * device. + * <p> + * This method is called after <code>create</code>. + * </p><p> + * If subclasses reimplement this method, they must + * call the <code>super</code> implementation. + * </p> + * + * @see #create + */ +protected void init () { + /* Create the standard colors */ + colors = new Color[SWT.COLOR_DARK_GRAY + 1]; + colors[SWT.COLOR_BLACK] = colors[0] = Color.wpf_new(this, OS.Colors_Black()); + colors[SWT.COLOR_DARK_RED] = Color.wpf_new(this, OS.Colors_Maroon ()); + colors[SWT.COLOR_DARK_GREEN] = Color.wpf_new(this, OS.Colors_Green ()); + colors[SWT.COLOR_DARK_YELLOW] = Color.wpf_new(this, OS.Colors_Olive()); + colors[SWT.COLOR_DARK_BLUE] = Color.wpf_new(this, OS.Colors_Navy ()); + colors[SWT.COLOR_DARK_MAGENTA] = Color.wpf_new(this, OS.Colors_Purple()); + colors[SWT.COLOR_DARK_CYAN] = Color.wpf_new(this, OS.Colors_Teal ()); + colors[SWT.COLOR_GRAY] = Color.wpf_new(this, OS.Colors_Silver ()); + colors[SWT.COLOR_DARK_GRAY] = Color.wpf_new(this, OS.Colors_Silver ()); + colors[SWT.COLOR_RED] = Color.wpf_new(this, OS.Colors_Red ()); + colors[SWT.COLOR_GREEN] = Color.wpf_new(this, OS.Colors_Lime ()); + colors[SWT.COLOR_YELLOW] = Color.wpf_new(this, OS.Colors_Yellow ()); + colors[SWT.COLOR_BLUE] = Color.wpf_new(this, OS.Colors_Blue ()); + colors[SWT.COLOR_MAGENTA] = Color.wpf_new(this, OS.Colors_Magenta ()); + colors[SWT.COLOR_CYAN] = Color.wpf_new(this, OS.Colors_Cyan ()); + colors[SWT.COLOR_WHITE] = Color.wpf_new(this, OS.Colors_White ()); +} + +/** + * Invokes platform specific functionality to allocate a new GC handle. + * <p> + * <b>IMPORTANT:</b> This method is <em>not</em> part of the public + * API for <code>Device</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 data the platform specific GC data + * @return the platform specific GC handle + */ +public abstract int internal_new_GC (GCData data); + +/** + * Invokes platform specific functionality to dispose a GC handle. + * <p> + * <b>IMPORTANT:</b> This method is <em>not</em> part of the public + * API for <code>Device</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 hDC the platform specific GC handle + * @param data the platform specific GC data + */ +public abstract void internal_dispose_GC (int hDC, GCData data); + +/** + * Returns <code>true</code> if the device has been disposed, + * and <code>false</code> otherwise. + * <p> + * This method gets the dispose state for the device. + * When a device has been disposed, it is an error to + * invoke any other method using the device. + * + * @return <code>true</code> when the device is disposed and <code>false</code> otherwise + */ +public boolean isDisposed () { + return disposed; +} + +void new_Object (Object object) { + for (int i=0; i<objects.length; i++) { + if (objects [i] == null) { + objects [i] = object; + errors [i] = new Error (); + return; + } + } + Object [] newObjects = new Object [objects.length + 128]; + System.arraycopy (objects, 0, newObjects, 0, objects.length); + newObjects [objects.length] = object; + objects = newObjects; + Error [] newErrors = new Error [errors.length + 128]; + System.arraycopy (errors, 0, newErrors, 0, errors.length); + newErrors [errors.length] = new Error (); + errors = newErrors; +} + +/** + * Releases any internal resources back to the operating + * system and clears all fields except the device handle. + * <p> + * When a device is destroyed, resources that were acquired + * on behalf of the programmer need to be returned to the + * operating system. For example, if the device allocated a + * font to be used as the system font, this font would be + * freed in <code>release</code>. Also,to assist the garbage + * collector and minimize the amount of memory that is not + * reclaimed when the programmer keeps a reference to a + * disposed device, all fields except the handle are zero'd. + * The handle is needed by <code>destroy</code>. + * </p> + * This method is called before <code>destroy</code>. + * </p><p> + * If subclasses reimplement this method, they must + * call the <code>super</code> implementation. + * </p> + * + * @see #dispose + * @see #destroy + */ +protected void release () { + for (int i = 0; i < colors.length; i++) { + if (colors[i] != null) colors[i].dispose(); + } + colors = null; + if (systemFont != null) systemFont.dispose(); + systemFont = null; +} + +/** + * If the underlying window system supports printing warning messages + * to the console, setting warnings to <code>false</code> prevents these + * messages from being printed. If the argument is <code>true</code> then + * message printing is not blocked. + * + * @param warnings <code>true</code>if warnings should be printed, and <code>false</code> otherwise + * + * @exception SWTException <ul> + * <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li> + * </ul> + */ +public void setWarnings (boolean warnings) { + checkDevice (); +} + +} diff --git a/bundles/org.eclipse.swt/Eclipse SWT/wpf/org/eclipse/swt/graphics/DeviceData.java b/bundles/org.eclipse.swt/Eclipse SWT/wpf/org/eclipse/swt/graphics/DeviceData.java new file mode 100644 index 0000000000..593b25584d --- /dev/null +++ b/bundles/org.eclipse.swt/Eclipse SWT/wpf/org/eclipse/swt/graphics/DeviceData.java @@ -0,0 +1,23 @@ +/******************************************************************************* + * Copyright (c) 2000, 2003 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; + + +public class DeviceData { + /* + * Debug fields - may not be honoured + * on some SWT platforms. + */ + public boolean debug; + public boolean tracking; + public Error [] errors; + public Object [] objects; +} diff --git a/bundles/org.eclipse.swt/Eclipse SWT/wpf/org/eclipse/swt/graphics/Font.java b/bundles/org.eclipse.swt/Eclipse SWT/wpf/org/eclipse/swt/graphics/Font.java new file mode 100644 index 0000000000..336c1c4914 --- /dev/null +++ b/bundles/org.eclipse.swt/Eclipse SWT/wpf/org/eclipse/swt/graphics/Font.java @@ -0,0 +1,302 @@ +/******************************************************************************* + * Copyright (c) 2000, 2005 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.internal.wpf.*; +import org.eclipse.swt.*; + +/** + * Instances of this class manage operating system resources that + * define how text looks when it is displayed. Fonts may be constructed + * by providing a device and either name, size and style information + * or a <code>FontData</code> object which encapsulates this data. + * <p> + * Application code must explicitly invoke the <code>Font.dispose()</code> + * method to release the operating system resources managed by each instance + * when those instances are no longer required. + * </p> + * + * @see FontData + */ + +public final class Font extends Resource { + + /** + * the handle to the OS font resource + * (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> + */ + public int handle; + + /** + * the handle to the OS font resource + * (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> + */ + public double size; + +/** + * Prevents uninitialized instances from being created outside the package. + */ +Font() { +} + +/** + * Constructs a new font given a device and font data + * which describes the desired font's appearance. + * <p> + * You must dispose the font when it is no longer required. + * </p> + * + * @param device the device to create the font on + * @param fd the FontData that describes the desired font (must not be null) + * + * @exception IllegalArgumentException <ul> + * <li>ERROR_NULL_ARGUMENT - if device is null and there is no current device</li> + * <li>ERROR_NULL_ARGUMENT - if the fd argument is null</li> + * </ul> + * @exception SWTError <ul> + * <li>ERROR_NO_HANDLES - if a font could not be created from the given font data</li> + * </ul> + */ +public Font(Device device, FontData fd) { + if (device == null) device = Device.getDevice(); + if (device == null) SWT.error(SWT.ERROR_NULL_ARGUMENT); + init(device, fd); + if (device.tracking) device.new_Object(this); +} + +/** + * Constructs a new font given a device and an array + * of font data which describes the desired font's + * appearance. + * <p> + * You must dispose the font when it is no longer required. + * </p> + * + * @param device the device to create the font on + * @param fds the array of FontData that describes the desired font (must not be null) + * + * @exception IllegalArgumentException <ul> + * <li>ERROR_NULL_ARGUMENT - if device is null and there is no current device</li> + * <li>ERROR_NULL_ARGUMENT - if the fds argument is null</li> + * <li>ERROR_INVALID_ARGUMENT - if the length of fds is zero</li> + * <li>ERROR_NULL_ARGUMENT - if any fd in the array is null</li> + * </ul> + * @exception SWTError <ul> + * <li>ERROR_NO_HANDLES - if a font could not be created from the given font data</li> + * </ul> + * + * @since 2.1 + */ +public Font(Device device, FontData[] fds) { + if (device == null) device = Device.getDevice(); + if (device == null) SWT.error(SWT.ERROR_NULL_ARGUMENT); + if (fds == null) SWT.error(SWT.ERROR_NULL_ARGUMENT); + if (fds.length == 0) SWT.error(SWT.ERROR_INVALID_ARGUMENT); + for (int i=0; i<fds.length; i++) { + if (fds[i] == null) SWT.error(SWT.ERROR_INVALID_ARGUMENT); + } + init(device, fds[0]); + if (device.tracking) device.new_Object(this); +} + +/** + * Constructs a new font given a device, a font name, + * the height of the desired font in points, and a font + * style. + * <p> + * You must dispose the font when it is no longer required. + * </p> + * + * @param device the device to create the font on + * @param name the name of the font (must not be null) + * @param height the font height in points + * @param style a bit or combination of NORMAL, BOLD, ITALIC + * + * @exception IllegalArgumentException <ul> + * <li>ERROR_NULL_ARGUMENT - if device is null and there is no current device</li> + * <li>ERROR_NULL_ARGUMENT - if the name argument is null</li> + * <li>ERROR_INVALID_ARGUMENT - if the height is negative</li> + * </ul> + * @exception SWTError <ul> + * <li>ERROR_NO_HANDLES - if a font could not be created from the given arguments</li> + * </ul> + */ +public Font(Device device, String name, int height, int style) { + if (device == null) device = Device.getDevice(); + if (device == null) SWT.error(SWT.ERROR_NULL_ARGUMENT); + if (name == null) SWT.error(SWT.ERROR_NULL_ARGUMENT); + init(device, new FontData (name, height, style)); + if (device.tracking) device.new_Object(this); +} + +/** + * Disposes of the operating system resources associated with + * the font. Applications must dispose of all fonts which + * they allocate. + */ +public void dispose() { + if (handle == 0) return; + if (device.isDisposed()) return; + OS.GCHandle_Free(handle); + handle = 0; + if (device.tracking) device.dispose_Object(this); + device = null; +} + +/** + * 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 Font)) return false; + Font font = (Font) object; + return device == font.device && handle == font.handle && size == font.size; +} + +/** + * Returns an array of <code>FontData</code>s representing the receiver. + * On Windows, only one FontData will be returned per font. On X however, + * a <code>Font</code> object <em>may</em> be composed of multiple X + * fonts. To support this case, we return an array of font data objects. + * + * @return an array of font data objects describing the receiver + * + * @exception SWTException <ul> + * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> + * </ul> + */ +public FontData[] getFontData() { + if (isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); + int fontFamily = OS.Typeface_FontFamily(handle); + int style = OS.Typeface_Style(handle); + int weight = OS.Typeface_Weight(handle); + int stretch = OS.Typeface_Stretch(handle); + int str = OS.FontFamily_Source(fontFamily); + int charArray = OS.String_ToCharArray(str); + char[] chars = new char[OS.String_Length(str)]; + OS.memmove(chars, charArray, chars.length * 2); + int fontStyle = OS.FontStyles_Normal; + if (OS.Object_Equals(style, OS.FontStyles_Italic)) fontStyle = OS.FontStyles_Italic; + if (OS.Object_Equals(style, OS.FontStyles_Oblique)) fontStyle = OS.FontStyles_Oblique; + int size = (int) (this.size * 72 / 96f); + FontData data = FontData.wpf_new(new String(chars), fontStyle, OS.FontWeight_ToOpenTypeWeight(weight), OS.FontStretch_ToOpenTypeStretch(stretch), (int)size); + OS.GCHandle_Free(charArray); + OS.GCHandle_Free(str); + OS.GCHandle_Free(fontFamily); + OS.GCHandle_Free(style); + OS.GCHandle_Free(weight); + OS.GCHandle_Free(stretch); + return new FontData[] {data}; +} + +/** + * 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 + * + * @see #equals + */ +public int hashCode () { + return handle; +} + +void init (Device device, FontData fd) { + if (fd == null) SWT.error(SWT.ERROR_NULL_ARGUMENT); + this.device = device; + int length = fd.fontFamily.length(); + char[] chars = new char[length + 1]; + fd.fontFamily.getChars(0, length, chars, 0); + int str = OS.gcnew_String(chars); + int fontFamily = OS.gcnew_FontFamily(str); + int style = fd.style; + int weight = OS.FontWeight_FromOpenTypeWeight(fd.weight); + int stretch = OS.FontStretch_FromOpenTypeStretch(fd.stretch); + handle = OS.gcnew_Typeface(fontFamily, style, weight, stretch); + OS.GCHandle_Free(fontFamily); + OS.GCHandle_Free(str); + OS.GCHandle_Free(weight); + OS.GCHandle_Free(stretch); + size = fd.height * 96 / 72f; + if (handle == 0) SWT.error(SWT.ERROR_NO_HANDLES); +} + +/** + * Returns <code>true</code> if the font has been disposed, + * and <code>false</code> otherwise. + * <p> + * This method gets the dispose state for the font. + * When a font has been disposed, it is an error to + * invoke any other method using the font. + * + * @return <code>true</code> when the font is disposed and <code>false</code> otherwise + */ +public boolean isDisposed() { + return handle == 0; +} + +/** + * 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 "Font {*DISPOSED*}"; + return "Font {" + handle + "}"; +} + +/** + * Invokes platform specific functionality to allocate a new font. + * <p> + * <b>IMPORTANT:</b> This method is <em>not</em> part of the public + * API for <code>Font</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 device the device on which to allocate the color + * @param handle the handle for the font + * @return a new font object containing the specified device and handle + */ +public static Font wpf_new(Device device, int handle, double size) { + if (device == null) device = Device.getDevice(); + Font font = new Font(); + font.handle = handle; + font.size = size; + font.device = device; + return font; +} + +} diff --git a/bundles/org.eclipse.swt/Eclipse SWT/wpf/org/eclipse/swt/graphics/FontData.java b/bundles/org.eclipse.swt/Eclipse SWT/wpf/org/eclipse/swt/graphics/FontData.java new file mode 100644 index 0000000000..fa35329588 --- /dev/null +++ b/bundles/org.eclipse.swt/Eclipse SWT/wpf/org/eclipse/swt/graphics/FontData.java @@ -0,0 +1,508 @@ +/******************************************************************************* + * Copyright (c) 2000, 2005 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.internal.wpf.*; +import org.eclipse.swt.*; + +/** + * Instances of this class describe operating system fonts. + * <p> + * For platform-independent behaviour, use the get and set methods + * corresponding to the following properties: + * <dl> + * <dt>height</dt><dd>the height of the font in points</dd> + * <dt>name</dt><dd>the face name of the font, which may include the foundry</dd> + * <dt>style</dt><dd>A bitwise combination of NORMAL, ITALIC and BOLD</dd> + * </dl> + * If extra, platform-dependent functionality is required: + * <ul> + * <li>On <em>Windows</em>, the data member of the <code>FontData</code> + * corresponds to a Windows <code>LOGFONT</code> structure whose fields + * may be retrieved and modified.</li> + * <li>On <em>X</em>, the fields of the <code>FontData</code> correspond + * to the entries in the font's XLFD name and may be retrieved and modified. + * </ul> + * Application code does <em>not</em> need to explicitly release the + * resources managed by each instance when those instances are no longer + * required, and thus no <code>dispose()</code> method is provided. + * + * @see Font + */ + +public final class FontData { + + /** + * A WPF font + * (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> + */ + public String fontFamily; + + public int style; + + public int weight; + + public int stretch; + + /** + * The height of the font data in points + * (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> + */ + public int height; + + /** + * The locales of the font + */ + String lang, country, variant; + +/** + * Constructs a new un-initialized font data. + */ +public FontData() { + fontFamily = ""; + style = OS.FontStyles_Normal; + weight = OS.FontWeight_ToOpenTypeWeight(OS.FontWeights_Normal); + stretch = OS.FontStretch_ToOpenTypeStretch(OS.FontStretches_Normal); + height = 12; +} + +/** + * Constructs a new FontData given a string representation + * in the form generated by the <code>FontData.toString</code> + * method. + * <p> + * Note that the representation varies between platforms, + * and a FontData can only be created from a string that was + * generated on the same platform. + * </p> + * + * @param string the string representation of a <code>FontData</code> (must not be null) + * + * @exception IllegalArgumentException <ul> + * <li>ERROR_NULL_ARGUMENT - if the argument is null</li> + * <li>ERROR_INVALID_ARGUMENT - if the argument does not represent a valid description</li> + * </ul> + * + * @see #toString + */ +public FontData(String string) { + if (string == null) SWT.error(SWT.ERROR_NULL_ARGUMENT); + int start = 0; + int end = string.indexOf('|'); + if (end == -1) SWT.error(SWT.ERROR_INVALID_ARGUMENT); + String version1 = string.substring(start, end); + try { + if (Integer.parseInt(version1) != 1) SWT.error(SWT.ERROR_INVALID_ARGUMENT); + } catch (NumberFormatException e) { + SWT.error(SWT.ERROR_INVALID_ARGUMENT); + } + + start = end + 1; + end = string.indexOf('|', start); + if (end == -1) SWT.error(SWT.ERROR_INVALID_ARGUMENT); + String name = string.substring(start, end); + + start = end + 1; + end = string.indexOf('|', start); + if (end == -1) SWT.error(SWT.ERROR_INVALID_ARGUMENT); + int height = 0; + try { + height = Integer.parseInt(string.substring(start, end)); + } catch (NumberFormatException e) { + SWT.error(SWT.ERROR_INVALID_ARGUMENT); + } + + start = end + 1; + end = string.indexOf('|', start); + if (end == -1) SWT.error(SWT.ERROR_INVALID_ARGUMENT); + int style = 0; + try { + style = Integer.parseInt(string.substring(start, end)); + } catch (NumberFormatException e) { + SWT.error(SWT.ERROR_INVALID_ARGUMENT); + } + + start = end + 1; + end = string.indexOf('|', start); + setName(name); + setHeight(height); + setStyle(style); + if (end == -1) return; + String platform = string.substring(start, end); + + start = end + 1; + end = string.indexOf('|', start); + if (end == -1) return; + String version2 = string.substring(start, end); + + if (platform.equals("WPF") && version2.equals("1")) { + try { + start = end + 1; + end = string.indexOf('|', start); + if (end == -1) return; + fontFamily = string.substring(start, end); + start = end + 1; + end = string.indexOf('|', start); + if (end == -1) return; + String styleStr = string.substring(start, end); + int length = styleStr.length(); + char[] chars = new char[length + 1]; + styleStr.getChars(0, length, chars, 0); + int str = OS.gcnew_String(chars); + int converter = OS.TypeDescriptor_GetConverter(OS.FontStyles_Normal); + this.style = OS.FontStyles_Normal; + int fontStyle = OS.TypeConverter_ConvertFromString(converter, str); + if (fontStyle != 0) { + if (OS.Object_Equals(OS.FontStyles_Italic, fontStyle)) this.style = OS.FontStyles_Italic; + if (OS.Object_Equals(OS.FontStyles_Oblique, fontStyle)) this.style = OS.FontStyles_Oblique; + OS.GCHandle_Free(fontStyle); + } + OS.GCHandle_Free(converter); + OS.GCHandle_Free(str); + start = end + 1; + end = string.indexOf('|', start); + if (end == -1) return; + weight = Integer.parseInt(string.substring(start, end)); + start = end + 1; + end = string.indexOf('|', start); + if (end == -1) end = string.length(); + stretch = Integer.parseInt(string.substring(start, end)); + } catch (NumberFormatException e) { + setName(name); + setHeight(height); + setStyle(style); + return; + } + } +} + +/** + * Constructs a new font data given a font name, + * the height of the desired font in points, + * and a font style. + * + * @param name the name of the font (must not be null) + * @param height the font height in points + * @param style a bit or combination of NORMAL, BOLD, ITALIC + * + * @exception IllegalArgumentException <ul> + * <li>ERROR_NULL_ARGUMENT - when the font name is null</li> + * <li>ERROR_INVALID_ARGUMENT - if the height is negative</li> + * </ul> + */ +public FontData(String name, int height, int style) { + if (name == null) SWT.error(SWT.ERROR_NULL_ARGUMENT); + setName(name); + setHeight(height); + setStyle(style); + stretch = OS.FontStretch_ToOpenTypeStretch(OS.FontStretches_Normal); +} + +/** + * 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 FontData)) return false; + FontData fd = (FontData)object; + return style == fd.style && + height == fd.height && + weight == fd.weight && + stretch == fd.stretch && + getName().equals(fd.getName()); +} + +/** + * Returns the height of the receiver in points. + * + * @return the height of this FontData + * + * @see #setHeight + */ +public int getHeight() { + return height; +} + +/** + * Returns the locale of the receiver. + * <p> + * The locale determines which platform character set this + * font is going to use. Widgets and graphics operations that + * use this font will convert UNICODE strings to the platform + * character set of the specified locale. + * </p> + * <p> + * On platforms where there are multiple character sets for a + * given language/country locale, the variant portion of the + * locale will determine the character set. + * </p> + * + * @return the <code>String</code> representing a Locale object + * @since 3.0 + */ +public String getLocale () { + StringBuffer buffer = new StringBuffer (); + char sep = '_'; + if (lang != null) { + buffer.append (lang); + buffer.append (sep); + } + if (country != null) { + buffer.append (country); + buffer.append (sep); + } + if (variant != null) { + buffer.append (variant); + } + + String result = buffer.toString (); + int length = result.length (); + if (length > 0) { + if (result.charAt (length - 1) == sep) { + result = result.substring (0, length - 1); + } + } + return result; +} + +/** + * Returns the name of the receiver. + * On platforms that support font foundries, the return value will + * be the foundry followed by a dash ("-") followed by the face name. + * + * @return the name of this <code>FontData</code> + * + * @see #setName + */ +public String getName() { + return fontFamily; +} + +/** + * Returns the style of the receiver which is a bitwise OR of + * one or more of the <code>SWT</code> constants NORMAL, BOLD + * and ITALIC. + * + * @return the style of this <code>FontData</code> + * + * @see #setStyle + */ +public int getStyle() { + int style = SWT.NORMAL; + if (weight == OS.FontWeight_ToOpenTypeWeight(OS.FontWeights_Bold)) style |= SWT.BOLD; + if (style == OS.FontStyles_Italic) style |= SWT.ITALIC; + return style; +} + +/** + * 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 + * + * @see #equals + */ +public int hashCode () { + return style ^ weight ^ stretch ^ getName().hashCode(); +} + +/** + * Sets the height of the receiver. The parameter is + * specified in terms of points, where a point is one + * seventy-second of an inch. + * + * @param height the height of the <code>FontData</code> + * + * @exception IllegalArgumentException <ul> + * <li>ERROR_INVALID_ARGUMENT - if the height is negative</li> + * </ul> + * + * @see #getHeight + */ +public void setHeight(int height) { + if (height < 0) SWT.error(SWT.ERROR_INVALID_ARGUMENT); + this.height = height; +} + +/** + * Sets the locale of the receiver. + * <p> + * The locale determines which platform character set this + * font is going to use. Widgets and graphics operations that + * use this font will convert UNICODE strings to the platform + * character set of the specified locale. + * </p> + * <p> + * On platforms where there are multiple character sets for a + * given language/country locale, the variant portion of the + * locale will determine the character set. + * </p> + * + * @param locale the <code>String</code> representing a Locale object + * @see java.util.Locale#toString + */ +public void setLocale(String locale) { + lang = country = variant = null; + if (locale != null) { + char sep = '_'; + int length = locale.length(); + int firstSep, secondSep; + + firstSep = locale.indexOf(sep); + if (firstSep == -1) { + firstSep = secondSep = length; + } else { + secondSep = locale.indexOf(sep, firstSep + 1); + if (secondSep == -1) secondSep = length; + } + if (firstSep > 0) lang = locale.substring(0, firstSep); + if (secondSep > firstSep + 1) country = locale.substring(firstSep + 1, secondSep); + if (length > secondSep + 1) variant = locale.substring(secondSep + 1); + } +} + +/** + * Sets the name of the receiver. + * <p> + * Some platforms support font foundries. On these platforms, the name + * of the font specified in setName() may have one of the following forms: + * <ol> + * <li>a face name (for example, "courier")</li> + * <li>a foundry followed by a dash ("-") followed by a face name (for example, "adobe-courier")</li> + * </ol> + * In either case, the name returned from getName() will include the + * foundry. + * </p> + * <p> + * On platforms that do not support font foundries, only the face name + * (for example, "courier") is used in <code>setName()</code> and + * <code>getName()</code>. + * </p> + * + * @param name the name of the font data (must not be null) + * @exception IllegalArgumentException <ul> + * <li>ERROR_NULL_ARGUMENT - when the font name is null</li> + * </ul> + * + * @see #getName + */ +public void setName(String name) { + if (name == null) SWT.error(SWT.ERROR_NULL_ARGUMENT); + fontFamily = name; +} + +/** + * Sets the style of the receiver to the argument which must + * be a bitwise OR of one or more of the <code>SWT</code> + * constants NORMAL, BOLD and ITALIC. All other style bits are + * ignored. + * + * @param style the new style for this <code>FontData</code> + * + * @see #getStyle + */ +public void setStyle(int style) { + if ((style & SWT.BOLD) == SWT.BOLD) { + weight = OS.FontWeight_ToOpenTypeWeight(OS.FontWeights_Bold); + } else { + weight = OS.FontWeight_ToOpenTypeWeight(OS.FontWeights_Normal); + } + if ((style & SWT.ITALIC) == SWT.ITALIC) { + this.style = OS.FontStyles_Italic; + } else { + this.style = OS.FontStyles_Normal; + } +} + +/** + * Returns a string representation of the receiver which is suitable + * for constructing an equivalent instance using the + * <code>FontData(String)</code> constructor. + * + * @return a string representation of the FontData + * + * @see FontData + */ +public String toString() { + StringBuffer buffer = new StringBuffer(); + buffer.append("1|"); //$NON-NLS-1$ + buffer.append(getName()); + buffer.append("|"); //$NON-NLS-1$ + buffer.append(getHeight()); + buffer.append("|"); //$NON-NLS-1$ + buffer.append(getStyle()); + buffer.append("|"); //$NON-NLS-1$ + buffer.append("WPF|1|"); //$NON-NLS-1$ + buffer.append(fontFamily); + buffer.append("|"); //$NON-NLS-1$ + int converter = OS.TypeDescriptor_GetConverter(OS.FontStyles_Normal); + int str = OS.TypeConverter_ConvertToString(converter, style != 0 ? style : OS.FontStyles_Normal); + int charArray = OS.String_ToCharArray(str); + char[] chars = new char[OS.String_Length(str)]; + OS.memmove(chars, charArray, chars.length * 2); + OS.GCHandle_Free (charArray); + OS.GCHandle_Free (str); + OS.GCHandle_Free (converter); + buffer.append(chars); + buffer.append("|"); //$NON-NLS-1$ + buffer.append(weight); + buffer.append("|"); //$NON-NLS-1$ + buffer.append(stretch); + return buffer.toString(); +} + +/** + * Invokes platform specific functionality to allocate a new font data. + * <p> + * <b>IMPORTANT:</b> This method is <em>not</em> part of the public + * API for <code>FontData</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 data the <code>LOGFONT</code> for the font data + * @param height the height of the font data + * @return a new font data object containing the specified <code>LOGFONT</code> and height + */ +public static FontData wpf_new(String fontFamily, int style, int weight, int stretch, int height) { + FontData data = new FontData(); + data.fontFamily = fontFamily; + data.style = style; + data.weight = weight; + data.stretch = stretch; + data.height = height; + return data; +} + +} diff --git a/bundles/org.eclipse.swt/Eclipse SWT/wpf/org/eclipse/swt/graphics/FontMetrics.java b/bundles/org.eclipse.swt/Eclipse SWT/wpf/org/eclipse/swt/graphics/FontMetrics.java new file mode 100644 index 0000000000..51d98b7e6c --- /dev/null +++ b/bundles/org.eclipse.swt/Eclipse SWT/wpf/org/eclipse/swt/graphics/FontMetrics.java @@ -0,0 +1,132 @@ +/******************************************************************************* + * Copyright (c) 2000, 2005 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; + + +/** + * Instances of this class provide measurement information + * about fonts including ascent, descent, height, leading + * space between rows, and average character width. + * <code>FontMetrics</code> are obtained from <code>GC</code>s + * using the <code>getFontMetrics()</code> method. + * + * @see GC#getFontMetrics + */ +public final class FontMetrics { + int ascent, descent, averageCharWidth, leading, height; + +FontMetrics() { +} + +/** + * 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 FontMetrics)) return false; + FontMetrics metrics = (FontMetrics)object; + return ascent == metrics.ascent && descent == metrics.descent && + averageCharWidth == metrics.averageCharWidth && leading == metrics.leading && + height == metrics.height; +} + +/** + * Returns the ascent of the font described by the receiver. A + * font's <em>ascent</em> is the distance from the baseline to the + * top of actual characters, not including any of the leading area, + * measured in pixels. + * + * @return the ascent of the font + */ +public int getAscent() { + return ascent; +} + +/** + * Returns the average character width, measured in pixels, + * of the font described by the receiver. + * + * @return the average character width of the font + */ +public int getAverageCharWidth() { + return averageCharWidth; +} + +/** + * Returns the descent of the font described by the receiver. A + * font's <em>descent</em> is the distance from the baseline to the + * bottom of actual characters, not including any of the leading area, + * measured in pixels. + * + * @return the descent of the font + */ +public int getDescent() { + return descent; +} + +/** + * Returns the height of the font described by the receiver, + * measured in pixels. A font's <em>height</em> is the sum of + * its ascent, descent and leading area. + * + * @return the height of the font + * + * @see #getAscent + * @see #getDescent + * @see #getLeading + */ +public int getHeight() { + return height; +} + +/** + * Returns the leading area of the font described by the + * receiver. A font's <em>leading area</em> is the space + * above its ascent which may include accents or other marks. + * + * @return the leading space of the font + */ +public int getLeading() { + return leading; +} + +/** + * 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 + * + * @see #equals + */ +public int hashCode() { + return ascent ^ descent ^ averageCharWidth ^ leading ^ height; +} + +public static FontMetrics wpf_new(int ascent, int descent, int averageCharWidth, int leading, int height) { + FontMetrics fontMetrics = new FontMetrics(); + fontMetrics.ascent = ascent; + fontMetrics.descent = descent; + fontMetrics.averageCharWidth = averageCharWidth; + fontMetrics.leading = leading; + fontMetrics.height = height; + return fontMetrics; +} + +} diff --git a/bundles/org.eclipse.swt/Eclipse SWT/wpf/org/eclipse/swt/graphics/GC.java b/bundles/org.eclipse.swt/Eclipse SWT/wpf/org/eclipse/swt/graphics/GC.java new file mode 100644 index 0000000000..f12d2127a5 --- /dev/null +++ b/bundles/org.eclipse.swt/Eclipse SWT/wpf/org/eclipse/swt/graphics/GC.java @@ -0,0 +1,2866 @@ +/******************************************************************************* + * Copyright (c) 2000, 2006 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.swt.graphics; + +import org.eclipse.swt.internal.wpf.*; +import org.eclipse.swt.*; + +/** + * 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> + * 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 + */ + +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> + */ + public int handle; + + Drawable drawable; + GCData data; + + static final int FOREGROUND = 1 << 0; + static final int BACKGROUND = 1 << 1; + static final int FONT = 1 << 2; + static final int LINE_STYLE = 1 << 3; + static final int LINE_WIDTH = 1 << 4; + static final int LINE_CAP = 1 << 5; + static final int LINE_JOIN = 1 << 6; + static final int ALPHA = 1 << 7; + static final int CLIPPING = 1 << 8; + static final int TRANSFORM = 1 << 9; + + static final int DRAW = FOREGROUND | LINE_STYLE | LINE_WIDTH | LINE_CAP | LINE_JOIN | ALPHA | CLIPPING | TRANSFORM; + static final int FILL = BACKGROUND | ALPHA | CLIPPING | TRANSFORM; + + static final double[] LINE_DOT_ZERO = new double[]{3, 3}; + static final double[] LINE_DASH_ZERO = new double[]{18, 6}; + static final double[] LINE_DASHDOT_ZERO = new double[]{9, 6, 3, 6}; + static final double[] LINE_DASHDOTDOT_ZERO = new double[]{9, 3, 3, 3, 3, 3}; + +/** + * Prevents uninitialized instances from being created outside the package. + */ +GC() { +} + +/** + * Constructs a new instance of this class which has been + * configured to draw on the specified drawable. Sets the + * foreground and background color 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> + * </ul> + */ +public GC(Drawable drawable) { + this(drawable, SWT.NONE); +} + +/** + * Constructs a new instance of this class which has been + * configured to draw on the specified drawable. Sets the + * foreground and background color 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> + * </ul> + * + * @since 2.1.2 + */ +public GC(Drawable drawable, int style) { + if (drawable == null) SWT.error(SWT.ERROR_NULL_ARGUMENT); + GCData data = new GCData (); + data.style = checkStyle(style); + int hDC = 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, hDC); + if (device.tracking) device.new_Object(this); +} + +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); +} + +void checkGC(int mask) { + int state = data.state; + if ((state & mask) == mask) return; + state = (state ^ mask) & mask; + data.state |= mask; + if ((state & (FOREGROUND | LINE_WIDTH | LINE_STYLE | LINE_JOIN | LINE_CAP)) != 0) { + int pen = data.pen; + if (pen != 0) OS.GCHandle_Free(pen); + pen = data.pen = OS.gcnew_Pen(); + int brush; + Pattern pattern = data.foregroundPattern; + if (pattern != null) { + brush = pattern.handle; + } else { + int foreground = data.foreground; + brush = OS.gcnew_SolidColorBrush(foreground); + if (brush == 0) SWT.error(SWT.ERROR_NO_HANDLES); + } + OS.Pen_Brush(pen, brush); + if (pattern == null) OS.GCHandle_Free(brush); + int width = data.lineWidth; + OS.Pen_Thickness(pen, Math.max (1, width)); + double[] dashes = null; + int dashStyle = 0; + switch (data.lineStyle) { + case SWT.LINE_SOLID: dashStyle = OS.DashStyles_Solid(); break; + case SWT.LINE_DOT: if (width == 0) dashes = LINE_DOT_ZERO; else dashStyle = OS.DashStyles_Dot(); break; + case SWT.LINE_DASH: if (width == 0) dashes = LINE_DASH_ZERO; else dashStyle = OS.DashStyles_Dash(); break; + case SWT.LINE_DASHDOT: if (width == 0) dashes = LINE_DASHDOT_ZERO; else dashStyle = OS.DashStyles_DashDot(); break; + case SWT.LINE_DASHDOTDOT: if (width == 0) dashes = LINE_DASHDOTDOT_ZERO; else dashStyle = OS.DashStyles_DashDotDot(); break; + case SWT.LINE_CUSTOM: { + if (data.lineDashes != null) { + dashes = new double[data.lineDashes.length * 2]; + for (int i = 0; i < data.lineDashes.length; i++) { + double dash = (double)data.lineDashes[i] / Math.max (1, width); + dashes[i] = dash; + dashes[i + data.lineDashes.length] = dash; + } + } else { + dashStyle = OS.DashStyles_Solid(); + } + } + } + if (dashes != null) { + int list = OS.gcnew_DoubleCollection(dashes.length); + for (int i = 0; i < dashes.length; i++) { + OS.DoubleCollection_Add(list, dashes[i]); + } + dashStyle = OS.gcnew_DashStyle(list, 0); + OS.GCHandle_Free(list); + } + OS.Pen_DashStyle(pen, dashStyle); + OS.GCHandle_Free(dashStyle); + int joinStyle = 0; + switch (data.lineJoin) { + case SWT.JOIN_MITER: joinStyle = OS.PenLineJoin_Miter; break; + case SWT.JOIN_BEVEL: joinStyle = OS.PenLineJoin_Bevel; break; + case SWT.JOIN_ROUND: joinStyle = OS.PenLineJoin_Round; break; + } + OS.Pen_LineJoin(pen, joinStyle); + int capStyle = OS.PenLineCap_Flat; + switch (data.lineCap) { + case SWT.CAP_FLAT: capStyle = OS.PenLineCap_Flat; break; + case SWT.CAP_ROUND: capStyle = OS.PenLineCap_Round; break; + case SWT.CAP_SQUARE: capStyle = OS.PenLineCap_Square; break; + } + OS.Pen_DashCap(pen, capStyle); + OS.Pen_EndLineCap(pen, capStyle); + OS.Pen_StartLineCap(pen, capStyle); + } + if ((state & BACKGROUND) != 0) { + if (data.brush != 0) OS.GCHandle_Free(data.brush); + Pattern pattern = data.backgroundPattern; + if (pattern != null) { + data.currentBrush = pattern.handle; + } else { + int background = data.background; + int brush = OS.gcnew_SolidColorBrush(background); + if (brush == 0) SWT.error(SWT.ERROR_NO_HANDLES); + data.currentBrush = data.brush = brush; + } + } + if ((state & (ALPHA | CLIPPING | TRANSFORM)) != 0) { + for (int i = 0; i < data.pushCount; i++) OS.DrawingContext_Pop(handle); + data.pushCount = 0; + if (data.alpha != 0xFF) { + OS.DrawingContext_PushOpacity(handle, (data.alpha & 0xFF) / (double)0xFF); + data.pushCount++; + } + if (data.clip != 0) { + OS.DrawingContext_PushClip(handle, data.clip); + data.pushCount++; + } + if (data.transform != 0) { + OS.DrawingContext_PushTransform(handle, data.transform); + data.pushCount++; + } + } + +} + +/** + * 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 == 0) 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); + + //TODO - implement copyArea +} + +/** + * 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 == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); + + //TODO - implement copyArea + +// /* +// * Feature in WinCE. The function WindowFromDC is not part of the +// * WinCE SDK. The fix is to remember the HWND. +// */ +// int hwnd = data.hwnd; +// if (hwnd == 0) { +// OS.BitBlt(handle, destX, destY, width, height, handle, srcX, srcY, OS.SRCCOPY); +// } else { +// RECT lprcClip = null; +// int hrgn = OS.CreateRectRgn(0, 0, 0, 0); +// if (OS.GetClipRgn(handle, hrgn) == 1) { +// lprcClip = new RECT(); +// OS.GetRgnBox(hrgn, lprcClip); +// } +// OS.DeleteObject(hrgn); +// RECT lprcScroll = new RECT(); +// OS.SetRect(lprcScroll, srcX, srcY, srcX + width, srcY + height); +// int flags = paint ? OS.SW_INVALIDATE | OS.SW_ERASE : 0; +// int res = OS.ScrollWindowEx(hwnd, destX - srcX, destY - srcY, lprcScroll, lprcClip, 0, null, flags); +// +// /* +// * Feature in WinCE. ScrollWindowEx does not accept combined +// * vertical and horizontal scrolling. The fix is to do a +// * BitBlt and invalidate the appropriate source area. +// */ +// if (res == 0 && OS.IsWinCE) { +// OS.BitBlt(handle, destX, destY, width, height, handle, srcX, srcY, OS.SRCCOPY); +// if (paint) { +// int deltaX = destX - srcX, deltaY = destY - srcY; +// boolean disjoint = (destX + width < srcX) || (srcX + width < destX) || (destY + height < srcY) || (srcY + height < destY); +// if (disjoint) { +// OS.InvalidateRect(hwnd, lprcScroll, true); +// } else { +// if (deltaX != 0) { +// int newX = destX - deltaX; +// if (deltaX < 0) newX = destX + width; +// OS.SetRect(lprcScroll, newX, srcY, newX + Math.abs(deltaX), srcY + height); +// OS.InvalidateRect(hwnd, lprcScroll, true); +// } +// if (deltaY != 0) { +// int newY = destY - deltaY; +// if (deltaY < 0) newY = destY + height; +// OS.SetRect(lprcScroll, srcX, newY, srcX + width, newY + Math.abs(deltaY)); +// OS.InvalidateRect(hwnd, lprcScroll, true); +// } +// } +// } +// } +// } +} + +/** + * Disposes of the operating system resources associated with + * the graphics context. Applications must dispose of all GCs + * which they allocate. + */ +public void dispose() { + if (handle == 0) return; + if (data.device.isDisposed()) return; + + int brush = data.brush; + if (brush != 0) OS.GCHandle_Free(brush); + data.brush = 0; + int pen = data.brush; + if (pen != 0) OS.GCHandle_Free(pen); + data.pen = 0; + int clip = data.clip; + if (clip != 0) OS.GCHandle_Free(clip); + data.clip = 0; + int transform = data.transform; + if (transform != 0) OS.GCHandle_Free(transform); + data.transform = 0; + + Image image = data.image; + if (image != null) image.memGC = null; + + Device device = data.device; + if (drawable != null) drawable.internal_dispose_GC(handle, data); + drawable = null; + handle = 0; + data.image = null; + if (device.tracking) device.dispose_Object(this); + data.device = null; + data = 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 == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); + checkGC(DRAW); + if (width < 0) { + x = x + width; + width = -width; + } + if (height < 0) { + y = y + height; + height = -height; + } + if (width == 0 || height == 0 || arcAngle == 0) return; + double offset = 0; + if (data.lineWidth == 0 || (data.lineWidth % 2) == 1) offset = 0.5; + if (arcAngle >= 360 || arcAngle <= -360) { + int center = OS.gcnew_Point(x + offset + width / 2f, y + offset + height / 2f); + OS.DrawingContext_DrawEllipse(handle, 0, data.pen, center, width / 2f, height / 2f); + OS.GCHandle_Free(center); + return; + } + boolean isNegative = arcAngle < 0; + boolean isLargeAngle = arcAngle > 180 || arcAngle < -180; + arcAngle = arcAngle + startAngle; + if (isNegative) { + // swap angles + int tmp = startAngle; + startAngle = arcAngle; + arcAngle = tmp; + } + double x1 = Math.cos(startAngle * Math.PI / 180) * width/2.0 + x + offset + width/2.0; + double y1 = -1 * Math.sin(startAngle * Math.PI / 180) * height/2.0 + y + offset + height/2.0; + double x2 = Math.cos(arcAngle * Math.PI / 180) * width/2.0 + x + offset + width/2.0; + double y2 = -1 * Math.sin(arcAngle * Math.PI / 180) * height/2.0 + y + offset + height/2.0; + int startPoint = OS.gcnew_Point(x1, y1); + int endPoint = OS.gcnew_Point(x2, y2); + int size = OS.gcnew_Size(width / 2.0, height / 2.0); + int arc = OS.gcnew_ArcSegment(endPoint, size, 0, isLargeAngle, OS.SweepDirection_Clockwise, true); + int figure = OS.gcnew_PathFigure(); + OS.PathFigure_StartPoint(figure, startPoint); + int segments = OS.PathFigure_Segments(figure); + OS.PathSegmentCollection_Add(segments, arc); + int path = OS.gcnew_PathGeometry(); + int figures = OS.PathGeometry_Figures(path); + OS.PathFigureCollection_Add(figures, figure); + OS.DrawingContext_DrawGeometry(handle, 0, data.pen, path); + OS.GCHandle_Free(figures); + OS.GCHandle_Free(path); + OS.GCHandle_Free(segments); + OS.GCHandle_Free(figure); + OS.GCHandle_Free(arc); + OS.GCHandle_Free(size); + OS.GCHandle_Free(endPoint); + OS.GCHandle_Free(startPoint); +} + +/** + * 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 == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); + //TODO - implement drawFocus +} + +/** + * 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 == 0) 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 == 0) 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 image, int srcX, int srcY, int srcWidth, int srcHeight, int destX, int destY, int destWidth, int destHeight, boolean simple) { + int imageHandle = image.handle; + int imgWidth = OS.BitmapSource_PixelWidth(imageHandle); + int imgHeight = OS.BitmapSource_PixelHeight(imageHandle); + 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); + } + } + int mode = 0; + switch (data.interpolation) { + case SWT.DEFAULT: mode = OS.BitmapScalingMode_Unspecified; break; + case SWT.NONE: mode = OS.BitmapScalingMode_LowQuality; break; + case SWT.LOW: mode = OS.BitmapScalingMode_LowQuality; break; + case SWT.HIGH: mode = OS.BitmapScalingMode_HighQuality; break; + default: + SWT.error(SWT.ERROR_INVALID_ARGUMENT); + } + if (srcX != 0 || srcY != 0 || srcWidth != imgWidth || srcHeight != imgHeight) { + int rect = OS.gcnew_Int32Rect(srcX, srcY, srcWidth, srcHeight); + imageHandle = OS.gcnew_CroppedBitmap(imageHandle, rect); + OS.RenderOptions_SetBitmapScalingMode(imageHandle, mode); + OS.GCHandle_Free(rect); + } else { + if (mode != OS.RenderOptions_GetBitmapScalingMode(imageHandle)) { + imageHandle = OS.Freezable_Clone(imageHandle); + OS.RenderOptions_SetBitmapScalingMode(imageHandle, mode); + } + } + int rect = OS.gcnew_Rect(destX, destY, destWidth, destHeight); + OS.DrawingContext_DrawImage(handle, imageHandle, rect); + OS.GCHandle_Free(rect); + if (image.handle != imageHandle) OS.GCHandle_Free(imageHandle); +} + +/** + * 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 == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); + checkGC(DRAW); + double offset = 0; + if (data.lineWidth == 0 || (data.lineWidth % 2) == 1) offset = 0.5; + int point0 = OS.gcnew_Point(x1 + offset, y1 + offset); + int point1 = OS.gcnew_Point(x2 + offset, y2 + offset); + OS.DrawingContext_DrawLine(handle, data.pen, point0, point1); + OS.GCHandle_Free(point0); + OS.GCHandle_Free(point1); +} + +/** + * 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 == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); + checkGC(DRAW); + if (width < 0) { + x = x + width; + width = -width; + } + if (height < 0) { + y = y + height; + height = -height; + } + double offset = 0; + if (data.lineWidth == 0 || (data.lineWidth % 2) == 1) offset = 0.5; + int center = OS.gcnew_Point(x + offset + width / 2f, y + offset + height / 2f); + OS.DrawingContext_DrawEllipse(handle, 0, data.pen, center, width / 2f, height / 2f); + OS.GCHandle_Free(center); +} + +/** + * Draws the path described by the parameter. + * + * @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> + * </ul> + * + * @see Path + * + * @since 3.1 + */ +public void drawPath (Path path) { + if (handle == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); + if (path == null) SWT.error(SWT.ERROR_NULL_ARGUMENT); + if (path.handle == 0) SWT.error(SWT.ERROR_INVALID_ARGUMENT); + checkGC(DRAW); + //TODO - check offset to draw in the midle of pixel + OS.PathGeometry_FillRule(path.handle, data.fillRule == SWT.FILL_EVEN_ODD ? OS.FillRule_EvenOdd : OS.FillRule_Nonzero); + OS.DrawingContext_DrawGeometry(handle, 0, data.pen, path.handle); +} + +/** + * 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 == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); + checkGC(DRAW); + int rect = OS.gcnew_Rect(x, y, 1, 1); + int brush = OS.Pen_Brush(data.pen); + OS.DrawingContext_DrawRectangle(handle, brush, 0, rect); + OS.GCHandle_Free(brush); + OS.GCHandle_Free(rect); +} + +/** + * 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 == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); + if (pointArray == null) SWT.error(SWT.ERROR_NULL_ARGUMENT); + checkGC(DRAW); + drawPolyLineSegment(pointArray, true, true); +} + +void drawPolyLineSegment(int[] pointArray, boolean closed, boolean stroked) { + if (pointArray.length < 4) return; + int list = OS.gcnew_PointCollection(pointArray.length / 2); + double offset = 0; + if (data.lineWidth == 0 || (data.lineWidth % 2) == 1) offset = 0.5; + for (int i = 0; i < pointArray.length; i += 2) { + int point = OS.gcnew_Point(pointArray[i] + offset, pointArray[i + 1] + offset); + OS.PointCollection_Add(list, point); + OS.GCHandle_Free(point); + } + int poly = OS.gcnew_PolyLineSegment(list, stroked); + OS.GCHandle_Free(list); + int figure = OS.gcnew_PathFigure(); + int startPoint = OS.gcnew_Point(pointArray[0], pointArray[1]); + OS.PathFigure_StartPoint(figure, startPoint); + OS.PathFigure_IsClosed(figure, closed); + int segments = OS.PathFigure_Segments(figure); + OS.PathSegmentCollection_Add(segments, poly); + int path = OS.gcnew_PathGeometry(); +// int mode = 0; +// switch (data.antialias) { +// case SWT.DEFAULT: +// case SWT.ON: mode = OS.EdgeMode_Unspecified; break; +// case SWT.OFF: mode = OS.EdgeMode_Aliased; break; +// } +// OS.RenderOptions_SetEdgeMode(path, mode); +// OS.PathGeometry_FillRule(path, data.fillRule == SWT.FILL_EVEN_ODD ? OS.FillRule_EvenOdd : OS.FillRule_Nonzero); + int figures = OS.PathGeometry_Figures(path); + OS.PathFigureCollection_Add(figures, figure); + OS.DrawingContext_DrawGeometry(handle, stroked ? 0 : data.brush, stroked ? data.pen : 0, path); + OS.GCHandle_Free(figures); + OS.GCHandle_Free(path); + OS.GCHandle_Free(segments); + OS.GCHandle_Free(figure); + OS.GCHandle_Free(startPoint); + OS.GCHandle_Free(poly); +} + +/** + * 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 == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); + if (pointArray == null) SWT.error(SWT.ERROR_NULL_ARGUMENT); + checkGC(DRAW); + drawPolyLineSegment(pointArray, false, true); +} + +/** + * 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 == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); + checkGC(DRAW); + if (width < 0) { + x = x + width; + width = -width; + } + if (height < 0) { + y = y + height; + height = -height; + } + double offset = 0; + if (data.lineWidth == 0 || (data.lineWidth % 2) == 1) offset = 0.5; + int rect = OS.gcnew_Rect(x + offset, y + offset, width, height); + OS.DrawingContext_DrawRectangle(handle, 0, data.pen, rect); + OS.GCHandle_Free(rect); +} + +/** + * 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 (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 == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); + if (arcWidth < 0 || arcHeight < 0) SWT.error(SWT.ERROR_INVALID_ARGUMENT); + checkGC(DRAW); + if (width < 0) { + x = x + width; + width = -width; + } + if (height < 0) { + y = y + height; + height = -height; + } + if (arcWidth < 0) arcWidth = -arcWidth; + if (arcHeight < 0) arcHeight = -arcHeight; + double offset = 0; + if (data.lineWidth == 0 || (data.lineWidth % 2) == 1) offset = 0.5; + int rect = OS.gcnew_Rect(x + offset, y + offset, width, height); + OS.DrawingContext_DrawRoundedRectangle(handle, 0, data.pen, rect, arcWidth / 2f, arcHeight / 2f); + OS.GCHandle_Free(rect); +} + +/** + * 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 specifing 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 == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); + if (string == null) SWT.error(SWT.ERROR_NULL_ARGUMENT); + int length = string.length (); + if (length == 0) return; + checkGC(FONT | FOREGROUND | ALPHA | CLIPPING | TRANSFORM | ((flags & SWT.DRAW_TRANSPARENT) != 0 ? 0 : BACKGROUND)); + char [] buffer = new char [length + 1]; + string.getChars (0, length, buffer, 0); + if ((flags & (SWT.DRAW_DELIMITER | SWT.DRAW_TAB)) != (SWT.DRAW_DELIMITER | SWT.DRAW_TAB)) { + for (int i = 0, j = 0; i < buffer.length; i++) { + char c = buffer[i]; + switch (c) { + case '\r': + case '\n': + if ((flags & SWT.DRAW_DELIMITER) == 0) continue; + break; + case '\t': + if ((flags & SWT.DRAW_TAB) == 0) continue; + break; + } + buffer[j++] = c; + } + } + int str = OS.gcnew_String (buffer); + int culture = OS.CultureInfo_CurrentUICulture(); + Font font = data.font; + int direction = (data.style & SWT.RIGHT_TO_LEFT) != 0 ? OS.FlowDirection_RightToLeft : OS.FlowDirection_LeftToRight; + int brush = OS.Pen_Brush(data.pen); + int text = OS.gcnew_FormattedText(str, culture, direction, font.handle, font.size, brush); + int point = OS.gcnew_Point(x, y); + if ((flags & SWT.DRAW_TRANSPARENT) == 0) { + double width = OS.FormattedText_WidthIncludingTrailingWhitespace(text); + double height = OS.FormattedText_Height(text); + int rect = OS.gcnew_Rect(x, y, width, height); + OS.DrawingContext_DrawRectangle(handle, data.currentBrush, 0, rect); + OS.GCHandle_Free(rect); + + } + OS.DrawingContext_DrawText(handle, text, point); + OS.GCHandle_Free(point); + OS.GCHandle_Free(culture); + OS.GCHandle_Free(str); + OS.GCHandle_Free(brush); + OS.GCHandle_Free(text); +} + +/** + * 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) { + return (object == this) || ((object instanceof GC) && (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 == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); + checkGC(FILL); + if (width < 0) { + x = x + width; + width = -width; + } + if (height < 0) { + y = y + height; + height = -height; + } + if (width == 0 || height == 0 || arcAngle == 0) return; + if (arcAngle >= 360 || arcAngle <= -360) { + int center = OS.gcnew_Point(x + width / 2f, y + height / 2f); + OS.DrawingContext_DrawEllipse(handle, data.brush, 0, center, width / 2f, height / 2f); + OS.GCHandle_Free(center); + return; + } + boolean isNegative = arcAngle < 0; + boolean isLargeAngle = arcAngle > 180 || arcAngle < -180; + arcAngle = arcAngle + startAngle; + if (isNegative) { + // swap angles + int tmp = startAngle; + startAngle = arcAngle; + arcAngle = tmp; + } + double x1 = Math.cos(startAngle * Math.PI / 180) * width/2.0 + x + width/2.0; + double y1 = -1 * Math.sin(startAngle * Math.PI / 180) * height/2.0 + y + height/2.0; + double x2 = Math.cos(arcAngle * Math.PI / 180) * width/2.0 + x + width/2.0; + double y2 = -1 * Math.sin(arcAngle * Math.PI / 180) * height/2.0 + y + height/2.0; + int startPoint = OS.gcnew_Point(x1, y1); + int endPoint = OS.gcnew_Point(x2, y2); + int center = OS.gcnew_Point(x + width / 2.0, y + height / 2.0); + int size = OS.gcnew_Size(width / 2.0, height / 2.0); + int arc = OS.gcnew_ArcSegment(endPoint, size, 0, isLargeAngle, OS.SweepDirection_Clockwise, false); + int line = OS.gcnew_LineSegment(center, false); + int figure = OS.gcnew_PathFigure(); + OS.PathFigure_StartPoint(figure, startPoint); + int segments = OS.PathFigure_Segments(figure); + OS.PathSegmentCollection_Add(segments, arc); + OS.PathSegmentCollection_Add(segments, line); + int path = OS.gcnew_PathGeometry(); + int figures = OS.PathGeometry_Figures(path); + OS.PathFigureCollection_Add(figures, figure); + OS.DrawingContext_DrawGeometry(handle, data.brush, 0, path); + OS.GCHandle_Free(figures); + OS.GCHandle_Free(path); + OS.GCHandle_Free(segments); + OS.GCHandle_Free(figure); + OS.GCHandle_Free(arc); + OS.GCHandle_Free(line); + OS.GCHandle_Free(size); + OS.GCHandle_Free(endPoint); + OS.GCHandle_Free(startPoint); +} + +/** + * 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 == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); + if (width == 0 || height == 0) return; + checkGC(FILL); + + int fromColor = data.foreground; + int toColor = data.background; + + 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) { + int temp = fromColor; + fromColor = toColor; + toColor = temp; + } + int brush = OS.gcnew_LinearGradientBrush(fromColor, toColor, vertical ? 90 : 0); + int rect = OS.gcnew_Rect(x, y, width, height); + OS.DrawingContext_DrawRectangle(handle, brush, 0, rect); + OS.GCHandle_Free(rect); + OS.GCHandle_Free(brush); +} + +/** + * 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 == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); + checkGC(FILL); + if (width < 0) { + x = x + width; + width = -width; + } + if (height < 0) { + y = y + height; + height = -height; + } + int center = OS.gcnew_Point(x + width / 2f, y + height / 2f); + OS.DrawingContext_DrawEllipse(handle, data.currentBrush, 0, center, width / 2f, height / 2f); + OS.GCHandle_Free(center); +} + +/** + * Fills the path described by the parameter. + * + * @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> + * </ul> + * + * @see Path + * + * @since 3.1 + */ +public void fillPath (Path path) { + if (handle == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); + if (path == null) SWT.error(SWT.ERROR_NULL_ARGUMENT); + if (path.handle == 0) SWT.error(SWT.ERROR_INVALID_ARGUMENT); + checkGC(FILL); + OS.PathGeometry_FillRule(path.handle, data.fillRule == SWT.FILL_EVEN_ODD ? OS.FillRule_EvenOdd : OS.FillRule_Nonzero); + OS.DrawingContext_DrawGeometry(handle, data.brush, 0, path.handle); +} + +/** + * 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 == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); + if (pointArray == null) SWT.error(SWT.ERROR_NULL_ARGUMENT); + checkGC(FILL); + drawPolyLineSegment(pointArray, true, false); +} + +/** + * 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 == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); + checkGC(FILL); + if (width < 0) { + x = x + width; + width = -width; + } + if (height < 0) { + y = y + height; + height = -height; + } + int rect = OS.gcnew_Rect(x, y, width, height); + OS.DrawingContext_DrawRectangle(handle, data.currentBrush, 0, rect); + OS.GCHandle_Free(rect); +} + +/** + * 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 (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 == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); + checkGC(FILL); + if (width < 0) { + x = x + width; + width = -width; + } + if (height < 0) { + y = y + height; + height = -height; + } + if (arcWidth < 0) arcWidth = -arcWidth; + if (arcHeight < 0) arcHeight = -arcHeight; + int rect = OS.gcnew_Rect(x, y, width, height); + OS.DrawingContext_DrawRoundedRectangle(handle, data.currentBrush, 0, rect, arcWidth / 2f, arcHeight / 2f); + OS.GCHandle_Free(rect); +} + +/** + * 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 == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); + //NOT DONE + return stringExtent(new String(new char[]{ch})).x; +} + +/** + * 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 == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); + return true; +} + +/** + * Returns the receiver's alpha value. + * + * @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 == 0) 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 == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); + return data.antialias; +} + +/** + * 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 == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); + return Color.wpf_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 == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); + return data.backgroundPattern; +} + +/** + * 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 == 0) 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 == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); + int x = 0, y = 0, width = 0, height = 0; + int visualType = OS.Object_GetType(data.visual); + int drawingVisualType = OS.DrawingVisual_typeid(); + if (OS.Object_Equals(visualType, drawingVisualType)) { + int clip = OS.ContainerVisual_Clip(data.visual); + int rect = OS.Geometry_Bounds(clip); + width = (int)OS.Rect_Width(rect); + height = (int)OS.Rect_Height(rect); + OS.GCHandle_Free(rect); + OS.GCHandle_Free(clip); + } else { + width = (int)OS.FrameworkElement_ActualWidth(data.visual); + height = (int)OS.FrameworkElement_ActualHeight(data.visual); + } + OS.GCHandle_Free(drawingVisualType); + OS.GCHandle_Free(visualType); + if (data.clip != 0) { + int bounds = OS.gcnew_Rect(x, y, width, height); + int rect = OS.Geometry_Bounds(data.clip); + OS.Rect_Intersect(bounds, rect); + x = (int)OS.Rect_X(bounds); + y = (int)OS.Rect_Y(bounds); + width = (int)OS.Rect_Width(bounds); + height = (int)OS.Rect_Height(bounds); + OS.GCHandle_Free(rect); + OS.GCHandle_Free(bounds); + } + return new Rectangle(x, y, width, height); +} + +/** + * Sets the region managed by the argument to the current + * clipping region of the receiver. + * + * @param region the region to fill with the clipping region + * + * @exception IllegalArgumentException <ul> + * <li>ERROR_NULL_ARGUMENT - if the region is null</li> + * <li>ERROR_INVALID_ARGUMENT - if the region is disposed</li> + * </ul> + * @exception SWTException <ul> + * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> + * </ul> + */ +public void getClipping (Region region) { + if (handle == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); + if (region == null) SWT.error (SWT.ERROR_NULL_ARGUMENT); + if (region.isDisposed()) SWT.error (SWT.ERROR_INVALID_ARGUMENT); + int bounds; + int visualType = OS.Object_GetType(data.visual); + int drawingVisualType = OS.DrawingVisual_typeid(); + if (OS.Object_Equals(visualType, drawingVisualType)) { + bounds = OS.ContainerVisual_Clip(data.visual); + } else { + double width = OS.FrameworkElement_ActualWidth(data.visual); + double height = OS.FrameworkElement_ActualHeight(data.visual); + int rect = OS.gcnew_Rect(0, 0, width, height); + bounds = OS.gcnew_RectangleGeometry(rect); + OS.GCHandle_Free(rect); + } + OS.GCHandle_Free(drawingVisualType); + OS.GCHandle_Free(visualType); + int geometries = OS.GeometryGroup_Children(region.handle); + OS.GeometryCollection_Clear(geometries); + if (data.clip != 0) { + int clip = OS.Geometry_GetFlattenedPathGeometry(data.clip); + int newGeometry = OS.gcnew_CombinedGeometry(OS.GeometryCombineMode_Intersect, bounds, clip); + OS.GeometryCollection_Add(geometries, newGeometry); + OS.GCHandle_Free(clip); + OS.GCHandle_Free(newGeometry); + } else { + OS.GeometryCollection_Add(geometries, bounds); + } + OS.GCHandle_Free(bounds); + OS.GCHandle_Free(geometries); +} + +/** + * 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 == 0) 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 == 0) 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 == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); + checkGC(FONT); + //TODO - find a better way of getting font metrics + String string = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; + int length = string.length(); + char [] buffer = new char [length + 1]; + string.getChars (0, length, buffer, 0); + int str = OS.gcnew_String (buffer); + int culture = OS.CultureInfo_CurrentUICulture(); + Font font = data.font; + int direction = (data.style & SWT.RIGHT_TO_LEFT) != 0 ? OS.FlowDirection_RightToLeft : OS.FlowDirection_LeftToRight; + int brush = OS.Brushes_White(); + int text = OS.gcnew_FormattedText(str, culture, direction, font.handle, font.size, brush); + double width = OS.FormattedText_WidthIncludingTrailingWhitespace(text); + double height = OS.FormattedText_Height(text); + double baseline = OS.FormattedText_Baseline(text); + OS.GCHandle_Free(text); + OS.GCHandle_Free(brush); + OS.GCHandle_Free(culture); + OS.GCHandle_Free(str); + return FontMetrics.wpf_new((int)baseline, (int)(height - baseline), (int)width / string.length(), 0, (int)height); +} + +/** + * 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 == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); + return Color.wpf_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 == 0) SWT.error(SWT.ERROR_GRAPHIC_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 + * + * @since 3.2 + */ +public GCData getGCData() { + if (handle == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); + 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 == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); + return data.interpolation; +} + +/** + * 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 == 0) 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 lin 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 == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); + if (data.lineDashes == null) return null; + int[] lineDashes = new int[data.lineDashes.length]; + System.arraycopy(data.lineDashes, 0, lineDashes, 0, lineDashes.length); + 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 == 0) 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 == 0) 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 == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); + return 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 == 0) 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 == 0) 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 == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); + if (transform == null) SWT.error(SWT.ERROR_NULL_ARGUMENT); + if (transform.isDisposed()) SWT.error(SWT.ERROR_INVALID_ARGUMENT); + if (data.transform != 0) { + OS.MatrixTransform_Matrix(transform.handle, data.transform); + } 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 == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); + return data.xorMode; +} + +void init(Drawable drawable, GCData data, int hDC) { + int foreground = data.foreground; + if (foreground != -1) data.state &= ~FOREGROUND; + int background = data.background; + if (background != 0) data.state &= ~BACKGROUND; + Font font = data.font; + if (font != null) data.state &= ~FONT; + Image image = data.image; + if (image != null) image.memGC = this; +// int layout = data.layout; +// if (layout != -1) { +// if (!OS.IsWinCE && OS.WIN32_VERSION >= OS.VERSION(4, 10)) { +// int flags = OS.GetLayout(hDC); +// if ((flags & OS.LAYOUT_RTL) != (layout & OS.LAYOUT_RTL)) { +// flags &= ~OS.LAYOUT_RTL; +// OS.SetLayout(hDC, flags | layout); +// } +// if ((data.style & SWT.RIGHT_TO_LEFT) != 0) data.style |= SWT.MIRRORED; +// } +// } + this.drawable = drawable; + this.data = data; + handle = hDC; +} + +/** + * 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; +} + +/** + * 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 == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); + return data.clip != 0; +} + +/** + * Returns <code>true</code> if the GC has been disposed, + * and <code>false</code> otherwise. + * <p> + * This method gets the dispose state for the GC. + * When a GC has been disposed, it is an error to + * invoke any other method using the GC. + * + * @return <code>true</code> when the GC is disposed and <code>false</code> otherwise + */ +public boolean isDisposed() { + return handle == 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 #setInterpolation + * @see #setTextAntialias + * @see #setTransform + * @see #getAdvanced + * + * @since 3.1 + */ +public void setAdvanced(boolean advanced) { + if (handle == 0) 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 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. + * + * @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> + * </ul> + * + * @see #setTextAntialias + * + * @since 3.1 + */ +public void setAntialias(int antialias) { + if (handle == 0) 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.antialias = antialias; +} + +/** + * Sets the receiver's alpha value. + * + * @param alpha the alpha value + * + * @exception SWTException <ul> + * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> + * </ul> + * + * @since 3.1 + */ +public void setAlpha(int alpha) { + if (handle == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); + data.alpha = alpha & 0xFF; + data.state &= ~ALPHA; +} + +/** + * 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 == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); + if (color == null) SWT.error(SWT.ERROR_NULL_ARGUMENT); + if (color.isDisposed()) SWT.error(SWT.ERROR_INVALID_ARGUMENT); + if (data.backgroundPattern == null && data.background == color.handle) return; + data.backgroundPattern = null; + data.background = color.handle; + data.state &= ~BACKGROUND; +} + +/** + * Sets the background pattern. The default value is <code>null</code>. + * + * @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> + * </ul> + * + * @see Pattern + * + * @since 3.1 + */ +public void setBackgroundPattern (Pattern pattern) { + if (handle == 0) 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 == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); + if (width < 0) { + x = x + width; + width = -width; + } + if (height < 0) { + y = y + height; + height = -height; + } + int rect = OS.gcnew_Rect(x, y, width, height); + int clip = OS.gcnew_RectangleGeometry(rect); + OS.GCHandle_Free(rect); + if (data.clip != 0) OS.GCHandle_Free(data.clip); + data.clip = clip; + data.state &= ~CLIPPING; +} + +/** + * Sets the area of the receiver which can be changed + * by drawing operations to the path specified + * by the argument. + * + * @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> + * </ul> + * + * @see Path + * + * @since 3.1 + */ +public void setClipping (Path path) { + if (handle == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); + if (path != null && path.isDisposed()) SWT.error(SWT.ERROR_INVALID_ARGUMENT); + if (data.clip != 0) OS.GCHandle_Free(data.clip); + data.clip = path != null ? OS.Geometry_Clone(path.handle) : 0; + data.state &= ~CLIPPING; +} + +/** + * 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 == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); + if (rect == null) { + if (data.clip != 0) OS.GCHandle_Free(data.clip); + data.clip = 0; + data.state &= ~CLIPPING; + } 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 == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); + if (region != null && region.isDisposed()) SWT.error(SWT.ERROR_INVALID_ARGUMENT); + if (data.clip != 0) OS.GCHandle_Free(data.clip); + data.clip = region != null ? OS.Geometry_Clone(region.handle) : 0; + 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 == 0) 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; +} + +/** + * 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 == 0) 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 == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); + if (color == null) SWT.error(SWT.ERROR_NULL_ARGUMENT); + if (color.isDisposed()) SWT.error(SWT.ERROR_INVALID_ARGUMENT); + if (data.foregroundPattern == null && color.handle == data.foreground) return; + data.foregroundPattern = null; + data.foreground = color.handle; + data.state &= ~FOREGROUND; +} + +/** + * Sets the foreground pattern. The default value is <code>null</code>. + * + * @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> + * </ul> + * + * @see Pattern + * + * @since 3.1 + */ +public void setForegroundPattern (Pattern pattern) { + if (handle == 0) 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; +} + +/** + * 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>. + * + * @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> + * </ul> + * + * @since 3.1 + */ +public void setInterpolation(int interpolation) { + if (handle == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); + switch (interpolation) { + case SWT.DEFAULT: break; + case SWT.NONE: break; + case SWT.LOW: break; + case SWT.HIGH: break; + default: + SWT.error(SWT.ERROR_INVALID_ARGUMENT); + } + data.interpolation = interpolation; +} + +/** + * 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 == 0) 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 == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); + int[] 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 int[dashes.length]; + System.arraycopy(dashes, 0, data.lineDashes, 0, dashes.length); + 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 == 0) 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 == 0) 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 == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); + if (data.lineWidth == lineWidth) return; + data.lineWidth = lineWidth; + data.state &= ~LINE_WIDTH; + switch (data.lineStyle) { + case SWT.LINE_DOT: + case SWT.LINE_DASH: + case SWT.LINE_DASHDOT: + case SWT.LINE_DASHDOTDOT: + data.state &= ~LINE_STYLE; + } +} + +/** + * 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 == 0) 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. + * + * @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> + * </ul> + * + * @see #setAntialias + * + * @since 3.1 + */ +public void setTextAntialias(int antialias) { + if (handle == 0) 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. + * + * @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> + * </ul> + * + * @see Transform + * + * @since 3.1 + */ +public void setTransform(Transform transform) { + if (handle == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); + if (transform != null && transform.isDisposed()) SWT.error(SWT.ERROR_INVALID_ARGUMENT); + data.transform = transform != null ? OS.gcnew_MatrixTransform(transform.handle) : 0; + data.state &= ~TRANSFORM; +} + +/** + * 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 specifing 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 == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); + if (string == null) SWT.error (SWT.ERROR_NULL_ARGUMENT); + checkGC(FONT); + int length = string.length(); + char [] buffer = new char [length + 1]; + string.getChars (0, length, buffer, 0); + if ((flags & (SWT.DRAW_DELIMITER | SWT.DRAW_TAB)) != (SWT.DRAW_DELIMITER | SWT.DRAW_TAB)) { + for (int i = 0, j = 0; i < buffer.length; i++) { + char c = buffer[i]; + switch (c) { + case '\r': + case '\n': + if ((flags & SWT.DRAW_DELIMITER) == 0) continue; + break; + case '\t': + if ((flags & SWT.DRAW_TAB) == 0) continue; + break; + } + buffer[j++] = c; + } + } + int str = OS.gcnew_String (buffer); + int culture = OS.CultureInfo_CurrentUICulture(); + Font font = data.font; + int direction = (data.style & SWT.RIGHT_TO_LEFT) != 0 ? OS.FlowDirection_RightToLeft : OS.FlowDirection_LeftToRight; + int brush = OS.Brushes_White(); + int text = OS.gcnew_FormattedText(str, culture, direction, font.handle, font.size, brush); + double width = OS.FormattedText_WidthIncludingTrailingWhitespace(text); + double height = OS.FormattedText_Height(text); + OS.GCHandle_Free(text); + OS.GCHandle_Free(brush); + OS.GCHandle_Free(culture); + OS.GCHandle_Free(str); + return new Point((int)width, (int)height); +} + +/** + * Returns a string containing a concise, human-readable + * description of the receiver. + * + * @return a string representation of the receiver + */ +public String toString () { + if (isDisposed()) return "GC {*DISPOSED*}"; + return "GC {" + handle + "}"; +} + +/** + * 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> + */ +public static GC wpf_new(Drawable drawable, GCData data) { + GC gc = new GC(); + int hDC = drawable.internal_new_GC(data); + gc.device = data.device; + gc.init(drawable, data, hDC); + return gc; +} + +/** + * Invokes platform specific functionality to wrap a graphics context. + * <p> + * <b>IMPORTANT:</b> This method is <em>not</em> part of the public + * API for <code>GC</code>. It is marked public only so that it + * can be shared within the packages provided by SWT. It is not + * available on all platforms, and should never be called from + * application code. + * </p> + * + * @param hDC the Windows HDC. + * @param data the data for the receiver. + * + * @return a new <code>GC</code> + */ +public static GC wpf_new(int hDC, GCData data) { + GC gc = new GC(); + gc.device = data.device; + gc.init(null, data, hDC); + return gc; +} + +} diff --git a/bundles/org.eclipse.swt/Eclipse SWT/wpf/org/eclipse/swt/graphics/GCData.java b/bundles/org.eclipse.swt/Eclipse SWT/wpf/org/eclipse/swt/graphics/GCData.java new file mode 100644 index 0000000000..90d3583d39 --- /dev/null +++ b/bundles/org.eclipse.swt/Eclipse SWT/wpf/org/eclipse/swt/graphics/GCData.java @@ -0,0 +1,56 @@ +/******************************************************************************* + * Copyright (c) 2000, 2005 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.*; + +/** + * Instances of this class are descriptions of GCs in terms + * of unallocated platform-specific data fields. + * <p> + * <b>IMPORTANT:</b> This class is <em>not</em> part of the public + * API for SWT. 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> + */ + +public final class GCData { + public Device device; + public int style, state = -1; + public int foreground; + public int background; + public Font font; + public Pattern foregroundPattern; + public Pattern backgroundPattern; + public boolean xorMode; + public int fillRule = SWT.FILL_EVEN_ODD; + public int interpolation = SWT.DEFAULT; + public int antialias = SWT.DEFAULT; + public int textAntialias = SWT.DEFAULT; + public int lineStyle = SWT.LINE_SOLID; + public int lineWidth; + public int lineCap = SWT.CAP_FLAT; + public int lineJoin = SWT.JOIN_MITER; + public int[] lineDashes; + public int alpha = 0xFF; + + public Image image; + public int pen; + public int brush, currentBrush; + public int pushCount; + public int clip; + public int transform; + public int visual; + public int drawingContext; + public int renderHandle; +} diff --git a/bundles/org.eclipse.swt/Eclipse SWT/wpf/org/eclipse/swt/graphics/Image.java b/bundles/org.eclipse.swt/Eclipse SWT/wpf/org/eclipse/swt/graphics/Image.java new file mode 100644 index 0000000000..0a486f12f9 --- /dev/null +++ b/bundles/org.eclipse.swt/Eclipse SWT/wpf/org/eclipse/swt/graphics/Image.java @@ -0,0 +1,1145 @@ +/******************************************************************************* + * Copyright (c) 2000, 2006 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.swt.graphics; + + +import org.eclipse.swt.internal.wpf.*; +import org.eclipse.swt.*; + +import java.io.*; + +/** + * Instances of this class are graphics which have been prepared + * for display on a specific device. That is, they are ready + * to paint using methods such as <code>GC.drawImage()</code> + * and display on widgets with, for example, <code>Button.setImage()</code>. + * <p> + * If loaded from a file format that supports it, an + * <code>Image</code> may have transparency, meaning that certain + * pixels are specified as being transparent when drawn. Examples + * of file formats that support transparency are GIF and PNG. + * </p><p> + * There are two primary ways to use <code>Images</code>. + * The first is to load a graphic file from disk and create an + * <code>Image</code> from it. This is done using an <code>Image</code> + * constructor, for example: + * <pre> + * Image i = new Image(device, "C:\\graphic.bmp"); + * </pre> + * A graphic file may contain a color table specifying which + * colors the image was intended to possess. In the above example, + * these colors will be mapped to the closest available color in + * SWT. It is possible to get more control over the mapping of + * colors as the image is being created, using code of the form: + * <pre> + * ImageData data = new ImageData("C:\\graphic.bmp"); + * RGB[] rgbs = data.getRGBs(); + * // At this point, rgbs contains specifications of all + * // the colors contained within this image. You may + * // allocate as many of these colors as you wish by + * // using the Color constructor Color(RGB), then + * // create the image: + * Image i = new Image(device, data); + * </pre> + * <p> + * Applications which require even greater control over the image + * loading process should use the support provided in class + * <code>ImageLoader</code>. + * </p><p> + * Application code must explicitly invoke the <code>Image.dispose()</code> + * method to release the operating system resources managed by each instance + * when those instances are no longer required. + * </p> + * + * @see Color + * @see ImageData + * @see ImageLoader + */ + +public final class Image extends Resource implements Drawable { + + /** + * specifies whether the receiver is a bitmap or an icon + * (one of <code>SWT.BITMAP</code>, <code>SWT.ICON</code>) + * <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> + */ + public int type; + + /** + * the handle to the OS image resource + * (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> + */ + public int handle; + + /** + * specifies the transparent pixel + */ + int transparentPixel = -1; + + /** + * the GC which is drawing on the image + */ + GC memGC; + + /** + * the alpha data for the image + */ + byte[] alphaData; + + /** + * the global alpha value to be used for every pixel + */ + int alpha = -1; + + /** + * the image data used to create this image if it is a + * icon. Used only in WinCE + */ + ImageData data; + + /** + * width of the image + */ + int width = -1; + + /** + * height of the image + */ + int height = -1; + + /** + * specifies the default scanline padding + */ + static final int DEFAULT_SCANLINE_PAD = 4; + +/** + * Prevents uninitialized instances from being created outside the package. + */ +Image () { +} + +/** + * Constructs an empty instance of this class with the + * specified width and height. The result may be drawn upon + * by creating a GC and using any of its drawing operations, + * as shown in the following example: + * <pre> + * Image i = new Image(device, width, height); + * GC gc = new GC(i); + * gc.drawRectangle(0, 0, 50, 50); + * gc.dispose(); + * </pre> + * <p> + * Note: Some platforms may have a limitation on the size + * of image that can be created (size depends on width, height, + * and depth). For example, Windows 95, 98, and ME do not allow + * images larger than 16M. + * </p> + * + * @param device the device on which to create the image + * @param width the width of the new image + * @param height the height of the new image + * + * @exception IllegalArgumentException <ul> + * <li>ERROR_NULL_ARGUMENT - if device is null and there is no current device</li> + * <li>ERROR_INVALID_ARGUMENT - if either the width or height is negative or zero</li> + * </ul> + * @exception SWTError <ul> + * <li>ERROR_NO_HANDLES if a handle could not be obtained for image creation</li> + * </ul> + */ +public Image(Device device, int width, int height) { + if (device == null) device = Device.getDevice(); + if (device == null) SWT.error(SWT.ERROR_NULL_ARGUMENT); + init(device, width, height); + if (device.tracking) device.new_Object(this); +} + +/** + * Constructs a new instance of this class based on the + * provided image, with an appearance that varies depending + * on the value of the flag. The possible flag values are: + * <dl> + * <dt><b>IMAGE_COPY</b></dt> + * <dd>the result is an identical copy of srcImage</dd> + * <dt><b>IMAGE_DISABLE</b></dt> + * <dd>the result is a copy of srcImage which has a <em>disabled</em> look</dd> + * <dt><b>IMAGE_GRAY</b></dt> + * <dd>the result is a copy of srcImage which has a <em>gray scale</em> look</dd> + * </dl> + * + * @param device the device on which to create the image + * @param srcImage the image to use as the source + * @param flag the style, either <code>IMAGE_COPY</code>, <code>IMAGE_DISABLE</code> or <code>IMAGE_GRAY</code> + * + * @exception IllegalArgumentException <ul> + * <li>ERROR_NULL_ARGUMENT - if device is null and there is no current device</li> + * <li>ERROR_NULL_ARGUMENT - if srcImage is null</li> + * <li>ERROR_INVALID_ARGUMENT - if the flag is not one of <code>IMAGE_COPY</code>, <code>IMAGE_DISABLE</code> or <code>IMAGE_GRAY</code></li> + * <li>ERROR_INVALID_ARGUMENT - if the image has been disposed</li> + * </ul> + * @exception SWTException <ul> + * <li>ERROR_INVALID_IMAGE - if the image is not a bitmap or an icon, or is otherwise in an invalid state</li> + * <li>ERROR_UNSUPPORTED_DEPTH - if the depth of the image is not supported</li> + * </ul> + * @exception SWTError <ul> + * <li>ERROR_NO_HANDLES if a handle could not be obtained for image creation</li> + * </ul> + */ +public Image(Device device, Image srcImage, int flag) { + if (device == null) device = Device.getDevice(); + if (device == null) SWT.error(SWT.ERROR_NULL_ARGUMENT); + this.device = device; + if (srcImage == null) SWT.error(SWT.ERROR_NULL_ARGUMENT); + if (srcImage.isDisposed()) SWT.error(SWT.ERROR_INVALID_ARGUMENT); + Rectangle rect = srcImage.getBounds(); + switch (flag) { + case SWT.IMAGE_COPY: { + type = srcImage.type; + handle = OS.BitmapSource_Clone(srcImage.handle); + transparentPixel = srcImage.transparentPixel; + alpha = srcImage.alpha; + if (srcImage.alphaData != null) { + alphaData = new byte[srcImage.alphaData.length]; + System.arraycopy(srcImage.alphaData, 0, alphaData, 0, alphaData.length); + } + if (device.tracking) device.new_Object(this); + return; + } + case SWT.IMAGE_DISABLE: { + ImageData data = srcImage.getImageData(); + PaletteData palette = data.palette; + RGB[] rgbs = new RGB[3]; + rgbs[0] = device.getSystemColor(SWT.COLOR_BLACK).getRGB(); + rgbs[1] = device.getSystemColor(SWT.COLOR_WIDGET_NORMAL_SHADOW).getRGB(); + rgbs[2] = device.getSystemColor(SWT.COLOR_WIDGET_BACKGROUND).getRGB(); + ImageData newData = new ImageData(rect.width, rect.height, 8, new PaletteData(rgbs)); + newData.alpha = data.alpha; + newData.alphaData = data.alphaData; + newData.maskData = data.maskData; + newData.maskPad = data.maskPad; + if (data.transparentPixel != -1) newData.transparentPixel = 0; + + /* Convert the pixels. */ + int[] scanline = new int[rect.width]; + int[] maskScanline = null; + ImageData mask = null; + if (data.maskData != null) mask = data.getTransparencyMask(); + if (mask != null) maskScanline = new int[rect.width]; + int redMask = palette.redMask; + int greenMask = palette.greenMask; + int blueMask = palette.blueMask; + int redShift = palette.redShift; + int greenShift = palette.greenShift; + int blueShift = palette.blueShift; + for (int y=0; y<rect.height; y++) { + int offset = y * newData.bytesPerLine; + data.getPixels(0, y, rect.width, scanline, 0); + if (mask != null) mask.getPixels(0, y, rect.width, maskScanline, 0); + for (int x=0; x<rect.width; x++) { + int pixel = scanline[x]; + if (!(pixel == data.transparentPixel || (mask != null && maskScanline[x] == 0))) { + int red, green, blue; + if (palette.isDirect) { + red = pixel & redMask; + red = (redShift < 0) ? red >>> -redShift : red << redShift; + green = pixel & greenMask; + green = (greenShift < 0) ? green >>> -greenShift : green << greenShift; + blue = pixel & blueMask; + blue = (blueShift < 0) ? blue >>> -blueShift : blue << blueShift; + } else { + red = palette.colors[pixel].red; + green = palette.colors[pixel].green; + blue = palette.colors[pixel].blue; + } + int intensity = red * red + green * green + blue * blue; + if (intensity < 98304) { + newData.data[offset] = (byte)1; + } else { + newData.data[offset] = (byte)2; + } + } + offset++; + } + } + init (device, newData); + if (device.tracking) device.new_Object(this); + return; + } + case SWT.IMAGE_GRAY: { + ImageData data = srcImage.getImageData(); + PaletteData palette = data.palette; + ImageData newData = data; + if (!palette.isDirect) { + /* Convert the palette entries to gray. */ + RGB [] rgbs = palette.getRGBs(); + for (int i=0; i<rgbs.length; i++) { + if (data.transparentPixel != i) { + RGB color = rgbs [i]; + int red = color.red; + int green = color.green; + int blue = color.blue; + int intensity = (red+red+green+green+green+green+green+blue) >> 3; + color.red = color.green = color.blue = intensity; + } + } + newData.palette = new PaletteData(rgbs); + } else { + /* Create a 8 bit depth image data with a gray palette. */ + RGB[] rgbs = new RGB[256]; + for (int i=0; i<rgbs.length; i++) { + rgbs[i] = new RGB(i, i, i); + } + newData = new ImageData(rect.width, rect.height, 8, new PaletteData(rgbs)); + newData.alpha = data.alpha; + newData.alphaData = data.alphaData; + newData.maskData = data.maskData; + newData.maskPad = data.maskPad; + if (data.transparentPixel != -1) newData.transparentPixel = 254; + + /* Convert the pixels. */ + int[] scanline = new int[rect.width]; + int redMask = palette.redMask; + int greenMask = palette.greenMask; + int blueMask = palette.blueMask; + int redShift = palette.redShift; + int greenShift = palette.greenShift; + int blueShift = palette.blueShift; + for (int y=0; y<rect.height; y++) { + int offset = y * newData.bytesPerLine; + data.getPixels(0, y, rect.width, scanline, 0); + for (int x=0; x<rect.width; x++) { + int pixel = scanline[x]; + if (pixel != data.transparentPixel) { + int red = pixel & redMask; + red = (redShift < 0) ? red >>> -redShift : red << redShift; + int green = pixel & greenMask; + green = (greenShift < 0) ? green >>> -greenShift : green << greenShift; + int blue = pixel & blueMask; + blue = (blueShift < 0) ? blue >>> -blueShift : blue << blueShift; + int intensity = (red+red+green+green+green+green+green+blue) >> 3; + if (newData.transparentPixel == intensity) intensity = 255; + newData.data[offset] = (byte)intensity; + } else { + newData.data[offset] = (byte)254; + } + offset++; + } + } + } + init (device, newData); + if (device.tracking) device.new_Object(this); + return; + } + default: + SWT.error(SWT.ERROR_INVALID_ARGUMENT); + } +} + +/** + * Constructs an empty instance of this class with the + * width and height of the specified rectangle. The result + * may be drawn upon by creating a GC and using any of its + * drawing operations, as shown in the following example: + * <pre> + * Image i = new Image(device, boundsRectangle); + * GC gc = new GC(i); + * gc.drawRectangle(0, 0, 50, 50); + * gc.dispose(); + * </pre> + * <p> + * Note: Some platforms may have a limitation on the size + * of image that can be created (size depends on width, height, + * and depth). For example, Windows 95, 98, and ME do not allow + * images larger than 16M. + * </p> + * + * @param device the device on which to create the image + * @param bounds a rectangle specifying the image's width and height (must not be null) + * + * @exception IllegalArgumentException <ul> + * <li>ERROR_NULL_ARGUMENT - if device is null and there is no current device</li> + * <li>ERROR_NULL_ARGUMENT - if the bounds rectangle is null</li> + * <li>ERROR_INVALID_ARGUMENT - if either the rectangle's width or height is negative</li> + * </ul> + * @exception SWTError <ul> + * <li>ERROR_NO_HANDLES if a handle could not be obtained for image creation</li> + * </ul> + */ +public Image(Device device, Rectangle bounds) { + if (device == null) device = Device.getDevice(); + if (device == null) SWT.error(SWT.ERROR_NULL_ARGUMENT); + if (bounds == null) SWT.error(SWT.ERROR_NULL_ARGUMENT); + init(device, bounds.width, bounds.height); + if (device.tracking) device.new_Object(this); +} + +/** + * Constructs an instance of this class from the given + * <code>ImageData</code>. + * + * @param device the device on which to create the image + * @param data the image data to create the image from (must not be null) + * + * @exception IllegalArgumentException <ul> + * <li>ERROR_NULL_ARGUMENT - if device is null and there is no current device</li> + * <li>ERROR_NULL_ARGUMENT - if the image data is null</li> + * </ul> + * @exception SWTException <ul> + * <li>ERROR_UNSUPPORTED_DEPTH - if the depth of the ImageData is not supported</li> + * </ul> + * @exception SWTError <ul> + * <li>ERROR_NO_HANDLES if a handle could not be obtained for image creation</li> + * </ul> + */ +public Image(Device device, ImageData data) { + if (device == null) device = Device.getDevice(); + if (device == null) SWT.error(SWT.ERROR_NULL_ARGUMENT); + init(device, data); + if (device.tracking) device.new_Object(this); +} + +/** + * Constructs an instance of this class, whose type is + * <code>SWT.ICON</code>, from the two given <code>ImageData</code> + * objects. The two images must be the same size. Pixel transparency + * in either image will be ignored. + * <p> + * The mask image should contain white wherever the icon is to be visible, + * and black wherever the icon is to be transparent. In addition, + * the source image should contain black wherever the icon is to be + * transparent. + * </p> + * + * @param device the device on which to create the icon + * @param source the color data for the icon + * @param mask the mask data for the icon + * + * @exception IllegalArgumentException <ul> + * <li>ERROR_NULL_ARGUMENT - if device is null and there is no current device</li> + * <li>ERROR_NULL_ARGUMENT - if either the source or mask is null </li> + * <li>ERROR_INVALID_ARGUMENT - if source and mask are different sizes</li> + * </ul> + * @exception SWTError <ul> + * <li>ERROR_NO_HANDLES if a handle could not be obtained for image creation</li> + * </ul> + */ +public Image(Device device, ImageData source, ImageData mask) { + if (device == null) device = Device.getDevice(); + if (device == null) SWT.error(SWT.ERROR_NULL_ARGUMENT); + if (source == null) SWT.error(SWT.ERROR_NULL_ARGUMENT); + if (mask == null) SWT.error(SWT.ERROR_NULL_ARGUMENT); + if (source.width != mask.width || source.height != mask.height) { + SWT.error(SWT.ERROR_INVALID_ARGUMENT); + } + mask = ImageData.convertMask (mask); + ImageData image = new ImageData(source.width, source.height, source.depth, source.palette, source.scanlinePad, source.data); + image.maskPad = mask.scanlinePad; + image.maskData = mask.data; + init(device, image); + if (device.tracking) device.new_Object(this); +} + +/** + * Constructs an instance of this class by loading its representation + * from the specified input stream. Throws an error if an error + * occurs while loading the image, or if the result is an image + * of an unsupported type. Application code is still responsible + * for closing the input stream. + * <p> + * This constructor is provided for convenience when loading a single + * image only. If the stream contains multiple images, only the first + * one will be loaded. To load multiple images, use + * <code>ImageLoader.load()</code>. + * </p><p> + * This constructor may be used to load a resource as follows: + * </p> + * <pre> + * static Image loadImage (Display display, Class clazz, String string) { + * InputStream stream = clazz.getResourceAsStream (string); + * if (stream == null) return null; + * Image image = null; + * try { + * image = new Image (display, stream); + * } catch (SWTException ex) { + * } finally { + * try { + * stream.close (); + * } catch (IOException ex) {} + * } + * return image; + * } + * </pre> + * + * @param device the device on which to create the image + * @param stream the input stream to load the image from + * + * @exception IllegalArgumentException <ul> + * <li>ERROR_NULL_ARGUMENT - if device is null and there is no current device</li> + * <li>ERROR_NULL_ARGUMENT - if the stream is null</li> + * </ul> + * @exception SWTException <ul> + * <li>ERROR_IO - if an IO error occurs while reading from the stream</li> + * <li>ERROR_INVALID_IMAGE - if the image stream contains invalid data </li> + * <li>ERROR_UNSUPPORTED_DEPTH - if the image stream describes an image with an unsupported depth</li> + * <li>ERROR_UNSUPPORTED_FORMAT - if the image stream contains an unrecognized format</li> + * </ul> + * @exception SWTError <ul> + * <li>ERROR_NO_HANDLES if a handle could not be obtained for image creation</li> + * </ul> + */ +public Image (Device device, InputStream stream) { + if (device == null) device = Device.getDevice(); + if (device == null) SWT.error(SWT.ERROR_NULL_ARGUMENT); + init(device, new ImageData(stream)); + if (device.tracking) device.new_Object(this); +} + +/** + * Constructs an instance of this class by loading its representation + * from the file with the specified name. Throws an error if an error + * occurs while loading the image, or if the result is an image + * of an unsupported type. + * <p> + * This constructor is provided for convenience when loading + * a single image only. If the specified file contains + * multiple images, only the first one will be used. + * + * @param device the device on which to create the image + * @param filename the name of the file to load the image from + * + * @exception IllegalArgumentException <ul> + * <li>ERROR_NULL_ARGUMENT - if device is null and there is no current device</li> + * <li>ERROR_NULL_ARGUMENT - if the file name is null</li> + * </ul> + * @exception SWTException <ul> + * <li>ERROR_IO - if an IO error occurs while reading from the file</li> + * <li>ERROR_INVALID_IMAGE - if the image file contains invalid data </li> + * <li>ERROR_UNSUPPORTED_DEPTH - if the image file describes an image with an unsupported depth</li> + * <li>ERROR_UNSUPPORTED_FORMAT - if the image file contains an unrecognized format</li> + * </ul> + * @exception SWTError <ul> + * <li>ERROR_NO_HANDLES if a handle could not be obtained for image creation</li> + * </ul> + */ +public Image (Device device, String filename) { + if (device == null) device = Device.getDevice(); + if (device == null) SWT.error(SWT.ERROR_NULL_ARGUMENT); + if (filename == null) SWT.error(SWT.ERROR_NULL_ARGUMENT); + this.device = device; + try { + handle = OS.gcnew_BitmapImage(); + if (handle == 0) SWT.error(SWT.ERROR_NO_HANDLES); + int length = filename.length(); + char[] chars = new char[length + 1]; + filename.getChars(0, length, chars, 0); + int str = OS.gcnew_String(chars); + if (str == 0) SWT.error(SWT.ERROR_NO_HANDLES); + int uri = OS.gcnew_Uri(str, OS.UriKind_RelativeOrAbsolute); + if (uri == 0) SWT.error(SWT.ERROR_NO_HANDLES); + OS.BitmapImage_BeginInit(handle); + OS.BitmapImage_CreateOptions(handle, OS.BitmapCreateOptions_PreservePixelFormat); + OS.BitmapImage_UriSource(handle, uri); + OS.BitmapImage_EndInit(handle); + if (OS.Freezable_CanFreeze(handle)) OS.Freezable_Freeze(handle); + OS.GCHandle_Free(uri); + OS.GCHandle_Free(str); + return; + } catch (SWTException e) {} + init(device, new ImageData(filename)); + if(device.tracking) device.new_Object(this); +} + +/** + * Disposes of the operating system resources associated with + * the image. Applications must dispose of all images which + * they allocate. + */ +public void dispose () { + if (handle == 0) return; + if (device.isDisposed()) return; + if (memGC != null) memGC.dispose(); + OS.GCHandle_Free(handle); + handle = 0; + memGC = null; + if (device.tracking) device.dispose_Object(this); + device = null; +} + +/** + * 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 Image)) return false; + Image image = (Image) object; + return device == image.device && handle == image.handle; +} + +/** + * Returns the color to which to map the transparent pixel, or null if + * the receiver has no transparent pixel. + * <p> + * There are certain uses of Images that do not support transparency + * (for example, setting an image into a button or label). In these cases, + * it may be desired to simulate transparency by using the background + * color of the widget to paint the transparent pixels of the image. + * Use this method to check which color will be used in these cases + * in place of transparency. This value may be set with setBackground(). + * <p> + * + * @return the background color of the image, or null if there is no transparency in the image + * + * @exception SWTException <ul> + * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> + * </ul> + */ +public Color getBackground() { + if (isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); + if (transparentPixel == -1) return null; + //TODO implement Image.getBackground() + return null; +} + +/** + * Returns the bounds of the receiver. The rectangle will always + * have x and y values of 0, and the width and height of the + * image. + * + * @return a rectangle specifying the image's bounds + * + * @exception SWTException <ul> + * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> + * <li>ERROR_INVALID_IMAGE - if the image is not a bitmap or an icon</li> + * </ul> + */ +public Rectangle getBounds() { + if (isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); + if (width == -1 || height == -1) { + width = OS.BitmapSource_PixelWidth(handle); + height = OS.BitmapSource_PixelHeight(handle); + } + return new Rectangle(0, 0, width, height); +} + +Point getDPI () { + //TODO + return new Point (96, 96); +} + +/** + * Returns an <code>ImageData</code> based on the receiver + * Modifications made to this <code>ImageData</code> will not + * affect the Image. + * + * @return an <code>ImageData</code> containing the image's data and attributes + * + * @exception SWTException <ul> + * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> + * <li>ERROR_INVALID_IMAGE - if the image is not a bitmap or an icon</li> + * </ul> + * + * @see ImageData + */ +public ImageData getImageData() { + if (isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); + int format = OS.BitmapSource_Format(handle); + int depth = OS.PixelFormat_BitsPerPixel(format); + int width = OS.BitmapSource_PixelWidth(handle); + int height = OS.BitmapSource_PixelHeight(handle); + int scanlinePad = DEFAULT_SCANLINE_PAD; + int bytesPerLine = (((width * depth + 7) / 8) + (scanlinePad - 1)) / scanlinePad * scanlinePad; + byte[] buffer = new byte[bytesPerLine * height]; + int rect = OS.Int32Rect_Empty(); + OS.BitmapSource_CopyPixels(handle, rect, buffer, buffer.length, bytesPerLine); + OS.GCHandle_Free(rect); + PaletteData paletteData = null; + int palette = OS.BitmapSource_Palette(handle); + if (palette != 0) { + int colors = OS.BitmapPalette_Colors(palette); + int count = OS.ColorList_Count(colors); + RGB[] rgbs = new RGB[count]; + paletteData = new PaletteData(rgbs); + if (count != 0) { + int index = 0; + int enumerator = OS.ColorList_GetEnumerator(colors); + while (OS.IEnumerator_MoveNext(enumerator)) { + int color = OS.ColorList_Current(enumerator); + rgbs[index++] = new RGB(OS.Color_R(color) & 0xFF, OS.Color_G(color) & 0xFF, OS.Color_B(color) & 0xFF); + OS.GCHandle_Free(color); + } + OS.GCHandle_Free(enumerator); + } + OS.GCHandle_Free(colors); + OS.GCHandle_Free(palette); + } else { + int[] formats = { + OS.PixelFormats_Bgr555(), + OS.PixelFormats_Bgr565(), + OS.PixelFormats_Bgr24(), + OS.PixelFormats_Rgb24(), + OS.PixelFormats_Bgr32(), + OS.PixelFormats_Bgra32(), + OS.PixelFormats_Pbgra32(), + OS.PixelFormats_Bgr101010(), + }; + for (int i = 0; i < formats.length; i++) { + if (OS.Object_Equals(format, formats[i])) { + switch (i) { + case 0: paletteData = new PaletteData(0x7C00, 0x3E0, 0x1F); break; + case 1: paletteData = new PaletteData(0xF800, 0x7E0, 0x1F); break; + case 2: paletteData = new PaletteData(0xFF, 0xFF00, 0xFF0000); break; + case 3: paletteData = new PaletteData(0xFF0000, 0xFF00, 0xFF); break; + case 4: + case 5: + case 6: paletteData = new PaletteData(0xFF00, 0xFF0000, 0xFF000000); break; + case 7: paletteData = new PaletteData(0x3FF, 0xFFC00, 0x3FF0000); break; + } + } + OS.GCHandle_Free(formats[i]); + } + } + OS.GCHandle_Free(format); + ImageData data = new ImageData(width, height, depth, paletteData, scanlinePad, buffer); + data.transparentPixel = transparentPixel; + if (transparentPixel == -1 && type == SWT.ICON) { + /* Get the icon mask data */ + int maskPad = 2; + int maskBpl = (((width + 7) / 8) + (maskPad - 1)) / maskPad * maskPad; + byte[] maskData = new byte[height * maskBpl]; + int offset = 3, maskOffset = 0; + for (int y = 0; y<height; y++) { + for (int x = 0; x<width; x++) { + if (buffer[offset] != 0) { + maskData[maskOffset + (x >> 3)] |= (1 << (7 - (x & 0x7))); + } else { + maskData[maskOffset + (x >> 3)] &= ~(1 << (7 - (x & 0x7))); + } + offset += 4; + } + maskOffset += maskBpl; + } + data.maskData = maskData; + data.maskPad = maskPad; + } + data.alpha = alpha; + if (alpha == -1 && alphaData != null) { + data.alphaData = new byte[alphaData.length]; + System.arraycopy(alphaData, 0, data.alphaData, 0, alphaData.length); + } + return data; +} + +/** + * 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 + * + * @see #equals + */ +public int hashCode () { + return handle; +} + +void init(Device device, int width, int height) { + if (width <= 0 || height <= 0) { + SWT.error (SWT.ERROR_INVALID_ARGUMENT); + } + this.device = device; + type = SWT.BITMAP; + Point dpi = getDPI(); + int pixelFormat = OS.PixelFormats_Bgr24(); + int stride = width * 3; + byte[] buffer = new byte[stride * height]; + for (int i = 0; i < buffer.length; i++) { + buffer[i] = (byte)0xFF; + } + handle = OS.BitmapSource_Create(width, height, dpi.x, dpi.y, pixelFormat, 0, buffer, buffer.length, stride); + if (handle == 0) SWT.error(SWT.ERROR_NO_HANDLES); + OS.GCHandle_Free(pixelFormat); + if (OS.Freezable_CanFreeze(handle)) OS.Freezable_Freeze(handle); +} + +void init(Device device, ImageData data) { + PaletteData palette = data.palette; + if (!(((data.depth == 1 || data.depth == 2 || data.depth == 4 || data.depth == 8) && !palette.isDirect) || + ((data.depth == 8) || (data.depth == 16 || data.depth == 24 || data.depth == 32) && palette.isDirect))) + SWT.error (SWT.ERROR_UNSUPPORTED_DEPTH); + this.device = device; + int width = data.width; + int height = data.height; + int redMask = palette.redMask; + int greenMask = palette.greenMask; + int blueMask = palette.blueMask; + ImageData newData = null; + int pixelFormat = 0; + boolean transparent = false; + if (data.maskData != null) { + transparent= true; + } else { + if (data.transparentPixel != -1) { + transparent = palette.isDirect; + } else { + if (data.alpha != -1) { + transparent = palette.isDirect; + } else { + transparent = data.alphaData != null; + } + } + } + if (transparent) { + pixelFormat = OS.PixelFormats_Bgra32(); + if (!(palette.isDirect && data.depth == 32 && redMask == 0xFF00 && greenMask == 0xFF0000 && blueMask == 0xFF000000)) { + newData = new ImageData(width, height, 32, new PaletteData(0xFF00, 0xFF0000, 0xFF000000)); + } + } else { + switch (data.depth) { + case 1: pixelFormat = OS.PixelFormats_Indexed1(); break; + case 2: pixelFormat = OS.PixelFormats_Indexed2(); break; + case 4: pixelFormat = OS.PixelFormats_Indexed4(); break; + case 8: + if (!palette.isDirect) { + pixelFormat = OS.PixelFormats_Indexed8(); + } else { + pixelFormat = OS.PixelFormats_Bgr32(); + newData = new ImageData(data.width, data.height, 32, new PaletteData(0xFF00, 0xFF0000, 0xFF000000)); + } + break; + case 16: + if (redMask == 0x7C00 && greenMask == 0x3E0 && blueMask == 0x1F) { + pixelFormat = OS.PixelFormats_Bgr555(); + } else if (redMask == 0xF800 && greenMask == 0x7E0 && blueMask == 0x1F) { + pixelFormat = OS.PixelFormats_Bgr565(); + } else { + pixelFormat = OS.PixelFormats_Bgr555(); + newData = new ImageData(data.width, data.height, 16, new PaletteData(0x7C00, 0x3E0, 0x1F)); + } + break; + case 24: + if (redMask == 0xFF && greenMask == 0xFF00 && blueMask == 0xFF0000) { + pixelFormat = OS.PixelFormats_Bgr24(); + } else if (redMask == 0xFF0000 && greenMask == 0xFF00 && blueMask == 0xFF) { + pixelFormat = OS.PixelFormats_Rgb24(); + } else { + pixelFormat = OS.PixelFormats_Bgr24(); + newData = new ImageData(data.width, data.height, 24, new PaletteData(0xFF, 0xFF00, 0xFF0000)); + } + break; + case 32: + if (redMask == 0x3FF && greenMask == 0xFFC00 && blueMask == 0x3FF0000) { + pixelFormat = OS.PixelFormats_Bgr101010(); + } else if (redMask == 0xFF00 && greenMask == 0xFF0000 && blueMask == 0xFF000000) { + pixelFormat = OS.PixelFormats_Bgr32(); + } else { + pixelFormat = OS.PixelFormats_Bgr32(); + newData = new ImageData(data.width, data.height, 32, new PaletteData(0xFF00, 0xFF0000, 0xFF000000)); + } + break; + } + } + if (newData != null) { + PaletteData newPalette = newData.palette; + if (palette.isDirect) { + ImageData.blit(ImageData.BLIT_SRC, + data.data, data.depth, data.bytesPerLine, data.getByteOrder(), 0, 0, width, height, redMask, greenMask, blueMask, + ImageData.ALPHA_OPAQUE, null, 0, 0, 0, + newData.data, newData.depth, newData.bytesPerLine, newData.getByteOrder(), 0, 0, width, height, newPalette.redMask, newPalette.greenMask, newPalette.blueMask, + false, false); + } else { + RGB[] rgbs = palette.getRGBs(); + int length = rgbs.length; + byte[] srcReds = new byte[length]; + byte[] srcGreens = new byte[length]; + byte[] srcBlues = new byte[length]; + for (int i = 0; i < rgbs.length; i++) { + RGB rgb = rgbs[i]; + if (rgb == null) continue; + srcReds[i] = (byte)rgb.red; + srcGreens[i] = (byte)rgb.green; + srcBlues[i] = (byte)rgb.blue; + } + ImageData.blit(ImageData.BLIT_SRC, + data.data, data.depth, data.bytesPerLine, data.getByteOrder(), 0, 0, width, height, srcReds, srcGreens, srcBlues, + ImageData.ALPHA_OPAQUE, null, 0, 0, 0, + newData.data, newData.depth, newData.bytesPerLine, newData.getByteOrder(), 0, 0, width, height, newPalette.redMask, newPalette.greenMask, newPalette.blueMask, + false, false); + } + if (data.transparentPixel != -1) { + newData.transparentPixel = newPalette.getPixel(palette.getRGB(data.transparentPixel)); + } + newData.maskPad = data.maskPad; + newData.maskData = data.maskData; + newData.alpha = data.alpha; + newData.alphaData = data.alphaData; + data = newData; + palette = data.palette; + } + int bitmapPalette = 0; + if (!palette.isDirect) { + if (data.transparentPixel != -1) { + transparentPixel = data.transparentPixel; + } else { + alpha = data.alpha; + } + RGB[] rgbs = palette.colors; + int list = OS.gcnew_ColorList(rgbs.length); + for (int i = 0; i < rgbs.length; i++) { + RGB rgb = rgbs[i]; + byte alpha; + if (data.transparentPixel != -1) { + alpha = (byte)(i == data.transparentPixel ? 0 : 0xFF); + } else { + alpha = (byte)(data.alpha & 0xFF); + } + int color = OS.Color_FromArgb(alpha, (byte)rgb.red, (byte)rgb.green, (byte)rgb.blue); + OS.ColorList_Add(list, color); + OS.GCHandle_Free(color); + } + bitmapPalette = OS.gcnew_BitmapPalette(list); + OS.GCHandle_Free(list); + } + type = SWT.BITMAP; + if (transparent) { + if (data.maskData != null || data.transparentPixel != -1) { + this.type = data.transparentPixel != -1 ? SWT.BITMAP : SWT.ICON; + transparentPixel = data.transparentPixel; + ImageData maskImage = data.getTransparencyMask(); + byte[] maskData = maskImage.data; + int maskBpl = maskImage.bytesPerLine; + int offset = 3, maskOffset = 0; + for (int y = 0; y<height; y++) { + for (int x = 0; x<width; x++) { + data.data[offset] = ((maskData[maskOffset + (x >> 3)]) & (1 << (7 - (x & 0x7)))) != 0 ? (byte)0xff : 0; + offset += 4; + } + maskOffset += maskBpl; + } + } else if (data.alpha != -1) { + alpha = data.alpha; + for (int i = 3, j = 0; i < data.data.length; i+=4, j++) { + data.data[i] = (byte)alpha; + } + } else { + int length = data.alphaData.length; + alphaData = new byte[length]; + System.arraycopy(data.alphaData, 0, alphaData, 0, length); + for (int i = 3, j = 0; i < data.data.length; i+=4, j++) { + data.data[i] = alphaData[j]; + } + } + } + Point dpi = getDPI(); + handle = OS.BitmapSource_Create(width, height, dpi.x, dpi.y, pixelFormat, bitmapPalette, data.data, data.data.length, data.bytesPerLine); + if (OS.Freezable_CanFreeze(handle)) OS.Freezable_Freeze(handle); + OS.GCHandle_Free(pixelFormat); + if (bitmapPalette != 0) OS.GCHandle_Free(bitmapPalette); + if (handle == 0) SWT.error(SWT.ERROR_NO_HANDLES); +} + +/** + * Invokes platform specific functionality to allocate a new GC handle. + * <p> + * <b>IMPORTANT:</b> This method is <em>not</em> part of the public + * API for <code>Image</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 data the platform specific GC data + * @return the platform specific GC handle + */ +public int internal_new_GC (GCData data) { + if (handle == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); + /* + * Create a new GC that can draw into the image. + * Only supported for bitmaps. + */ + if (type != SWT.BITMAP || memGC != null) { + SWT.error(SWT.ERROR_INVALID_ARGUMENT); + } + if (width == -1 || height == -1) { + width = OS.BitmapSource_PixelWidth(handle); + height = OS.BitmapSource_PixelHeight(handle); + } + + int visual = OS.gcnew_DrawingVisual(); + if (visual == 0) SWT.error(SWT.ERROR_NO_HANDLES); + int rect = OS.gcnew_Rect(0, 0, width, height); + int geometry = OS.gcnew_RectangleGeometry(rect); + OS.ContainerVisual_Clip (visual, geometry); + int dc = OS.DrawingVisual_RenderOpen(visual); + if (dc == 0) SWT.error(SWT.ERROR_NO_HANDLES); + Point dpi = getDPI(); + int pixelFormat = OS.PixelFormats_Pbgra32(); + int renderHandle = OS.gcnew_RenderTargetBitmap(width, height, dpi.x, dpi.y, pixelFormat); + if (renderHandle == 0) SWT.error(SWT.ERROR_NO_HANDLES); + OS.DrawingContext_DrawImage(dc, handle, rect); + OS.GCHandle_Free(rect); + OS.GCHandle_Free(geometry); + if (data != null) { + int mask = SWT.LEFT_TO_RIGHT | SWT.RIGHT_TO_LEFT; + if ((data.style & mask) == 0) { + data.style |= SWT.LEFT_TO_RIGHT; + } + data.device = device; + data.image = this; + data.background = OS.Colors_White; + data.foreground = OS.Colors_Black; + data.font = device.systemFont; + data.visual = visual; + data.renderHandle = renderHandle; + } + return dc; +} + +/** + * Invokes platform specific functionality to dispose a GC handle. + * <p> + * <b>IMPORTANT:</b> This method is <em>not</em> part of the public + * API for <code>Image</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 dc the platform specific GC handle + * @param data the platform specific GC data + */ +public void internal_dispose_GC (int dc, GCData data) { + OS.DrawingContext_Close(dc); + int renderHandle = data.renderHandle; + OS.RenderTargetBitmap_Render(renderHandle, data.visual); + OS.GCHandle_Free(data.visual); + OS.GCHandle_Free(dc); + int format = OS.BitmapSource_Format(handle); + int palette = OS.BitmapSource_Palette(handle); + OS.GCHandle_Free(handle); + handle = OS.gcnew_FormatConvertedBitmap(renderHandle, format, palette, 100); + if (handle == 0) SWT.error(SWT.ERROR_NO_HANDLES); + OS.GCHandle_Free(renderHandle); + renderHandle = 0; + if (OS.Freezable_CanFreeze(handle)) OS.Freezable_Freeze(handle); +} + +/** + * Returns <code>true</code> if the image has been disposed, + * and <code>false</code> otherwise. + * <p> + * This method gets the dispose state for the image. + * When an image has been disposed, it is an error to + * invoke any other method using the image. + * + * @return <code>true</code> when the image is disposed and <code>false</code> otherwise + */ +public boolean isDisposed() { + return handle == 0; +} + +/** + * Sets the color to which to map the transparent pixel. + * <p> + * There are certain uses of <code>Images</code> that do not support + * transparency (for example, setting an image into a button or label). + * In these cases, it may be desired to simulate transparency by using + * the background color of the widget to paint the transparent pixels + * of the image. This method specifies the color that will be used in + * these cases. For example: + * <pre> + * Button b = new Button(); + * image.setBackground(b.getBackground()); + * b.setImage(image); + * </pre> + * </p><p> + * The image may be modified by this operation (in effect, the + * transparent regions may be filled with the supplied color). Hence + * this operation is not reversible and it is not legal to call + * this function twice or with a null argument. + * </p><p> + * This method has no effect if the receiver does not have a transparent + * pixel value. + * </p> + * + * @param color the color to use when a transparent pixel is specified + * + * @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 (isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); + if (color == null) SWT.error(SWT.ERROR_NULL_ARGUMENT); + if (color.isDisposed()) SWT.error(SWT.ERROR_INVALID_ARGUMENT); + if (transparentPixel == -1) return; + //TODO implement Image.setBackground() +} + +/** + * 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 "Image {*DISPOSED*}"; + return "Image {" + handle + "}"; +} + +/** + * Invokes platform specific functionality to allocate a new image. + * <p> + * <b>IMPORTANT:</b> This method is <em>not</em> part of the public + * API for <code>Image</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 device the device on which to allocate the color + * @param type the type of the image (<code>SWT.BITMAP</code> or <code>SWT.ICON</code>) + * @param handle the OS handle for the image + * @return a new image object containing the specified device, type and handle + */ +public static Image wpf_new(Device device, int type, int handle) { + if (device == null) device = Device.getDevice(); + Image image = new Image(); + image.type = type; + image.handle = handle; + image.device = device; + return image; +} + +} diff --git a/bundles/org.eclipse.swt/Eclipse SWT/wpf/org/eclipse/swt/graphics/Path.java b/bundles/org.eclipse.swt/Eclipse SWT/wpf/org/eclipse/swt/graphics/Path.java new file mode 100644 index 0000000000..79c022a24e --- /dev/null +++ b/bundles/org.eclipse.swt/Eclipse SWT/wpf/org/eclipse/swt/graphics/Path.java @@ -0,0 +1,578 @@ +/******************************************************************************* + * Copyright (c) 2000, 2006 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.swt.graphics; + +import org.eclipse.swt.*; +import org.eclipse.swt.internal.wpf.*; + +/** + * Instances of this class represent paths through the two-dimensional + * coordinate system. Paths do not have to be continuous, and can be + * described using lines, rectangles, arcs, cubic or quadratic bezier curves, + * glyphs, or other paths. + * <p> + * Application code must explicitly invoke the <code>Path.dispose()</code> + * method to release the operating system resources managed by each instance + * when those instances are no longer required. + * </p> + * + * @since 3.1 + */ +public class Path extends Resource { + + /** + * the OS resource for the Path + * (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> + */ + public int handle; + + int currentFigure, currentPoint; + +/** + * Constructs a new empty Path. + * + * @param device the device on which to allocate the path + * + * @exception IllegalArgumentException <ul> + * <li>ERROR_NULL_ARGUMENT - if the device is null and there is no current device</li> + * </ul> + * @exception SWTError <ul> + * <li>ERROR_NO_HANDLES if a handle for the path could not be obtained/li> + * </ul> + * + * @see #dispose() + */ +public Path (Device device) { + if (device == null) device = Device.getDevice(); + if (device == null) SWT.error(SWT.ERROR_NULL_ARGUMENT); + this.device = device; + handle = OS.gcnew_PathGeometry(); + if (handle == 0) SWT.error(SWT.ERROR_NO_HANDLES); + if (device.tracking) device.new_Object(this); +} + +/** + * Adds to the receiver a circular or elliptical arc that lies within + * the specified rectangular area. + * <p> + * The resulting arc begins at <code>startAngle</code> and extends + * for <code>arcAngle</code> degrees. + * 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 + * @param y the y coordinate of the upper-left corner of the arc + * @param width the width of the arc + * @param height the height of the arc + * @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 addArc(float x, float y, float width, float height, float startAngle, float arcAngle) { + if (isDisposed()) 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; + boolean isNegative = arcAngle < 0; + boolean isLargeAngle = arcAngle > 180 || arcAngle < -180; + arcAngle = arcAngle + startAngle; + if (isNegative) { + // swap angles + float tmp = startAngle; + startAngle = arcAngle; + arcAngle = tmp; + } + double x1 = Math.cos(startAngle * Math.PI / 180) * width/2.0 + x + width/2.0; + double y1 = -1 * Math.sin(startAngle * Math.PI / 180) * height/2.0 + y + height/2.0; + double x2 = Math.cos(arcAngle * Math.PI / 180) * width/2.0 + x + width/2.0; + double y2 = -1 * Math.sin(arcAngle * Math.PI / 180) * height/2.0 + y + height/2.0; + if (currentFigure == 0) { + currentFigure = OS.gcnew_PathFigure(); + int figures = OS.PathGeometry_Figures(handle); + OS.PathFigureCollection_Add(figures, currentFigure); + OS.GCHandle_Free(figures); + } + int startPoint = OS.gcnew_Point(x1, y1); + int endPoint = OS.gcnew_Point(x2, y2); + int size = OS.gcnew_Size(width / 2.0, height / 2.0); + int arc = OS.gcnew_ArcSegment(endPoint, size, 0, isLargeAngle, OS.SweepDirection_Clockwise, true); + int segments = OS.PathFigure_Segments(currentFigure); + if (OS.PathSegmentCollection_Count(segments) != 0) { + int segment = OS.gcnew_LineSegment(startPoint, true); + OS.PathSegmentCollection_Add(segments, segment); + OS.GCHandle_Free(segment); + } else { + OS.PathFigure_StartPoint(currentFigure, startPoint); + } + OS.PathSegmentCollection_Add(segments, arc); + OS.GCHandle_Free(segments); + OS.GCHandle_Free(arc); + OS.GCHandle_Free(size); + OS.GCHandle_Free(startPoint); + if (currentPoint != 0) OS.GCHandle_Free(currentPoint); + currentPoint = endPoint; + if (arcAngle > 360 || arcAngle < -360) { + OS.GCHandle_Free(currentFigure); + currentFigure = 0; + } + +} + +/** + * Adds to the receiver the path described by the parameter. + * + * @param path the path to add to the receiver + * + * @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> + */ +public void addPath(Path path) { + if (isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); + if (path == null) SWT.error(SWT.ERROR_NULL_ARGUMENT); + if (path.isDisposed()) SWT.error(SWT.ERROR_INVALID_ARGUMENT); + OS.PathGeometry_AddGeometry(handle, path.handle); + if (path.currentPoint != 0) { + currentPoint = OS.gcnew_Point(OS.Point_X(path.currentPoint), OS.Point_Y(path.currentPoint)); + } + int figures = OS.PathGeometry_Figures(handle); + int count = OS.PathFigureCollection_Count(figures); + OS.GCHandle_Free(figures); + if (count != 0) { + int figure = OS.PathGeometry_Figures(handle, count - 1); + if (!OS.PathFigure_IsClosed(figure)) { + currentFigure = figure; + return; + } + OS.GCHandle_Free(figure); + } + +} + +/** + * Adds to the receiver the rectangle specified by x, y, width and height. + * + * @param x the x coordinate of the rectangle to add + * @param y the y coordinate of the rectangle to add + * @param width the width of the rectangle to add + * @param height the height of the rectangle to add + * + * @exception SWTException <ul> + * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> + * </ul> + */ +public void addRectangle(float x, float y, float width, float height) { + if (isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); + int rect = OS.gcnew_Rect(x, y, width, height); + int geometry = OS.gcnew_RectangleGeometry(rect); + OS.PathGeometry_AddGeometry(handle, geometry); + OS.GCHandle_Free(geometry); + OS.GCHandle_Free(rect); + if (currentFigure != 0) OS.GCHandle_Free(currentFigure); + currentFigure = 0; + int point = OS.gcnew_Point(x, y); + if (currentPoint != 0) OS.GCHandle_Free(currentPoint); + currentPoint = point; + +} + +/** + * Adds to the receiver the pattern of glyphs generated by drawing + * the given string using the given font starting at the point (x, y). + * + * @param string the text to use + * @param x the x coordinate of the starting point + * @param y the y coordinate of the starting point + * @param font the font to use + * + * @exception IllegalArgumentException <ul> + * <li>ERROR_NULL_ARGUMENT - if the font is null</li> + * <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 addString(String string, float x, float y, Font font) { + if (isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); + if (font == null) SWT.error(SWT.ERROR_NULL_ARGUMENT); + if (font.isDisposed()) SWT.error(SWT.ERROR_INVALID_ARGUMENT); + int length = string.length(); + char [] buffer = new char [length + 1]; + string.getChars (0, length, buffer, 0); + int str = OS.gcnew_String (buffer); + int culture = OS.CultureInfo_CurrentUICulture(); + int point = OS.gcnew_Point(x, y); + int brush = OS.Brushes_White(); + int text = OS.gcnew_FormattedText(str, culture, OS.FlowDirection_LeftToRight, font.handle, font.size, brush); + int geometry = OS.FormattedText_BuildGeometry(text, point); + OS.PathGeometry_AddGeometry(handle, geometry); + OS.GCHandle_Free(brush); + OS.GCHandle_Free(geometry); + OS.GCHandle_Free(culture); + OS.GCHandle_Free(str); + OS.GCHandle_Free(point); + OS.GCHandle_Free(text); + if (currentFigure != 0) OS.GCHandle_Free(currentFigure); + currentFigure = 0; + if (currentPoint != 0) OS.GCHandle_Free(currentPoint); + currentPoint = 0; +} + +/** + * Closes the current sub path by adding to the receiver a line + * from the current point of the path back to the starting point + * of the sub path. + * + * @exception SWTException <ul> + * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> + * </ul> + */ +public void close() { + if (isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); + if (currentFigure != 0) OS.PathFigure_IsClosed(currentFigure, true); + currentFigure = 0; +} + +/** + * Returns <code>true</code> if the specified point is contained by + * the receiver and false otherwise. + * <p> + * If outline is <code>true</code>, the point (x, y) checked for containment in + * the receiver's outline. If outline is <code>false</code>, the point is + * checked to see if it is contained within the bounds of the (closed) area + * covered by the receiver. + * + * @param x the x coordinate of the point to test for containment + * @param y the y coordinate of the point to test for containment + * @param gc the GC to use when testing for containment + * @param outline controls whether to check the outline or contained area of the path + * @return <code>true</code> if the path contains the point and <code>false</code> otherwise + * + * @exception IllegalArgumentException <ul> + * <li>ERROR_NULL_ARGUMENT - if the gc is null</li> + * <li>ERROR_INVALID_ARGUMENT - if the gc has been disposed</li> + * </ul> + * @exception SWTException <ul> + * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> + * </ul> + */ +public boolean contains(float x, float y, GC gc, boolean outline) { + if (isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); + if (gc == null) SWT.error(SWT.ERROR_NULL_ARGUMENT); + if (gc.isDisposed()) SWT.error(SWT.ERROR_INVALID_ARGUMENT); + gc.checkGC(GC.LINE_CAP | GC.LINE_JOIN | GC.LINE_STYLE | GC.LINE_WIDTH | GC.TRANSFORM); + boolean result; + int point = OS.gcnew_Point(x, y); + if (outline) { + result = OS.Geometry_StrokeContains(handle, gc.data.pen, point); + } else { + result = OS.Geometry_FillContains(handle, point); + } + OS.GCHandle_Free(point); + return result; +} + +/** + * Adds to the receiver a cubic bezier curve based on the parameters. + * + * @param cx1 the x coordinate of the first control point of the spline + * @param cy1 the y coordinate of the first control of the spline + * @param cx2 the x coordinate of the second control of the spline + * @param cy2 the y coordinate of the second control of the spline + * @param x the x coordinate of the end point of the spline + * @param y the y coordinate of the end point of the spline + * + * @exception SWTException <ul> + * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> + * </ul> + */ +public void cubicTo(float cx1, float cy1, float cx2, float cy2, float x, float y) { + if (isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); + int controlPoint1 = OS.gcnew_Point(cx1, cy1); + int controlPoint2 = OS.gcnew_Point(cx2, cy2); + int point = OS.gcnew_Point(x, y); + if (currentFigure == 0) newFigure(); + if (currentPoint != 0) OS.GCHandle_Free(currentPoint); + currentPoint = point; + int segment = OS.gcnew_BezierSegment(controlPoint1, controlPoint2, point, true); + int segments = OS.PathFigure_Segments(currentFigure); + OS.PathSegmentCollection_Add(segments, segment); + OS.GCHandle_Free(segments); + OS.GCHandle_Free(segment); + OS.GCHandle_Free(controlPoint1); + OS.GCHandle_Free(controlPoint2); +} + +/** + * Disposes of the operating system resources associated with + * the Path. Applications must dispose of all Paths that + * they allocate. + */ +public void dispose() { + if (handle == 0) return; + if (device.isDisposed()) return; + OS.GCHandle_Free(handle); + handle = 0; + if (device.tracking) device.dispose_Object(this); + device = null; +} + +/** + * Replaces the first four elements in the parameter with values that + * describe the smallest rectangle that will completely contain the + * receiver (i.e. the bounding box). + * + * @param bounds the array to hold the result + * + * @exception IllegalArgumentException <ul> + * <li>ERROR_NULL_ARGUMENT - if the parameter is null</li> + * <li>ERROR_INVALID_ARGUMENT - if the parameter is too small to hold the bounding box</li> + * </ul> + * @exception SWTException <ul> + * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> + * </ul> + */ +public void getBounds(float[] bounds) { + if (isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); + if (bounds == null) SWT.error(SWT.ERROR_NULL_ARGUMENT); + if (bounds.length < 4) SWT.error(SWT.ERROR_INVALID_ARGUMENT); + int rect = OS.PathGeometry_Bounds(handle); + bounds[0] = (float)OS.Rect_X(rect); + bounds[1] = (float)OS.Rect_Y(rect); + bounds[2] = (float)OS.Rect_Width(rect); + bounds[3] = (float)OS.Rect_Height(rect); + OS.GCHandle_Free(rect); +} + +/** + * Replaces the first two elements in the parameter with values that + * describe the current point of the path. + * + * @param point the array to hold the result + * + * @exception IllegalArgumentException <ul> + * <li>ERROR_NULL_ARGUMENT - if the parameter is null</li> + * <li>ERROR_INVALID_ARGUMENT - if the parameter is too small to hold the end point</li> + * </ul> + * @exception SWTException <ul> + * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> + * </ul> + */ +public void getCurrentPoint(float[] point) { + if (isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); + if (point == null) SWT.error(SWT.ERROR_NULL_ARGUMENT); + if (point.length < 2) SWT.error(SWT.ERROR_INVALID_ARGUMENT); + if (currentPoint != 0) { + point[0] = (float)OS.Point_X(currentPoint); + point[1] = (float)OS.Point_Y(currentPoint); + } else { + point[0] = point[1] = 0; + } +} + +/** + * Returns a device independent representation of the receiver. + * + * @return the PathData for the receiver + * + * @exception SWTException <ul> + * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> + * </ul> + * + * @see PathData + */ +public PathData getPathData() { + if (isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); + byte[] types = new byte[128]; + float[] points = new float[128 * 2]; + int pointsIndex = 0, typesIndex = 0; + int figures = OS.PathGeometry_Figures(handle); + int figureCount = OS.PathFigureCollection_Count(figures); + OS.GCHandle_Free(figures); + for (int i = 0; i < figureCount; i++) { + int figure = OS.PathGeometry_Figures(handle, i); + int segments = OS.PathFigure_Segments(figure); + int segmentCount = OS.PathSegmentCollection_Count(segments); + OS.GCHandle_Free(segments); + for (int j = 0; j < segmentCount; j++) { + int segment = OS.PathFigure_Segments(figure, j); + int type = OS.Object_GetType(segment); + //TODO - need get points out of every segment + //TODO - need to convert ArcSegment to beziers + + + OS.GCHandle_Free(type); + OS.GCHandle_Free(segment); + } + OS.GCHandle_Free(figure); + } + if (typesIndex != types.length) { + byte[] newTypes = new byte[typesIndex]; + System.arraycopy(types, 0, newTypes, 0, typesIndex); + types = newTypes; + } + if (pointsIndex != points.length) { + float[] newPoints = new float[pointsIndex]; + System.arraycopy(points, 0, newPoints, 0, pointsIndex); + points = newPoints; + } + PathData result = new PathData(); + result.types = types; + result.points = points; + return result; +} + +/** + * Adds to the receiver a line from the current point to + * the point specified by (x, y). + * + * @param x the x coordinate of the end of the line to add + * @param y the y coordinate of the end of the line to add + * + * @exception SWTException <ul> + * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> + * </ul> + */ +public void lineTo(float x, float y) { + if (isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); + int point = OS.gcnew_Point(x, y); + if (currentFigure == 0) newFigure(); + if (currentPoint != 0) OS.GCHandle_Free(currentPoint); + currentPoint = point; + int segment = OS.gcnew_LineSegment(point, true); + int segments = OS.PathFigure_Segments(currentFigure); + OS.PathSegmentCollection_Add(segments, segment); + OS.GCHandle_Free(segments); + OS.GCHandle_Free(segment); +} + +/** + * Returns <code>true</code> if the Path has been disposed, + * and <code>false</code> otherwise. + * <p> + * This method gets the dispose state for the Path. + * When a Path has been disposed, it is an error to + * invoke any other method using the Path. + * + * @return <code>true</code> when the Path is disposed, and <code>false</code> otherwise + */ +public boolean isDisposed() { + return handle == 0; +} + +/** + * Sets the current point of the receiver to the point + * specified by (x, y). Note that this starts a new + * sub path. + * + * @param x the x coordinate of the new end point + * @param y the y coordinate of the new end point + * + * @exception SWTException <ul> + * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> + * </ul> + */ +public void moveTo(float x, float y) { + if (isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); + int point = OS.gcnew_Point(x, y); + if (currentPoint != 0) OS.GCHandle_Free(currentPoint); + currentPoint = point; + if (currentFigure != 0) { + int segments = OS.PathFigure_Segments(currentFigure); + int count = OS.PathSegmentCollection_Count(segments); + OS.GCHandle_Free(segments); + if (count == 0) { + OS.PathFigure_StartPoint(currentFigure, point); + return; + } + } + if (currentFigure != 0) OS.GCHandle_Free(currentFigure); + newFigure(); +} + +void newFigure() { + currentFigure = OS.gcnew_PathFigure(); + if (currentPoint != 0) { + OS.PathFigure_StartPoint(currentFigure, currentPoint); + } + int figures = OS.PathGeometry_Figures(handle); + OS.PathFigureCollection_Add(figures, currentFigure); + OS.GCHandle_Free(figures); +} + +/** + * Adds to the receiver a quadratic curve based on the parameters. + * + * @param cx the x coordinate of the control point of the spline + * @param cy the y coordinate of the control point of the spline + * @param x the x coordinate of the end point of the spline + * @param y the y coordinate of the end point of the spline + * + * @exception SWTException <ul> + * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> + * </ul> + */ +public void quadTo(float cx, float cy, float x, float y) { + if (isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); + int controlPoint = OS.gcnew_Point(cx, cy); + int point = OS.gcnew_Point(x, y); + if (currentFigure == 0) newFigure(); + if (currentPoint != 0) OS.GCHandle_Free(currentPoint); + currentPoint = point; + int segment = OS.gcnew_QuadraticBezierSegment(controlPoint, point, true); + int segments = OS.PathFigure_Segments(currentFigure); + OS.PathSegmentCollection_Add(segments, segment); + OS.GCHandle_Free(segments); + OS.GCHandle_Free(segment); + OS.GCHandle_Free(controlPoint); +} + +/** + * 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 "Path {*DISPOSED*}"; + return "Path {" + handle + "}"; +} + +} diff --git a/bundles/org.eclipse.swt/Eclipse SWT/wpf/org/eclipse/swt/graphics/Pattern.java b/bundles/org.eclipse.swt/Eclipse SWT/wpf/org/eclipse/swt/graphics/Pattern.java new file mode 100644 index 0000000000..845d177724 --- /dev/null +++ b/bundles/org.eclipse.swt/Eclipse SWT/wpf/org/eclipse/swt/graphics/Pattern.java @@ -0,0 +1,195 @@ +/******************************************************************************* + * Copyright (c) 2000, 2006 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.swt.graphics; + +import org.eclipse.swt.*; +import org.eclipse.swt.internal.wpf.*; + +/** + * Instances of this class represent patterns to use while drawing. Patterns + * can be specified either as bitmaps or gradients. + * <p> + * Application code must explicitly invoke the <code>Pattern.dispose()</code> + * method to release the operating system resources managed by each instance + * when those instances are no longer required. + * </p> + * + * @since 3.1 + */ +public class Pattern extends Resource { + + /** + * the OS resource for the Pattern + * (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> + */ + public int handle; + +/** + * Constructs a new Pattern given an image. Drawing with the resulting + * pattern will cause the image to be tiled over the resulting area. + * + * @param device the device on which to allocate the pattern + * @param image the image that the pattern will draw + * + * @exception IllegalArgumentException <ul> + * <li>ERROR_NULL_ARGUMENT - if the device is null and there is no current device, or the image is null</li> + * <li>ERROR_INVALID_ARGUMENT - if the image has been disposed</li> + * </ul> + * @exception SWTError <ul> + * <li>ERROR_NO_HANDLES if a handle for the pattern could not be obtained/li> + * </ul> + * + * @see #dispose() + */ +public Pattern(Device device, Image image) { + if (device == null) device = Device.getDevice(); + if (device == null) SWT.error(SWT.ERROR_NULL_ARGUMENT); + if (image == null) SWT.error(SWT.ERROR_NULL_ARGUMENT); + if (image.isDisposed()) SWT.error(SWT.ERROR_INVALID_ARGUMENT); + this.device = device; + handle = OS.gcnew_ImageBrush(image.handle); + if (handle == 0) SWT.error(SWT.ERROR_NO_HANDLES); + OS.TileBrush_TileMode(handle, OS.TileMode_Tile); + OS.TileBrush_Stretch(handle, OS.Stretch_None); + OS.TileBrush_ViewportUnits(handle, OS.BrushMappingMode_Absolute); + OS.TileBrush_AlignmentX(handle, OS.AlignmentX_Left); + OS.TileBrush_AlignmentY(handle, OS.AlignmentY_Top); + int rect = OS.gcnew_Rect(0, 0, OS.BitmapSource_PixelWidth(image.handle), OS.BitmapSource_PixelHeight(image.handle)); + OS.TileBrush_Viewport(handle, rect); + OS.GCHandle_Free(rect); + if (device.tracking) device.new_Object(this); +} + +/** + * Constructs a new Pattern that represents a linear, two color + * gradient. Drawing with the pattern will cause the resulting area to be + * tiled with the gradient specified by the arguments. + * + * @param device the device on which to allocate the pattern + * @param x1 the x coordinate of the starting corner of the gradient + * @param y1 the y coordinate of the starting corner of the gradient + * @param x2 the x coordinate of the ending corner of the gradient + * @param y2 the y coordinate of the ending corner of the gradient + * @param color1 the starting color of the gradient + * @param color2 the ending color of the gradient + * + * @exception IllegalArgumentException <ul> + * <li>ERROR_NULL_ARGUMENT - if the device is null and there is no current device, + * or if either color1 or color2 is null</li> + * <li>ERROR_INVALID_ARGUMENT - if either color1 or color2 has been disposed</li> + * </ul> + * @exception SWTError <ul> + * <li>ERROR_NO_HANDLES if a handle for the pattern could not be obtained/li> + * </ul> + * + * @see #dispose() + */ +public Pattern(Device device, float x1, float y1, float x2, float y2, Color color1, Color color2) { + this(device, x1, y1, x2, y2, color1, 0xFF, color2, 0xFF); +} + +/** + * Constructs a new Pattern that represents a linear, two color + * gradient. Drawing with the pattern will cause the resulting area to be + * tiled with the gradient specified by the arguments. + * + * @param device the device on which to allocate the pattern + * @param x1 the x coordinate of the starting corner of the gradient + * @param y1 the y coordinate of the starting corner of the gradient + * @param x2 the x coordinate of the ending corner of the gradient + * @param y2 the y coordinate of the ending corner of the gradient + * @param color1 the starting color of the gradient + * @param alpha1 the starting alpha value of the gradient + * @param color2 the ending color of the gradient + * @param alpha2 the ending alpha value of the gradient + * + * @exception IllegalArgumentException <ul> + * <li>ERROR_NULL_ARGUMENT - if the device is null and there is no current device, + * or if either color1 or color2 is null</li> + * <li>ERROR_INVALID_ARGUMENT - if either color1 or color2 has been disposed</li> + * </ul> + * @exception SWTError <ul> + * <li>ERROR_NO_HANDLES if a handle for the pattern could not be obtained/li> + * </ul> + * + * @see #dispose() + * + * @since 3.2 + */ +public Pattern(Device device, float x1, float y1, float x2, float y2, Color color1, int alpha1, Color color2, int alpha2) { + if (device == null) device = Device.getDevice(); + if (device == null) SWT.error(SWT.ERROR_NULL_ARGUMENT); + if (color1 == null) SWT.error(SWT.ERROR_NULL_ARGUMENT); + if (color1.isDisposed()) SWT.error(SWT.ERROR_INVALID_ARGUMENT); + if (color2 == null) SWT.error(SWT.ERROR_NULL_ARGUMENT); + if (color2.isDisposed()) SWT.error(SWT.ERROR_INVALID_ARGUMENT); + this.device = device; + int startColor = OS.Color_FromArgb((byte)(alpha1 & 0xFF), OS.Color_R(color1.handle), OS.Color_G(color1.handle), OS.Color_B(color1.handle)); + int endColor = OS.Color_FromArgb((byte)(alpha2 & 0xFF), OS.Color_R(color2.handle), OS.Color_G(color2.handle), OS.Color_B(color2.handle)); + int startPoint = OS.gcnew_Point(x1, y1); + int endPoint = OS.gcnew_Point(x2, y2); + handle = OS.gcnew_LinearGradientBrush(startColor, endColor, startPoint, endPoint); + if (handle == 0) SWT.error(SWT.ERROR_NO_HANDLES); + OS.GradientBrush_MappingMode(handle, OS.BrushMappingMode_Absolute); + OS.GradientBrush_SpreadMethod(handle, OS.GradientSpreadMethod_Repeat); + OS.GCHandle_Free(startColor); + OS.GCHandle_Free(endColor); + OS.GCHandle_Free(startPoint); + OS.GCHandle_Free(endPoint); + if (device.tracking) device.new_Object(this); +} + +/** + * Disposes of the operating system resources associated with + * the Pattern. Applications must dispose of all Patterns that + * they allocate. + */ +public void dispose() { + if (handle == 0) return; + if (device.isDisposed()) return; + OS.GCHandle_Free(handle); + handle = 0; + if (device.tracking) device.dispose_Object(this); + device = null; +} + +/** + * Returns <code>true</code> if the Pattern has been disposed, + * and <code>false</code> otherwise. + * <p> + * This method gets the dispose state for the Pattern. + * When a Pattern has been disposed, it is an error to + * invoke any other method using the Pattern. + * + * @return <code>true</code> when the Pattern is disposed, and <code>false</code> otherwise + */ +public boolean isDisposed() { + return handle == 0; +} + +/** + * 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 "Pattern {*DISPOSED*}"; + return "Pattern {" + handle + "}"; +} + +} diff --git a/bundles/org.eclipse.swt/Eclipse SWT/wpf/org/eclipse/swt/graphics/Region.java b/bundles/org.eclipse.swt/Eclipse SWT/wpf/org/eclipse/swt/graphics/Region.java new file mode 100644 index 0000000000..c009aa81b8 --- /dev/null +++ b/bundles/org.eclipse.swt/Eclipse SWT/wpf/org/eclipse/swt/graphics/Region.java @@ -0,0 +1,720 @@ +/******************************************************************************* + * Copyright (c) 2000, 2005 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.internal.wpf.*; +import org.eclipse.swt.*; + +/** + * Instances of this class represent areas of an x-y coordinate + * system that are aggregates of the areas covered by a number + * of polygons. + * <p> + * Application code must explicitly invoke the <code>Region.dispose()</code> + * method to release the operating system resources managed by each instance + * when those instances are no longer required. + * </p> + */ + +public final class Region extends Resource { + + /** + * the OS resource for the region + * (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> + */ + public int handle; + +/** + * Constructs a new empty region. + * + * @exception SWTError <ul> + * <li>ERROR_NO_HANDLES if a handle could not be obtained for region creation</li> + * </ul> + */ +public Region () { + this(null); +} + +/** + * Constructs a new empty region. + * <p> + * You must dispose the region when it is no longer required. + * </p> + * + * @param device the device on which to allocate the region + * + * @exception IllegalArgumentException <ul> + * <li>ERROR_NULL_ARGUMENT - if device is null and there is no current device</li> + * </ul> + * @exception SWTError <ul> + * <li>ERROR_NO_HANDLES if a handle could not be obtained for region creation</li> + * </ul> + * + * @see #dispose + * + * @since 3.0 + */ +public Region (Device device) { + if (device == null) device = Device.getDevice(); + if (device == null) SWT.error(SWT.ERROR_NULL_ARGUMENT); + this.device = device; + handle = OS.gcnew_GeometryGroup(); + if (handle == 0) SWT.error(SWT.ERROR_NO_HANDLES); + if (device.tracking) device.new_Object(this); +} + +/** + * Constructs a new region given a handle to the operating + * system resources that it should represent. + * + * @param handle the handle for the result + */ +Region(Device device, int handle) { + this.device = device; + this.handle = handle; +} + +/** + * Adds the given polygon to the collection of polygons + * the receiver maintains to describe its area. + * + * @param pointArray points that describe the polygon to merge with the receiver + * + * @exception IllegalArgumentException <ul> + * <li>ERROR_NULL_ARGUMENT - if the argument is null</li> + * </ul> + * @exception SWTException <ul> + * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> + * </ul> + * + * @since 3.0 +* + */ +public void add (int[] pointArray) { + if (isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); + if (pointArray == null) SWT.error(SWT.ERROR_NULL_ARGUMENT); + combine(pointArray, OS.GeometryCombineMode_Union); +} + + + +/** + * Adds the given rectangle to the collection of polygons + * the receiver maintains to describe its area. + * + * @param rect the rectangle to merge with the receiver + * + * @exception IllegalArgumentException <ul> + * <li>ERROR_NULL_ARGUMENT - if the argument is null</li> + * <li>ERROR_INVALID_ARGUMENT - if the rectangle's width or height is negative</li> + * </ul> + * @exception SWTException <ul> + * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> + * </ul> + */ +public void add (Rectangle rect) { + if (isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); + if (rect == null) SWT.error(SWT.ERROR_NULL_ARGUMENT); + add (rect.x, rect.y, rect.width, rect.height); +} + +/** + * Adds the given rectangle to the collection of polygons + * the receiver maintains to describe its area. + * + * @param x the x coordinate of the rectangle + * @param y the y coordinate of the rectangle + * @param width the width coordinate of the rectangle + * @param height the height coordinate of the rectangle + * + * @exception IllegalArgumentException <ul> + * <li>ERROR_INVALID_ARGUMENT - if the rectangle's width or height is negative</li> + * </ul> + * @exception SWTException <ul> + * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> + * </ul> + * + * @since 3.1 + */ +public void add (int x, int y, int width, int height) { + if (isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); + if (width < 0 || height < 0) SWT.error(SWT.ERROR_INVALID_ARGUMENT); + int rect = OS.gcnew_Rect(x, y, width, height); + int geometry1 = OS.gcnew_RectangleGeometry(rect); + int geometries = OS.GeometryGroup_Children(handle); + if (OS.GeometryCollection_Count(geometries) == 0) { + OS.GeometryCollection_Add(geometries, geometry1); + } else { + int geometry2 = OS.GeometryGroup_Children(handle, 0); + int geometry3 = OS.gcnew_CombinedGeometry(OS.GeometryCombineMode_Union, geometry1, geometry2); + OS.GeometryCollection_Remove(geometries, geometry2); + OS.GeometryCollection_Add(geometries, geometry3); + OS.GCHandle_Free(geometry2); + OS.GCHandle_Free(geometry3); + } + OS.GCHandle_Free(rect); + OS.GCHandle_Free(geometry1); + OS.GCHandle_Free(geometries); +} + +/** + * Adds all of the polygons which make up the area covered + * by the argument to the collection of polygons the receiver + * maintains to describe its area. + * + * @param region the region to merge + * + * @exception IllegalArgumentException <ul> + * <li>ERROR_NULL_ARGUMENT - if the argument is null</li> + * <li>ERROR_INVALID_ARGUMENT - if the argument has been disposed</li> + * </ul> + * @exception SWTException <ul> + * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> + * </ul> + */ +public void add (Region region) { + if (isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); + if (region == null) SWT.error(SWT.ERROR_NULL_ARGUMENT); + if (region.isDisposed()) SWT.error(SWT.ERROR_INVALID_ARGUMENT); + int geometries = OS.GeometryGroup_Children(handle); + if (OS.GeometryCollection_Count(geometries) == 0) { + OS.GeometryCollection_Add(geometries, region.handle); + } else { + int geometry2 = OS.GeometryGroup_Children(handle, 0); + int geometry3 = OS.gcnew_CombinedGeometry(OS.GeometryCombineMode_Union, region.handle, geometry2); + OS.GeometryCollection_Remove(geometries, geometry2); + OS.GeometryCollection_Add(geometries, geometry3); + OS.GCHandle_Free(geometry2); + OS.GCHandle_Free(geometry3); + } + OS.GCHandle_Free(geometries); +} + + +void combine (int[] pointArray, int mode) { + if (pointArray.length < 4) return; + int list = OS.gcnew_PointCollection(pointArray.length / 2); + for (int i = 0; i < pointArray.length; i += 2) { + int point = OS.gcnew_Point(pointArray[i], pointArray[i + 1]); + OS.PointCollection_Add(list, point); + OS.GCHandle_Free(point); + } + int poly = OS.gcnew_PolyLineSegment(list, true); + OS.GCHandle_Free(list); + int figure = OS.gcnew_PathFigure(); + int startPoint = OS.gcnew_Point(pointArray[0], pointArray[1]); + OS.PathFigure_StartPoint(figure, startPoint); + OS.PathFigure_IsClosed(figure, true); + int segments = OS.PathFigure_Segments(figure); + OS.PathSegmentCollection_Add(segments, poly); + int path = OS.gcnew_PathGeometry(); + int figures = OS.PathGeometry_Figures(path); + OS.PathFigureCollection_Add(figures, figure); + int geometries = OS.GeometryGroup_Children(handle); + if (OS.GeometryCollection_Count(geometries) == 0) { + if (mode == OS.GeometryCombineMode_Union) OS.GeometryCollection_Add(geometries, path); + } else { + int geometry2 = OS.GeometryGroup_Children(handle, 0); + int geometry3 = OS.gcnew_CombinedGeometry(mode, geometry2, path); + OS.GeometryCollection_Remove(geometries, geometry2); + OS.GeometryCollection_Add(geometries, geometry3); + OS.GCHandle_Free(geometry2); + OS.GCHandle_Free(geometry3); + } + OS.GCHandle_Free(geometries); + OS.GCHandle_Free(figures); + OS.GCHandle_Free(path); + OS.GCHandle_Free(segments); + OS.GCHandle_Free(figure); + OS.GCHandle_Free(startPoint); + OS.GCHandle_Free(poly); +} + +/** + * Returns <code>true</code> if the point specified by the + * arguments is inside the area specified by the receiver, + * and <code>false</code> otherwise. + * + * @param x the x coordinate of the point to test for containment + * @param y the y coordinate of the point to test for containment + * @return <code>true</code> if the region contains the point and <code>false</code> otherwise + * + * @exception SWTException <ul> + * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> + * </ul> + */ +public boolean contains (int x, int y) { + if (isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); + int point = OS.gcnew_Point(x, y); + boolean result = OS.Geometry_FillContains(handle, point); + OS.GCHandle_Free(point); + return result; +} + +/** + * Returns <code>true</code> if the given point is inside the + * area specified by the receiver, and <code>false</code> + * otherwise. + * + * @param pt the point to test for containment + * @return <code>true</code> if the region contains the point and <code>false</code> otherwise + * + * @exception IllegalArgumentException <ul> + * <li>ERROR_NULL_ARGUMENT - if the argument is null</li> + * </ul> + * @exception SWTException <ul> + * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> + * </ul> + */ +public boolean contains (Point pt) { + if (isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); + if (pt == null) SWT.error(SWT.ERROR_NULL_ARGUMENT); + return contains(pt.x, pt.y); +} + +/** + * Disposes of the operating system resources associated with + * the region. Applications must dispose of all regions which + * they allocate. + */ +public void dispose () { + if (handle == 0) return; + if (device.isDisposed()) return; + OS.GCHandle_Free(handle); + handle = 0; + if (device.tracking) device.dispose_Object(this); + device = null; +} + +/** + * 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 (this == object) return true; + if (!(object instanceof Region)) return false; + Region rgn = (Region)object; + return handle == rgn.handle; +} + +/** + * Returns a rectangle which represents the rectangular + * union of the collection of polygons the receiver + * maintains to describe its area. + * + * @return a bounding rectangle for the region + * + * @exception SWTException <ul> + * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> + * </ul> + * + * @see Rectangle#union + */ +public Rectangle getBounds() { + if (isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); + if (OS.Geometry_IsEmpty(handle)) return new Rectangle(0, 0, 0, 0); + int rect = OS.Geometry_Bounds(handle); + Rectangle result = new Rectangle((int)OS.Rect_X(rect), (int)OS.Rect_Y(rect), (int)OS.Rect_Width(rect), (int)OS.Rect_Height(rect)); + OS.GCHandle_Free(rect); + return result; +} + +/** + * 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 + * + * @see #equals + */ +public int hashCode () { + return handle; +} + +/** + * Intersects the given rectangle to the collection of polygons + * the receiver maintains to describe its area. + * + * @param rect the rectangle to intersect with the receiver + * + * @exception IllegalArgumentException <ul> + * <li>ERROR_NULL_ARGUMENT - if the argument is null</li> + * <li>ERROR_INVALID_ARGUMENT - if the rectangle's width or height is negative</li> + * </ul> + * @exception SWTException <ul> + * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> + * </ul> + * + * @since 3.0 + */ +public void intersect (Rectangle rect) { + if (isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); + if (rect == null) SWT.error(SWT.ERROR_NULL_ARGUMENT); + intersect (rect.x, rect.y, rect.width, rect.height); +} + +/** + * Intersects the given rectangle to the collection of polygons + * the receiver maintains to describe its area. + * + * @param x the x coordinate of the rectangle + * @param y the y coordinate of the rectangle + * @param width the width coordinate of the rectangle + * @param height the height coordinate of the rectangle + * + * @exception IllegalArgumentException <ul> + * <li>ERROR_INVALID_ARGUMENT - if the rectangle's width or height is negative</li> + * </ul> + * @exception SWTException <ul> + * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> + * </ul> + * + * @since 3.1 + */ +public void intersect (int x, int y, int width, int height) { + if (isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); + if (width < 0 || height < 0) SWT.error(SWT.ERROR_INVALID_ARGUMENT); + int rect = OS.gcnew_Rect(x, y, width, height); + int geometry1 = OS.gcnew_RectangleGeometry(rect); + int geometries = OS.GeometryGroup_Children(handle); + if (OS.GeometryCollection_Count(geometries) != 0) { + int geometry2 = OS.GeometryGroup_Children(handle, 0); + int geometry3 = OS.gcnew_CombinedGeometry(OS.GeometryCombineMode_Intersect, geometry1, geometry2); + OS.GeometryCollection_Remove(geometries, geometry2); + OS.GeometryCollection_Add(geometries, geometry3); + OS.GCHandle_Free(geometry2); + OS.GCHandle_Free(geometry3); + } + OS.GCHandle_Free(rect); + OS.GCHandle_Free(geometry1); + OS.GCHandle_Free(geometries); +} + +/** + * Intersects all of the polygons which make up the area covered + * by the argument to the collection of polygons the receiver + * maintains to describe its area. + * + * @param region the region to intersect + * + * @exception IllegalArgumentException <ul> + * <li>ERROR_NULL_ARGUMENT - if the argument is null</li> + * <li>ERROR_INVALID_ARGUMENT - if the argument has been disposed</li> + * </ul> + * @exception SWTException <ul> + * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> + * </ul> + * + * @since 3.0 + */ +public void intersect (Region region) { + if (isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); + if (region == null) SWT.error(SWT.ERROR_NULL_ARGUMENT); + if (region.isDisposed()) SWT.error(SWT.ERROR_INVALID_ARGUMENT); + int geometries = OS.GeometryGroup_Children(handle); + if (OS.GeometryCollection_Count(geometries) != 0) { + int geometry2 = OS.GeometryGroup_Children(handle, 0); + int geometry3 = OS.gcnew_CombinedGeometry(OS.GeometryCombineMode_Intersect, region.handle, geometry2); + OS.GeometryCollection_Remove(geometries, geometry2); + OS.GeometryCollection_Add(geometries, geometry3); + OS.GCHandle_Free(geometry2); + OS.GCHandle_Free(geometry3); + } + OS.GCHandle_Free(geometries); +} + +/** + * Returns <code>true</code> if the rectangle described by the + * arguments intersects with any of the polygons the receiver + * maintains to describe its area, and <code>false</code> otherwise. + * + * @param x the x coordinate of the origin of the rectangle + * @param y the y coordinate of the origin of the rectangle + * @param width the width of the rectangle + * @param height the height of the rectangle + * @return <code>true</code> if the rectangle intersects with the receiver, and <code>false</code> otherwise + * + * @exception SWTException <ul> + * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> + * </ul> + * + * @see Rectangle#intersects(Rectangle) + */ +public boolean intersects (int x, int y, int width, int height) { + if (isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); + int rect = OS.gcnew_Rect(x, y, width, height); + int geometry = OS.gcnew_RectangleGeometry(rect); + int result = OS.Geometry_FillContainsWithDetail(handle, geometry); + OS.GCHandle_Free(geometry); + OS.GCHandle_Free(rect); + return result != OS.IntersectionDetail_Empty; +} + +/** + * Returns <code>true</code> if the given rectangle intersects + * with any of the polygons the receiver maintains to describe + * its area and <code>false</code> otherwise. + * + * @param rect the rectangle to test for intersection + * @return <code>true</code> if the rectangle intersects with the receiver, and <code>false</code> otherwise + * + * @exception IllegalArgumentException <ul> + * <li>ERROR_NULL_ARGUMENT - if the argument is null</li> + * </ul> + * @exception SWTException <ul> + * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> + * </ul> + * + * @see Rectangle#intersects(Rectangle) + */ +public boolean intersects (Rectangle rect) { + if (isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); + if (rect == null) SWT.error(SWT.ERROR_NULL_ARGUMENT); + return intersects(rect.x, rect.y, rect.width, rect.height); +} + +/** + * Returns <code>true</code> if the region has been disposed, + * and <code>false</code> otherwise. + * <p> + * This method gets the dispose state for the region. + * When a region has been disposed, it is an error to + * invoke any other method using the region. + * + * @return <code>true</code> when the region is disposed, and <code>false</code> otherwise + */ +public boolean isDisposed() { + return handle == 0; +} + +/** + * Returns <code>true</code> if the receiver does not cover any + * area in the (x, y) coordinate plane, and <code>false</code> if + * the receiver does cover some area in the plane. + * + * @return <code>true</code> if the receiver is empty, and <code>false</code> otherwise + * + * @exception SWTException <ul> + * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> + * </ul> + */ +public boolean isEmpty () { + if (isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); + return OS.Geometry_IsEmpty(handle); +} + +/** + * Subtracts the given polygon from the collection of polygons + * the receiver maintains to describe its area. + * + * @param pointArray points that describe the polygon to merge with the receiver + * + * @exception IllegalArgumentException <ul> + * <li>ERROR_NULL_ARGUMENT - if the argument is null</li> + * </ul> + * @exception SWTException <ul> + * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> + * </ul> + * + * @since 3.0 + */ +public void subtract (int[] pointArray) { + if (isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); + if (pointArray == null) SWT.error(SWT.ERROR_NULL_ARGUMENT); + combine(pointArray, OS.GeometryCombineMode_Exclude); +} + +/** + * Subtracts the given rectangle from the collection of polygons + * the receiver maintains to describe its area. + * + * @param rect the rectangle to subtract from the receiver + * + * @exception IllegalArgumentException <ul> + * <li>ERROR_NULL_ARGUMENT - if the argument is null</li> + * <li>ERROR_INVALID_ARGUMENT - if the rectangle's width or height is negative</li> + * </ul> + * @exception SWTException <ul> + * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> + * </ul> + * + * @since 3.0 + */ +public void subtract (Rectangle rect) { + if (isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); + if (rect == null) SWT.error(SWT.ERROR_NULL_ARGUMENT); + subtract (rect.x, rect.y, rect.width, rect.height); +} + +/** + * Subtracts the given rectangle from the collection of polygons + * the receiver maintains to describe its area. + * + * @param x the x coordinate of the rectangle + * @param y the y coordinate of the rectangle + * @param width the width coordinate of the rectangle + * @param height the height coordinate of the rectangle + * + * @exception IllegalArgumentException <ul> + * <li>ERROR_INVALID_ARGUMENT - if the rectangle's width or height is negative</li> + * </ul> + * @exception SWTException <ul> + * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> + * </ul> + * + * @since 3.1 + */ +public void subtract (int x, int y, int width, int height) { + if (isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); + if (width < 0 || height < 0) SWT.error(SWT.ERROR_INVALID_ARGUMENT); + int rect = OS.gcnew_Rect(x, y, width, height); + int geometry1 = OS.gcnew_RectangleGeometry(rect); + int geometries = OS.GeometryGroup_Children(handle); + if (OS.GeometryCollection_Count(geometries) != 0) { + int geometry2 = OS.GeometryGroup_Children(handle, 0); + int geometry3 = OS.gcnew_CombinedGeometry(OS.GeometryCombineMode_Exclude, geometry2, geometry1); + OS.GeometryCollection_Remove(geometries, geometry2); + OS.GeometryCollection_Add(geometries, geometry3); + OS.GCHandle_Free(geometry2); + OS.GCHandle_Free(geometry3); + } + OS.GCHandle_Free(rect); + OS.GCHandle_Free(geometry1); + OS.GCHandle_Free(geometries); +} + +/** + * Subtracts all of the polygons which make up the area covered + * by the argument from the collection of polygons the receiver + * maintains to describe its area. + * + * @param region the region to subtract + * + * @exception IllegalArgumentException <ul> + * <li>ERROR_NULL_ARGUMENT - if the argument is null</li> + * <li>ERROR_INVALID_ARGUMENT - if the argument has been disposed</li> + * </ul> + * @exception SWTException <ul> + * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> + * </ul> + * + * @since 3.0 + */ +public void subtract (Region region) { + if (isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); + if (region == null) SWT.error(SWT.ERROR_NULL_ARGUMENT); + if (region.isDisposed()) SWT.error(SWT.ERROR_INVALID_ARGUMENT); + int geometries = OS.GeometryGroup_Children(handle); + if (OS.GeometryCollection_Count(geometries) != 0) { + int geometry2 = OS.GeometryGroup_Children(handle, 0); + int geometry3 = OS.gcnew_CombinedGeometry(OS.GeometryCombineMode_Exclude, geometry2, region.handle); + OS.GeometryCollection_Remove(geometries, geometry2); + OS.GeometryCollection_Add(geometries, geometry3); + OS.GCHandle_Free(geometry2); + OS.GCHandle_Free(geometry3); + } + OS.GCHandle_Free(geometries); +} + +/** + * Translate all of the polygons the receiver maintains to describe + * its area by the specified point. + * + * @param x the x coordinate of the point to translate + * @param y the y coordinate of the point to translate + * + * @exception SWTException <ul> + * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> + * </ul> + * + * @since 3.1 + */ +public void translate (int x, int y) { + if (isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); + int transform1 = OS.Geometry_Transform(handle); + int transform2 = OS.gcnew_TranslateTransform(x, y); + int transform = OS.gcnew_TransformGroup(); + int transforms = OS.TransformGroup_Children(transform); + OS.TransformCollection_Add(transforms, transform1); + OS.TransformCollection_Add(transforms, transform2); + OS.Geometry_Transform(handle, transform); + OS.GCHandle_Free(transform1); + OS.GCHandle_Free(transform2); + OS.GCHandle_Free(transform); + OS.GCHandle_Free(transforms); +} + +/** + * Translate all of the polygons the receiver maintains to describe + * its area by the specified point. + * + * @param pt the point to translate + * + * @exception IllegalArgumentException <ul> + * <li>ERROR_NULL_ARGUMENT - if the argument is null</li> + * </ul> + * @exception SWTException <ul> + * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> + * </ul> + * + * @since 3.1 + */ +public void translate (Point pt) { + if (isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); + if (pt == null) SWT.error(SWT.ERROR_NULL_ARGUMENT); + translate (pt.x, pt.y); +} + +/** + * 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 "Region {*DISPOSED*}"; + return "Region {" + handle + "}"; +} + +/** + * Invokes platform specific functionality to allocate a new region. + * <p> + * <b>IMPORTANT:</b> This method is <em>not</em> part of the public + * API for <code>Region</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 device the device on which to allocate the region + * @param handle the handle for the region + * @return a new region object containing the specified device and handle + */ +public static Region wpf_new(Device device, int handle) { + return new Region(device, handle); +} + +} diff --git a/bundles/org.eclipse.swt/Eclipse SWT/wpf/org/eclipse/swt/graphics/TextLayout.java b/bundles/org.eclipse.swt/Eclipse SWT/wpf/org/eclipse/swt/graphics/TextLayout.java new file mode 100644 index 0000000000..68c313812b --- /dev/null +++ b/bundles/org.eclipse.swt/Eclipse SWT/wpf/org/eclipse/swt/graphics/TextLayout.java @@ -0,0 +1,1658 @@ +/******************************************************************************* + * Copyright (c) 2000, 2006 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.swt.graphics; + +import org.eclipse.swt.internal.wpf.*; +import org.eclipse.swt.*; + +/** + * <code>TextLayout</code> is a graphic object that represents + * styled text. + * <p> + * Instances of this class provide support for drawing, cursor + * navigation, hit testing, text wrapping, alignment, tab expansion + * line breaking, etc. These are aspects required for rendering internationalized text. + * </p><p> + * Application code must explicitly invoke the <code>TextLayout#dispose()</code> + * method to release the operating system resources managed by each instance + * when those instances are no longer required. + * </p> + * + * @since 3.0 + */ +public final class TextLayout extends Resource { + Font font; + String text, segmentsText; + int lineSpacing; + int ascent, descent; + int alignment; + int wrapWidth; + int orientation; + int indent; + boolean justify; + int[] tabs; + int[] segments; + StyleItem[] styles; + + int string, defaultTextProperties; + int[] runs; + int[] lines; + + static final char LTR_MARK = '\u200E', RTL_MARK = '\u200F'; + static final int TAB_COUNT = 32; + +class StyleItem { + TextStyle style; + int start, length; + int textProperties; + + void free() { + if (textProperties != 0) OS.GCHandle_Free(textProperties); + textProperties = 0; + } + public String toString () { + return "StyleItem {" + start + ", " + style + "}"; + } +} + +/** + * Constructs a new instance of this class on the given device. + * <p> + * You must dispose the text layout when it is no longer required. + * </p> + * + * @param device the device on which to allocate the text layout + * + * @exception IllegalArgumentException <ul> + * <li>ERROR_NULL_ARGUMENT - if device is null and there is no current device</li> + * </ul> + * + * @see #dispose() + */ +public TextLayout (Device device) { + if (device == null) device = Device.getDevice(); + if (device == null) SWT.error(SWT.ERROR_NULL_ARGUMENT); + this.device = device; + wrapWidth = ascent = descent = -1; + lineSpacing = 0; + orientation = SWT.LEFT_TO_RIGHT; + styles = new StyleItem[2]; + styles[0] = new StyleItem(); + styles[1] = new StyleItem(); + text = ""; //$NON-NLS-1$ + if (device.tracking) device.new_Object(this); +} + +void checkLayout () { + if (isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); +} + +/* +* Compute the runs: itemize, shape, place, and reorder the runs. +* Break paragraphs into lines, wraps the text, and initialize caches. +*/ +void computeRuns () { + if (lines != null) return; + + int jniRef = OS.NewGlobalRef(this); + int textSource = OS.gcnew_SWTTextSource(jniRef); + int formatter = OS.TextFormatter_Create(); + Font font = this.font != null ? this.font : device.systemFont; + segmentsText = getSegmentsText(); + int length = segmentsText.length(); + char [] buffer = new char [length + 1]; + segmentsText.getChars (0, length, buffer, 0); + string = OS.gcnew_String(buffer); + int culture = OS.CultureInfo_CurrentUICulture(); + defaultTextProperties = OS.gcnew_SWTTextRunProperties(font.handle, font.size, font.size, 0, 0, 0, OS.BaselineAlignment_Baseline, culture); + for (int i = 0; i < styles.length; i++) { + StyleItem run = styles[i]; + TextStyle style = run.style; + if (style != null) { + Font styleFont = style.font != null ? style.font : font; + int fg = 0; + if (style.foreground != null) { + fg = OS.gcnew_SolidColorBrush(style.foreground.handle); + } + int bg = 0; + if (style.background != null) { + bg = OS.gcnew_SolidColorBrush(style.background.handle); + } + int decorations = 0; + if (style.strikeout || style.underline) { + decorations = OS.gcnew_TextDecorationCollection(2); + if (style.strikeout) { + int strikeout = OS.TextDecorations_Strikethrough(); + OS.TextDecorationCollection_Add(decorations, strikeout); + OS.GCHandle_Free(strikeout); + } + if (style.underline) { + int underline = OS.TextDecorations_Underline(); + OS.TextDecorationCollection_Add(decorations, underline); + OS.GCHandle_Free(underline); + } + } + run.textProperties = OS.gcnew_SWTTextRunProperties(styleFont.handle, styleFont.size, styleFont.size, decorations, fg, bg, OS.BaselineAlignment_Baseline, culture); + if (fg != 0) OS.GCHandle_Free(fg); + if (bg != 0) OS.GCHandle_Free(bg); + if (decorations != 0) OS.GCHandle_Free(decorations); + } + } + int textAlignment = OS.TextAlignment_Left; + if (justify) { + textAlignment = OS.TextAlignment_Justify; + } else { + switch (alignment) { + case SWT.CENTER: textAlignment = OS.TextAlignment_Center; break; + case SWT.RIGHT: textAlignment = OS.TextAlignment_Right; break; + } + } + int flowDirection = (orientation & SWT.RIGHT_TO_LEFT) != 0 ? OS.FlowDirection_RightToLeft : OS.FlowDirection_LeftToRight; + int textWrapping = wrapWidth != -1 ? OS.TextWrapping_Wrap : OS.TextWrapping_NoWrap; + int tabCollection = 0; + if (tabs != null) { + int position = 0; + int tabLength = Math.max(tabs.length, TAB_COUNT), i; + tabCollection = OS.gcnew_TextTabPropertiesCollection(tabLength); + for (i = 0; i < tabs.length; i++) { + position = tabs[i]; + int tab = OS.gcnew_TextTabProperties(OS.TextTabAlignment_Left, position, 0, 0); + OS.TextTabPropertiesCollection_Add(tabCollection, tab); + OS.GCHandle_Free(tab); + } + int width = tabs[tabs.length - 1]; + if (tabs.length > 1) width -= tabs[tabs.length - 2]; + if (width > 0) { + for (; i < length; i++) { + position += width; + int tab = OS.gcnew_TextTabProperties(OS.TextTabAlignment_Left, position, 0, 0); + OS.TextTabPropertiesCollection_Add(tabCollection, tab); + OS.GCHandle_Free(tab); + } + } + } + int paragraphProperties = OS.gcnew_SWTTextParagraphProperties(flowDirection, textAlignment, false, defaultTextProperties, textWrapping, 0, 0, tabCollection); + int firstParagraphProperties = OS.gcnew_SWTTextParagraphProperties(flowDirection, textAlignment, true, defaultTextProperties, textWrapping, 0, indent, tabCollection); + int offset = 0; + int index = 0; + lines = new int[4]; + int lineBreak = 0; + while (offset < length || offset == 0) { + char ch; + boolean firstLine = offset == 0 || (ch = segmentsText.charAt(offset - 1)) == '\r' || ch == '\n'; + int paragraphProps = firstLine ? firstParagraphProperties : paragraphProperties; + int textLine = OS.TextFormatter_FormatLine(formatter, textSource, offset, wrapWidth != -1 ? wrapWidth : 0, paragraphProps, lineBreak); + offset += OS.TextLine_Length(textLine); + lineBreak = OS.TextLine_GetTextLineBreak(textLine); + if (index == lines.length) { + int[] tmpLines = new int[index + 4]; + System.arraycopy(lines, 0, tmpLines, 0, index); + lines = tmpLines; + } + lines[index++] = textLine; + } + if (index != lines.length) { + int[] tmpLines = new int[index]; + System.arraycopy(lines, 0, tmpLines, 0, index); + lines = tmpLines; + } + if (tabCollection != 0) OS.GCHandle_Free(tabCollection); + OS.GCHandle_Free(paragraphProperties); + OS.GCHandle_Free(firstParagraphProperties); + OS.GCHandle_Free(culture); + OS.GCHandle_Free(formatter); + OS.GCHandle_Free(textSource); + OS.DeleteGlobalRef(jniRef); +} + +/** + * Disposes of the operating system resources associated with + * the text layout. Applications must dispose of all allocated text layouts. + */ +public void dispose () { + if (device == null) return; + freeRuns(); + font = null; + text = null; + segmentsText = null; + tabs = null; + styles = null; +// lineOffset = null; +// lineY = null; +// lineWidth = null; + if (device.tracking) device.dispose_Object(this); + device = null; +} + +/** + * Draws the receiver's text using the specified GC at the specified + * point. + * + * @param gc the GC to draw + * @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 SWTException <ul> + * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> + * </ul> + * @exception IllegalArgumentException <ul> + * <li>ERROR_NULL_ARGUMENT - if the gc is null</li> + * </ul> + */ +public void draw (GC gc, int x, int y) { + draw(gc, x, y, -1, -1, null, null); +} + +/** + * Draws the receiver's text using the specified GC at the specified + * point. + * + * @param gc the GC to draw + * @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 selectionStart the offset where the selections starts, or -1 indicating no selection + * @param selectionEnd the offset where the selections ends, or -1 indicating no selection + * @param selectionForeground selection foreground, or NULL to use the system default color + * @param selectionBackground selection background, or NULL to use the system default color + * + * @exception SWTException <ul> + * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> + * </ul> + * @exception IllegalArgumentException <ul> + * <li>ERROR_NULL_ARGUMENT - if the gc is null</li> + * </ul> + */ +public void draw (GC gc, int x, int y, int selectionStart, int selectionEnd, Color selectionForeground, Color selectionBackground) { + checkLayout(); + computeRuns(); + if (gc == null) SWT.error(SWT.ERROR_NULL_ARGUMENT); + if (gc.isDisposed()) SWT.error(SWT.ERROR_INVALID_ARGUMENT); + if (selectionForeground != null && selectionForeground.isDisposed()) SWT.error(SWT.ERROR_INVALID_ARGUMENT); + if (selectionBackground != null && selectionBackground.isDisposed()) SWT.error(SWT.ERROR_INVALID_ARGUMENT); + int length = text.length(); + if (length == 0) return; + gc.checkGC(GC.FOREGROUND); + int fg = OS.Pen_Brush(gc.data.pen); + OS.SWTTextRunProperties_ForegroundBrush(defaultTextProperties, fg); + for (int i = 0; i < styles.length; i++) { + StyleItem run = styles[i]; + if (run.style != null && run.style.foreground == null) { + OS.SWTTextRunProperties_ForegroundBrush(run.textProperties, fg); + } + } + int drawingContext = gc.handle; + boolean hasSelection = selectionStart <= selectionEnd && selectionStart != -1 && selectionEnd != -1; + int selBrush = 0; + if (hasSelection) { + selectionStart = Math.min(Math.max(0, selectionStart), length - 1); + selectionEnd = Math.min(Math.max(0, selectionEnd), length - 1); + selectionStart = translateOffset(selectionStart); + selectionEnd = translateOffset(selectionEnd); + if (selectionBackground != null) { + selBrush = OS.gcnew_SolidColorBrush(selectionBackground.handle); + } else { + selBrush = OS.Brushes_LightSkyBlue(); + } + } + int lineStart = 0, lineEnd = 0; + double drawY = y; + for (int i = 0; i < lines.length; i++) { + int line = lines[i]; + if (line == 0) break; + lineStart = lineEnd; + lineEnd = lineStart + OS.TextLine_Length(line); + double nextDrawY; + int lineHeight = (int)OS.TextLine_Height(line); + if (ascent != -1 && descent != -1) { + lineHeight = Math.max(lineHeight, ascent + descent); + nextDrawY = drawY + lineHeight + lineSpacing; + int baseline = (int)OS.TextLine_Baseline(line); + if (ascent > baseline) drawY += ascent - baseline; + } else { + nextDrawY = drawY + lineHeight + lineSpacing; + } + + //draw line selection + boolean fullSelection = selectionStart <= lineStart && selectionEnd >= lineEnd; + boolean partialSelection = !(selectionStart > lineEnd || lineStart > selectionEnd); + if (hasSelection && (fullSelection || partialSelection)) { + int selLineStart = Math.max (lineStart, selectionStart); + int selLineEnd = Math.min (lineEnd, selectionEnd); + int rects = OS.TextLine_GetTextBounds(line, selLineStart, selLineEnd - selLineStart + 1); + if (rects != 0) { + int enumerator = OS.TextBoundsCollection_GetEnumerator(rects); + while (OS.IEnumerator_MoveNext(enumerator)) { + int bounds = OS.TextBoundsCollection_Current(enumerator); + int textRect = OS.TextBounds_Rectangle(bounds); + OS.Rect_Y(textRect, OS.Rect_Y(textRect) + drawY); + OS.DrawingContext_DrawRectangle(drawingContext, selBrush, 0, textRect); + OS.GCHandle_Free(textRect); + OS.GCHandle_Free(bounds); + } + OS.GCHandle_Free(enumerator); + } + OS.GCHandle_Free(rects); + } + + //draw line text + int point = OS.gcnew_Point(x, drawY); + OS.TextLine_Draw(line, drawingContext, point, 0); + OS.GCHandle_Free(point); + + drawY = nextDrawY; + } + if (selBrush != 0) OS.GCHandle_Free(selBrush); + OS.GCHandle_Free(fg); +} + +void freeRuns () { + if (lines == null) return; + for (int i = 0; i < lines.length; i++) { + if (lines[i] != 0) { + OS.GCHandle_Free(lines[i]); + } + } + lines = null; + if (runs != null) { + for (int i = 0; i < runs.length; i++) { + if (runs[i] == 0) break; + OS.GCHandle_Free(runs[i]); + } + runs = null; + } + for (int i = 0; i < styles.length; i++) { + styles[i].free(); + } + if (defaultTextProperties != 0) OS.GCHandle_Free(defaultTextProperties); + if (string != 0) OS.GCHandle_Free(string); + defaultTextProperties = string = 0; + segmentsText = null; +} + +/** + * Returns the receiver's horizontal text alignment, which will be one + * of <code>SWT.LEFT</code>, <code>SWT.CENTER</code> or + * <code>SWT.RIGHT</code>. + * + * @return the alignment used to positioned text horizontally + * + * @exception SWTException <ul> + * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> + * </ul> + */ +public int getAlignment () { + checkLayout(); + return alignment; +} + +/** + * Returns the ascent of the receiver. + * + * @return the ascent + * + * @exception SWTException <ul> + * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> + * </ul> + * + * @see #getDescent() + * @see #setDescent(int) + * @see #setAscent(int) + * @see #getLineMetrics(int) + */ +public int getAscent () { + checkLayout(); + return ascent; +} + +/** + * Returns the bounds of the receiver. + * + * @return the bounds of the receiver + * + * @exception SWTException <ul> + * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> + * </ul> + */ +public Rectangle getBounds () { + checkLayout(); + computeRuns(); + double width = 0; + double height = 0; + for (int line=0; line<lines.length; line++) { + if (wrapWidth == -1) width = Math.max(width, OS.TextLine_WidthIncludingTrailingWhitespace(lines[line])); + int lineHeight = (int)OS.TextLine_Height(lines[line]); + if (ascent != -1 && descent != -1) lineHeight = Math.max(lineHeight, ascent + descent); + height += lineHeight + lineSpacing; + } + if (wrapWidth != -1) width = wrapWidth; + return new Rectangle (0, 0, (int)width, (int)height); +} + +/** + * Returns the bounds for the specified range of characters. The + * bounds is the smallest rectangle that encompasses all characters + * in the range. The start and end offsets are inclusive and will be + * clamped if out of range. + * + * @param start the start offset + * @param end the end offset + * @return the bounds of the character range + * + * @exception SWTException <ul> + * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> + * </ul> + */ +public Rectangle getBounds (int start, int end) { + checkLayout(); + computeRuns(); + int length = text.length(); + if (length == 0) return new Rectangle(0, 0, 0, 0); + if (start > end) return new Rectangle(0, 0, 0, 0); + start = Math.min(Math.max(0, start), length - 1); + end = Math.min(Math.max(0, end), length - 1); + start = translateOffset(start); + end = translateOffset(end); + int lineStart = 0, lineEnd = 0, lineY = 0; + int rect = 0; + for (int i = 0; i < lines.length; i++) { + int lineLength = OS.TextLine_Length(lines[i]); + lineStart = lineEnd; + lineEnd = lineStart + lineLength; + if (start < lineEnd) { + if (end < lineStart) break; + int rangeStart = Math.max(start, lineStart); + int rangLength = Math.min(end, lineEnd) - rangeStart + 1; + int rects = OS.TextLine_GetTextBounds(lines[i], rangeStart, rangLength); + if (rects != 0) { + int enumerator = OS.TextBoundsCollection_GetEnumerator(rects); + while (OS.IEnumerator_MoveNext(enumerator)) { + int bounds = OS.TextBoundsCollection_Current(enumerator); + int textRect = OS.TextBounds_Rectangle(bounds); + OS.Rect_Y(textRect, OS.Rect_Y(textRect) + lineY); + if (rect != 0) { + OS.Rect_Union(rect, textRect); + OS.GCHandle_Free(textRect); + } else { + rect = textRect; + } + OS.GCHandle_Free(bounds); + } + OS.GCHandle_Free(enumerator); + } + OS.GCHandle_Free(rects); + } + int lineHeight = (int)OS.TextLine_Height(lines[i]); + if (ascent != -1 && descent != -1) lineHeight = Math.max(lineHeight, ascent + descent); + lineY += lineHeight + lineSpacing; + } + if (rect == 0) return new Rectangle(0, 0, 0, 0); + Rectangle result = new Rectangle((int)OS.Rect_X(rect), (int)OS.Rect_Y(rect), (int)OS.Rect_Width(rect), (int)OS.Rect_Height(rect)); + OS.GCHandle_Free(rect); + return result; +} + +/** + * Returns the descent of the receiver. + * + * @return the descent + * + * @exception SWTException <ul> + * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> + * </ul> + * + * @see #getAscent() + * @see #setAscent(int) + * @see #setDescent(int) + * @see #getLineMetrics(int) + */ +public int getDescent () { + checkLayout(); + return descent; +} + +/** + * Returns the default 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 () { + checkLayout(); + return font; +} + +/** +* Returns the receiver's indent. +* +* @return the receiver's indent +* +* @exception SWTException <ul> +* <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> +* </ul> +* +* @since 3.2 +*/ +public int getIndent () { + checkLayout(); + return indent; +} + +/** +* Returns the receiver's justification. +* +* @return the receiver's justification +* +* @exception SWTException <ul> +* <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> +* </ul> +* +* @since 3.2 +*/ +public boolean getJustify () { + checkLayout(); + return justify; +} + +/** + * Returns the embedding level for the specified character offset. The + * embedding level is usually used to determine the directionality of a + * character in bidirectional text. + * + * @param offset the charecter offset + * @return the embedding level + * + * @exception IllegalArgumentException <ul> + * <li>ERROR_INVALID_ARGUMENT - if the character offset is out of range</li> + * </ul> + * @exception SWTException <ul> + * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> + */ +public int getLevel (int offset) { + checkLayout(); + computeRuns(); + int length = text.length(); + if (!(0 <= offset && offset <= length)) SWT.error(SWT.ERROR_INVALID_RANGE); + offset = translateOffset(offset); + int level = (orientation & SWT.RIGHT_TO_LEFT) != 0 ? 1 : 0; + for (int i = 0; i < lines.length; i++) { + int lineLength = OS.TextLine_Length(lines[i]); + if (lineLength > offset) { + int runs = OS.TextLine_GetIndexedGlyphRuns (lines[i]); + int enumerator = OS.IndexedGlyphRunCollection_GetEnumerator(runs); + while (OS.IEnumerator_MoveNext(enumerator)) { + int indexedGlyphRun = OS.IndexedGlyphRunCollection_Current(enumerator); + int rangeStart = OS.IndexedGlyphRun_TextSourceCharacterIndex(indexedGlyphRun); + int rangeEnd = rangeStart + OS.IndexedGlyphRun_TextSourceLength(indexedGlyphRun); + int glyphRun = OS.IndexedGlyphRun_GlyphRun(indexedGlyphRun); + int bidiLevel = OS.GlyphRun_BidiLevel(glyphRun); + OS.GCHandle_Free(glyphRun); + OS.GCHandle_Free(indexedGlyphRun); + if (rangeStart <= offset && offset < rangeEnd) { + level = bidiLevel; + break; + } + } + OS.GCHandle_Free(enumerator); + OS.GCHandle_Free(runs); + break; + } + } + return level; +} + +/** + * Returns the bounds of the line for the specified line index. + * + * @param lineIndex the line index + * @return the line bounds + * + * @exception IllegalArgumentException <ul> + * <li>ERROR_INVALID_ARGUMENT - if the line index is out of range</li> + * </ul> + * @exception SWTException <ul> + * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> + * </ul> + */ +public Rectangle getLineBounds(int lineIndex) { + checkLayout(); + computeRuns(); + if (!(0 <= lineIndex && lineIndex < runs.length)) SWT.error(SWT.ERROR_INVALID_RANGE); + int offset = 0; + double y = 0; + for (int i=0; i<lineIndex; i++) { + offset += OS.TextLine_Length(lines[i]); + int lineHeight = (int)OS.TextLine_Height(lines[i]); + if (ascent != -1 && descent != -1) lineHeight = Math.max(lineHeight, ascent + descent); + y += lineHeight + lineSpacing; + } + int line = lines[lineIndex]; + double x = OS.TextLine_Start(line); + double width = OS.TextLine_Width(line); + double height = OS.TextLine_Height(line); + if (ascent != -1 && descent != -1) height = Math.max(height, ascent + descent); + char ch; + boolean firstLine = offset == 0 || (ch = segmentsText.charAt(offset - 1)) == '\r' || ch == '\n'; + if (firstLine) { + x += indent; + width -= indent; + } + return new Rectangle ((int)x, (int)y, (int)width, (int)height); +} + +/** + * Returns the receiver's line count. This includes lines caused + * by wrapping. + * + * @return the line count + * + * @exception SWTException <ul> + * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> + * </ul> + */ +public int getLineCount () { + checkLayout(); + computeRuns(); + return lines.length; +} + +/** + * Returns the index of the line that contains the specified + * character offset. + * + * @param offset the character offset + * @return the line index + * + * @exception IllegalArgumentException <ul> + * <li>ERROR_INVALID_ARGUMENT - if the character offset is out of range</li> + * </ul> + * @exception SWTException <ul> + * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> + * </ul> + */ +public int getLineIndex (int offset) { + checkLayout(); + computeRuns(); + int length = text.length(); + if (!(0 <= offset && offset <= length)) SWT.error(SWT.ERROR_INVALID_RANGE); + offset = translateOffset(offset); + int start = 0; + for (int line=0; line<lines.length; line++) { + int lineLength = OS.TextLine_Length(lines[line]); + if (start + lineLength > offset) return line; + start += lineLength; + } + return lines.length - 1; +} + +/** + * Returns the font metrics for the specified line index. + * + * @param lineIndex the line index + * @return the font metrics + * + * @exception IllegalArgumentException <ul> + * <li>ERROR_INVALID_ARGUMENT - if the line index is out of range</li> + * </ul> + * @exception SWTException <ul> + * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> + * </ul> + */ +public FontMetrics getLineMetrics (int lineIndex) { + checkLayout(); + computeRuns(); + if (!(0 <= lineIndex && lineIndex < runs.length)) SWT.error(SWT.ERROR_INVALID_RANGE); + int length = text.length(); + double baseline, height; + if (length == 0) { + Font font = this.font != null ? this.font : device.systemFont; + int str = OS.gcnew_String (new char []{' ', '\0'}); + int culture = OS.CultureInfo_CurrentUICulture(); + int direction = (orientation & SWT.RIGHT_TO_LEFT) != 0 ? OS.FlowDirection_RightToLeft : OS.FlowDirection_LeftToRight; + int brush = OS.Brushes_White(); + int text = OS.gcnew_FormattedText(str, culture, direction, font.handle, font.size, brush); + height = OS.FormattedText_Height(text); + baseline = OS.FormattedText_Baseline(text); + OS.GCHandle_Free(text); + OS.GCHandle_Free(str); + OS.GCHandle_Free(brush); + OS.GCHandle_Free(culture); + } else { + baseline = OS.TextLine_Baseline(lines[lineIndex]); + height = OS.TextLine_Height(lines[lineIndex]); + if (ascent != -1 && descent != -1) { + baseline = Math.max(baseline, ascent); + height = Math.max(height, ascent + descent); + } + } + return FontMetrics.wpf_new((int)baseline, (int)(height - baseline), 0, 0, (int)height); +} + +/** + * Returns the line offsets. Each value in the array is the + * offset for the first character in a line except for the last + * value, which contains the length of the text. + * + * @return the line offsets + * + * @exception SWTException <ul> + * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> + * </ul> + */ +public int[] getLineOffsets () { + checkLayout(); + computeRuns(); + int start = 0; + int[] offsets = new int[lines.length+1]; + for (int i = 0; i < lines.length; i++) { + start += OS.TextLine_Length(lines[i]); + offsets[i+1] = untranslateOffset(start); + } + return offsets; +} + +/** + * Returns the location for the specified character offset. The + * <code>trailing</code> argument indicates whether the offset + * corresponds to the leading or trailing edge of the cluster. + * + * @param offset the character offset + * @param trailing the trailing flag + * @return the location of the character offset + * + * @exception SWTException <ul> + * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> + * </ul> + * + * @see #getOffset(Point, int[]) + * @see #getOffset(int, int, int[]) + */ +public Point getLocation (int offset, boolean trailing) { + checkLayout(); + computeRuns(); + int length = text.length(); + if (!(0 <= offset && offset <= length)) SWT.error(SWT.ERROR_INVALID_RANGE); + length = segmentsText.length(); + offset = translateOffset(offset); + double y = 0; + int start = 0, line; + for (line=0; line<lines.length; line++) { + int lineLength = OS.TextLine_Length(lines[line]); + if (start + lineLength > offset) break; + start += lineLength; + int lineHeight = (int)OS.TextLine_Height(lines[line]); + if (ascent != -1 && descent != -1) lineHeight = Math.max(lineHeight, ascent + descent); + y += lineHeight + lineSpacing; + } + int characterHit = OS.gcnew_CharacterHit(offset, trailing ? 1 : 0); + double x = OS.TextLine_GetDistanceFromCharacterHit(lines[line], characterHit); + OS.GCHandle_Free(characterHit); + return new Point((int)x, (int)y); +} + +/** + * Returns the next offset for the specified offset and movement + * type. The movement is one of <code>SWT.MOVEMENT_CHAR</code>, + * <code>SWT.MOVEMENT_CLUSTER</code> or <code>SWT.MOVEMENT_WORD</code>. + * + * @param offset the start offset + * @param movement the movement type + * @return the next offset + * + * @exception IllegalArgumentException <ul> + * <li>ERROR_INVALID_ARGUMENT - if the offset is out of range</li> + * </ul> + * @exception SWTException <ul> + * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> + * </ul> + * + * @see #getPreviousOffset(int, int) + */ +public int getNextOffset (int offset, int movement) { + checkLayout(); + return _getOffset (offset, movement, true); +} + +int _getOffset(int offset, int movement, boolean forward) { + computeRuns(); + int length = text.length(); + if (!(0 <= offset && offset <= length)) SWT.error(SWT.ERROR_INVALID_RANGE); + if (forward && offset == length) return length; + if (!forward && offset == 0) return 0; + int step = forward ? 1 : -1; + if ((movement & SWT.MOVEMENT_CHAR) != 0) return offset + step; + length = segmentsText.length(); + offset = translateOffset(offset); + int lineStart = 0; + for (int line=0; line<lines.length; line++) { + int lineLength = OS.TextLine_Length(lines[line]); + if (lineStart <= offset && offset < lineStart + lineLength) { + if (forward) { + if (offset >= lineStart + lineLength - OS.TextLine_NewlineLength(lines[line])) { + return untranslateOffset(lineStart + lineLength); + } + } else { + if (offset == lineStart) { + if (line == 0) return 0; + int breakLength = OS.TextLine_NewlineLength(lines[line - 1]); + if (breakLength != 0) { + return untranslateOffset(offset - breakLength); + } + } + } + int resultCharHit; + int characterHit = OS.gcnew_CharacterHit(offset, 0); + if (forward) { + resultCharHit = OS.TextLine_GetNextCaretCharacterHit(lines[line], characterHit); + } else { + resultCharHit = OS.TextLine_GetPreviousCaretCharacterHit(lines[line], characterHit); + } + int result = OS.CharacterHit_FirstCharacterIndex(resultCharHit); + int trailing = OS.CharacterHit_TrailingLength(resultCharHit); + OS.GCHandle_Free(resultCharHit); + OS.GCHandle_Free(characterHit); + return untranslateOffset(result + trailing); + } + lineStart += lineLength; + } + return forward ? text.length() : 0; +} + +/** + * Returns the character offset for the specified point. + * For a typical character, the trailing argument will be filled in to + * indicate whether the point is closer to the leading edge (0) or + * the trailing edge (1). When the point is over a cluster composed + * of multiple characters, the trailing argument will be filled with the + * position of the character in the cluster that is closest to + * the point. + * + * @param point the point + * @param trailing the trailing buffer + * @return the character offset + * + * @exception IllegalArgumentException <ul> + * <li>ERROR_INVALID_ARGUMENT - if the trailing length is less than <code>1</code></li> + * <li>ERROR_NULL_ARGUMENT - if the point is null</li> + * </ul> + * @exception SWTException <ul> + * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> + * </ul> + * + * @see #getLocation(int, boolean) + */ +public int getOffset (Point point, int[] trailing) { + checkLayout(); + if (point == null) SWT.error (SWT.ERROR_NULL_ARGUMENT); + return getOffset (point.x, point.y, trailing) ; +} + +/** + * Returns the character offset for the specified point. + * For a typical character, the trailing argument will be filled in to + * indicate whether the point is closer to the leading edge (0) or + * the trailing edge (1). When the point is over a cluster composed + * of multiple characters, the trailing argument will be filled with the + * position of the character in the cluster that is closest to + * the point. + * + * @param x the x coordinate of the point + * @param y the y coordinate of the point + * @param trailing the trailing buffer + * @return the character offset + * + * @exception IllegalArgumentException <ul> + * <li>ERROR_INVALID_ARGUMENT - if the trailing length is less than <code>1</code></li> + * </ul> + * @exception SWTException <ul> + * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> + * </ul> + * + * @see #getLocation(int, boolean) + */ +public int getOffset (int x, int y, int[] trailing) { + checkLayout(); + computeRuns(); + if (trailing != null && trailing.length < 1) SWT.error(SWT.ERROR_INVALID_ARGUMENT); + double lineY = 0; + int line; + for (line=0; line<lines.length; line++) { + double lineHeight = OS.TextLine_Length(lines[line]); + if (lineY + lineHeight > y) break; + lineY += lineHeight; + } + if (line >= lines.length) line = lines.length - 1; + int characterHit = OS.TextLine_GetCharacterHitFromDistance(lines[line], x); + int offset = OS.CharacterHit_FirstCharacterIndex(characterHit); + if (trailing != null) trailing[0] = OS.CharacterHit_TrailingLength(characterHit); + OS.GCHandle_Free(characterHit); + return untranslateOffset(offset); +} + +/** + * Returns the orientation of the receiver. + * + * @return the orientation style + * + * @exception SWTException <ul> + * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> + * </ul> + */ +public int getOrientation () { + checkLayout(); + return orientation; +} + +/** + * Returns the previous offset for the specified offset and movement + * type. The movement is one of <code>SWT.MOVEMENT_CHAR</code>, + * <code>SWT.MOVEMENT_CLUSTER</code> or <code>SWT.MOVEMENT_WORD</code>. + * + * @param offset the start offset + * @param movement the movement type + * @return the previous offset + * + * @exception IllegalArgumentException <ul> + * <li>ERROR_INVALID_ARGUMENT - if the offset is out of range</li> + * </ul> + * @exception SWTException <ul> + * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> + * </ul> + * + * @see #getNextOffset(int, int) + */ +public int getPreviousOffset (int offset, int movement) { + checkLayout(); + return _getOffset (offset, movement, false); +} + +/** + * Gets the ranges of text that are associated with a <code>TextStyle</code>. + * + * @return the ranges, an array of offsets representing the start and end of each + * text style. + * + * @exception SWTException <ul> + * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> + * </ul> + * + * @see #getStyles() + * + * @since 3.2 + */ +public int[] getRanges () { + checkLayout(); + int[] result = new int[styles.length * 2]; + int count = 0; + for (int i=0; i<styles.length - 1; i++) { + if (styles[i].style != null) { + result[count++] = styles[i].start; + result[count++] = styles[i + 1].start - 1; + } + } + if (count != result.length) { + int[] newResult = new int[count]; + System.arraycopy(result, 0, newResult, 0, count); + result = newResult; + } + return result; +} + +/** + * Returns the text segments offsets of the receiver. + * + * @return the text segments offsets + * + * @exception SWTException <ul> + * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> + * </ul> + */ +public int[] getSegments () { + checkLayout(); + return segments; +} + +String getSegmentsText() { + if (segments == null) return text; + int nSegments = segments.length; + if (nSegments <= 1) return text; + int length = text.length(); + if (length == 0) return text; + if (nSegments == 2) { + if (segments[0] == 0 && segments[1] == length) return text; + } + char[] oldChars = new char[length]; + text.getChars(0, length, oldChars, 0); + char[] newChars = new char[length + nSegments]; + int charCount = 0, segmentCount = 0; + char separator = orientation == SWT.RIGHT_TO_LEFT ? RTL_MARK : LTR_MARK; + while (charCount < length) { + if (segmentCount < nSegments && charCount == segments[segmentCount]) { + newChars[charCount + segmentCount++] = separator; + } else { + newChars[charCount + segmentCount] = oldChars[charCount++]; + } + } + if (segmentCount < nSegments) { + segments[segmentCount] = charCount; + newChars[charCount + segmentCount++] = separator; + } + return new String(newChars, 0, Math.min(charCount + segmentCount, newChars.length)); +} + +/** + * Returns the line spacing of the receiver. + * + * @return the line spacing + * + * @exception SWTException <ul> + * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> + * </ul> + */ +public int getSpacing () { + checkLayout(); + return lineSpacing; +} + +/** + * Gets the style of the receiver at the specified character offset. + * + * @param offset the text offset + * @return the style or <code>null</code> if not set + * + * @exception IllegalArgumentException <ul> + * <li>ERROR_INVALID_ARGUMENT - if the character offset is out of range</li> + * </ul> + * @exception SWTException <ul> + * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> + * </ul> + */ +public TextStyle getStyle (int offset) { + checkLayout(); + int length = text.length(); + if (!(0 <= offset && offset < length)) SWT.error(SWT.ERROR_INVALID_RANGE); + for (int i=1; i<styles.length; i++) { + if (styles[i].start > offset) { + return styles[i - 1].style; + } + } + return null; +} + +/** + * Gets all styles of the receiver. + * + * @return the styles + * + * @exception SWTException <ul> + * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> + * </ul> + * + * @see #getRanges() + * + * @since 3.2 + */ +public TextStyle[] getStyles () { + checkLayout(); + TextStyle[] result = new TextStyle[styles.length]; + int count = 0; + for (int i=0; i<styles.length; i++) { + if (styles[i].style != null) { + result[count++] = styles[i].style; + } + } + if (count != result.length) { + TextStyle[] newResult = new TextStyle[count]; + System.arraycopy(result, 0, newResult, 0, count); + result = newResult; + } + return result; +} + +/** + * Returns the tab list of the receiver. + * + * @return the tab list + * + * @exception SWTException <ul> + * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> + * </ul> + */ +public int[] getTabs () { + checkLayout(); + return tabs; +} + +int GetTextRun(int textSourceCharacterIndex) { + if (runs == null) runs = new int[4]; + int index = 0; + while (index < runs.length && runs[index] != 0) index++; + if (index == runs.length) { + int[] tmpRuns = new int[index + 4]; + System.arraycopy(runs, 0, tmpRuns, 0, index); + runs = tmpRuns; + } + int length = OS.String_Length(string); + if (textSourceCharacterIndex >= length) { + runs[index] = OS.gcnew_TextEndOfParagraph(1, defaultTextProperties); + } else { + int styleIndex = 1; + while (styleIndex < styles.length && styles[styleIndex].start <= textSourceCharacterIndex) styleIndex++; + TextStyle textStyle = styles[styleIndex - 1].style; + int textProperties = styles[styleIndex - 1].textProperties; + if (textProperties == 0) textProperties = defaultTextProperties; + int end = styles[styleIndex].start; + if (textStyle != null && textStyle.metrics != null) { + GlyphMetrics metrics = textStyle.metrics; + runs[index] = OS.gcnew_SWTTextEmbeddedObject(textProperties, end - textSourceCharacterIndex, metrics.width, metrics.ascent + metrics.descent, metrics.ascent); + } else { + char ch = segmentsText.charAt(textSourceCharacterIndex); + if (ch == '\n' || ch == '\r') { + int breakLength = 1; + if (ch == '\r' && textSourceCharacterIndex + 1 < end && segmentsText.charAt(textSourceCharacterIndex + 1) == '\n') breakLength++; + runs[index] = OS.gcnew_TextEndOfLine(breakLength, textProperties); + } else { + int i = textSourceCharacterIndex; + while (i < end && (ch = segmentsText.charAt(i)) != '\n' && ch != '\r') i++; + runs[index] = OS.gcnew_TextCharacters(string, textSourceCharacterIndex, i - textSourceCharacterIndex, textProperties); + } + } + } + return runs[index]; +} + +int GetPrecedingText(int textSourceCharacterIndexLimit) { + System.out.println("GetPrecedingText"); + return 0; +} + +/** + * Gets the receiver's text, which will be an empty + * string if it has never been set. + * + * @return the receiver's text + * + * @exception SWTException <ul> + * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> + * </ul> + */ +public String getText () { + checkLayout(); + return text; +} + +/** + * Returns the width of the receiver. + * + * @return the width + * + * @exception SWTException <ul> + * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> + * </ul> + */ +public int getWidth () { + checkLayout(); + return wrapWidth; +} + +/** + * Returns <code>true</code> if the text layout has been disposed, + * and <code>false</code> otherwise. + * <p> + * This method gets the dispose state for the text layout. + * When a text layout has been disposed, it is an error to + * invoke any other method using the text layout. + * </p> + * + * @return <code>true</code> when the text layout is disposed and <code>false</code> otherwise + */ +public boolean isDisposed () { + return device == null; +} + +/** + * Sets the text alignment for the receiver. The alignment controls + * how a line of text is positioned horizontally. The argument should + * be one of <code>SWT.LEFT</code>, <code>SWT.RIGHT</code> or <code>SWT.CENTER</code>. + * <p> + * The default alignment is <code>SWT.LEFT</code>. Note that the receiver's + * width must be set in order to use <code>SWT.RIGHT</code> or <code>SWT.CENTER</code> + * alignment. + * </p> + * + * @param alignment the new alignment + * + * @exception SWTException <ul> + * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> + * </ul> + * + * @see #setWidth(int) + */ +public void setAlignment (int alignment) { + checkLayout(); + int mask = SWT.LEFT | SWT.CENTER | SWT.RIGHT; + alignment &= mask; + if (alignment == 0) return; + if ((alignment & SWT.LEFT) != 0) alignment = SWT.LEFT; + if ((alignment & SWT.RIGHT) != 0) alignment = SWT.RIGHT; + if (this.alignment == alignment) return; + freeRuns(); + this.alignment = alignment; +} + +/** + * Sets the ascent of the receiver. The ascent is distance in pixels + * from the baseline to the top of the line and it is applied to all + * lines. The default value is <code>-1</code> which means that the + * ascent is calculated from the line fonts. + * + * @param ascent the new ascent + * + * @exception IllegalArgumentException <ul> + * <li>ERROR_INVALID_ARGUMENT - if the ascent is less than <code>-1</code></li> + * </ul> + * @exception SWTException <ul> + * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> + * </ul> + * + * @see #setDescent(int) + * @see #getLineMetrics(int) + */ +public void setAscent(int ascent) { + checkLayout(); + if (ascent < -1) SWT.error(SWT.ERROR_INVALID_ARGUMENT); + if (this.ascent == ascent) return; + freeRuns(); + this.ascent = ascent; +} + +/** + * Sets the descent of the receiver. The descent is distance in pixels + * from the baseline to the bottom of the line and it is applied to all + * lines. The default value is <code>-1</code> which means that the + * descent is calculated from the line fonts. + * + * @param descent the new descent + * + * @exception IllegalArgumentException <ul> + * <li>ERROR_INVALID_ARGUMENT - if the descent is less than <code>-1</code></li> + * </ul> + * @exception SWTException <ul> + * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> + * </ul> + * + * @see #setAscent(int) + * @see #getLineMetrics(int) + */ +public void setDescent(int descent) { + checkLayout(); + if (descent < -1) SWT.error(SWT.ERROR_INVALID_ARGUMENT); + if (this.descent == descent) return; + freeRuns(); + this.descent = descent; +} + +/** + * Sets the default font which will be used by the receiver + * to draw and measure text. If the + * argument is null, then a default font appropriate + * for the platform will be used instead. Note that a text + * style can override the default font. + * + * @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) { + checkLayout(); + if (font != null && font.isDisposed()) SWT.error(SWT.ERROR_INVALID_ARGUMENT); + if (this.font == font) return; + if (font != null && font.equals(this.font)) return; + freeRuns(); + this.font = font; +} + +/** + * Sets the indent of the receiver. This indent it applied of the first line of + * each paragraph. + * + * @param indent new indent + * + * @exception SWTException <ul> + * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> + * </ul> + * + * @since 3.2 + */ +public void setIndent (int indent) { + checkLayout(); + if (indent < 0) return; + if (this.indent == indent) return; + freeRuns(); + this.indent = indent; +} + +/** + * Sets the justification of the receiver. Note that the receiver's + * width must be set in order to use justification. + * + * @param justify new justify + * + * @exception SWTException <ul> + * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> + * </ul> + * + * @since 3.2 + */ +public void setJustify (boolean justify) { + checkLayout(); + if (this.justify == justify) return; + freeRuns(); + this.justify = justify; +} + +/** + * Sets the orientation of the receiver, which must be one + * of <code>SWT.LEFT_TO_RIGHT</code> or <code>SWT.RIGHT_TO_LEFT</code>. + * + * @param orientation new orientation style + * + * @exception SWTException <ul> + * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> + * </ul> + */ +public void setOrientation (int orientation) { + checkLayout(); + int mask = SWT.LEFT_TO_RIGHT | SWT.RIGHT_TO_LEFT; + orientation &= mask; + if (orientation == 0) return; + if ((orientation & SWT.LEFT_TO_RIGHT) != 0) orientation = SWT.LEFT_TO_RIGHT; + if (this.orientation == orientation) return; + this.orientation = orientation; + freeRuns(); +} + +/** + * Sets the offsets of the receiver's text segments. Text segments are used to + * override the default behaviour of the bidirectional algorithm. + * Bidirectional reordering can happen within a text segment but not + * between two adjacent segments. + * <p> + * Each text segment is determined by two consecutive offsets in the + * <code>segments</code> arrays. The first element of the array should + * always be zero and the last one should always be equals to length of + * the text. + * </p> + * + * @param segments the text segments offset + * + * @exception SWTException <ul> + * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> + * </ul> + */ +public void setSegments(int[] segments) { + checkLayout(); + if (this.segments == null && segments == null) return; + if (this.segments != null && segments != null) { + if (this.segments.length == segments.length) { + int i; + for (i = 0; i <segments.length; i++) { + if (this.segments[i] != segments[i]) break; + } + if (i == segments.length) return; + } + } + freeRuns(); + this.segments = segments; +} + +/** + * Sets the line spacing of the receiver. The line spacing + * is the space left between lines. + * + * @param spacing the new line spacing + * + * @exception IllegalArgumentException <ul> + * <li>ERROR_INVALID_ARGUMENT - if the spacing is negative</li> + * </ul> + * @exception SWTException <ul> + * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> + * </ul> + */ +public void setSpacing (int spacing) { + checkLayout(); + if (spacing < 0) SWT.error(SWT.ERROR_INVALID_ARGUMENT); + if (this.lineSpacing == spacing) return; + freeRuns(); + this.lineSpacing = spacing; +} + +/** + * Sets the style of the receiver for the specified range. Styles previously + * set for that range will be overwritten. The start and end offsets are + * inclusive and will be clamped if out of range. + * + * @param style the style + * @param start the start offset + * @param end the end offset + * + * @exception SWTException <ul> + * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> + * </ul> + */ +public void setStyle (TextStyle style, int start, int end) { + checkLayout(); + int length = text.length(); + if (length == 0) return; + if (start > end) return; + start = Math.min(Math.max(0, start), length - 1); + end = Math.min(Math.max(0, end), length - 1); + int low = -1; + int high = styles.length; + while (high - low > 1) { + int index = (high + low) / 2; + if (styles[index + 1].start > start) { + high = index; + } else { + low = index; + } + } + if (0 <= high && high < styles.length) { + StyleItem item = styles[high]; + if (item.start == start && styles[high + 1].start - 1 == end) { + if (style == null) { + if (item.style == null) return; + } else { + if (style.equals(item.style)) return; + } + } + } + freeRuns(); + int modifyStart = high; + int modifyEnd = modifyStart; + while (modifyEnd < styles.length) { + if (styles[modifyEnd + 1].start > end) break; + modifyEnd++; + } + if (modifyStart == modifyEnd) { + int styleStart = styles[modifyStart].start; + int styleEnd = styles[modifyEnd + 1].start - 1; + if (styleStart == start && styleEnd == end) { + styles[modifyStart].style = style; + return; + } + if (styleStart != start && styleEnd != end) { + StyleItem[] newStyles = new StyleItem[styles.length + 2]; + System.arraycopy(styles, 0, newStyles, 0, modifyStart + 1); + StyleItem item = new StyleItem(); + item.start = start; + item.style = style; + newStyles[modifyStart + 1] = item; + item = new StyleItem(); + item.start = end + 1; + item.style = styles[modifyStart].style; + newStyles[modifyStart + 2] = item; + System.arraycopy(styles, modifyEnd + 1, newStyles, modifyEnd + 3, styles.length - modifyEnd - 1); + styles = newStyles; + return; + } + } + if (start == styles[modifyStart].start) modifyStart--; + if (end == styles[modifyEnd + 1].start - 1) modifyEnd++; + int newLength = styles.length + 1 - (modifyEnd - modifyStart - 1); + StyleItem[] newStyles = new StyleItem[newLength]; + System.arraycopy(styles, 0, newStyles, 0, modifyStart + 1); + StyleItem item = new StyleItem(); + item.start = start; + item.style = style; + newStyles[modifyStart + 1] = item; + styles[modifyEnd].start = end + 1; + System.arraycopy(styles, modifyEnd, newStyles, modifyStart + 2, styles.length - modifyEnd); + styles = newStyles; +} + +/** + * Sets the receiver's tab list. Each value in the tab list specifies + * the space in pixels from the origin of the text layout to the respective + * tab stop. The last tab stop width is repeated continuously. + * + * @param tabs the new tab list + * + * @exception SWTException <ul> + * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> + * </ul> + */ +public void setTabs (int[] tabs) { + checkLayout(); + if (this.tabs == null && tabs == null) return; + if (this.tabs != null && tabs !=null) { + if (this.tabs.length == tabs.length) { + int i; + for (i = 0; i <tabs.length; i++) { + if (this.tabs[i] != tabs[i]) break; + } + if (i == tabs.length) return; + } + } + freeRuns(); + this.tabs = tabs; +} + +/** + * Sets the receiver's text. + * + * @param text the new text + * + * @exception IllegalArgumentException <ul> + * <li>ERROR_NULL_ARGUMENT - if the text is null</li> + * </ul> + * @exception SWTException <ul> + * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> + * </ul> + */ +public void setText (String text) { + checkLayout(); + if (text == null) SWT.error(SWT.ERROR_NULL_ARGUMENT); + if (text.equals(this.text)) return; + freeRuns(); + this.text = text; + styles = new StyleItem[2]; + styles[0] = new StyleItem(); + styles[1] = new StyleItem(); + styles[1].start = text.length(); +} + +/** + * Sets the line width of the receiver, which determines how + * text should be wrapped and aligned. The default value is + * <code>-1</code> which means wrapping is disabled. + * + * @param width the new width + * + * @exception IllegalArgumentException <ul> + * <li>ERROR_INVALID_ARGUMENT - if the width is <code>0</code> or less than <code>-1</code></li> + * </ul> + * @exception SWTException <ul> + * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> + * </ul> + * + * @see #setAlignment(int) + */ +public void setWidth (int width) { + checkLayout(); + if (width < -1 || width == 0) SWT.error(SWT.ERROR_INVALID_ARGUMENT); + if (this.wrapWidth == width) return; + freeRuns(); + this.wrapWidth = width; +} + +int validadeOffset(int offset, int step) { + offset += step; + if (segments != null && segments.length > 2) { + for (int i = 0; i < segments.length; i++) { + if (translateOffset(segments[i]) - 1 == offset) { + offset += step; + break; + } + } + } + return offset; +} + +/** + * 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 "TextLayout {*DISPOSED*}"; + return "TextLayout {}"; +} + +int translateOffset(int offset) { + if (segments == null) return offset; + int nSegments = segments.length; + if (nSegments <= 1) return offset; + int length = text.length(); + if (length == 0) return offset; + if (nSegments == 2) { + if (segments[0] == 0 && segments[1] == length) return offset; + } + for (int i = 0; i < nSegments && offset - i >= segments[i]; i++) { + offset++; + } + return offset; +} + +int untranslateOffset(int offset) { + if (segments == null) return offset; + int nSegments = segments.length; + if (nSegments <= 1) return offset; + int length = text.length(); + if (length == 0) return offset; + if (nSegments == 2) { + if (segments[0] == 0 && segments[1] == length) return offset; + } + for (int i = 0; i < nSegments && offset > segments[i]; i++) { + offset--; + } + return offset; +} +} diff --git a/bundles/org.eclipse.swt/Eclipse SWT/wpf/org/eclipse/swt/graphics/Transform.java b/bundles/org.eclipse.swt/Eclipse SWT/wpf/org/eclipse/swt/graphics/Transform.java new file mode 100644 index 0000000000..9aac18f051 --- /dev/null +++ b/bundles/org.eclipse.swt/Eclipse SWT/wpf/org/eclipse/swt/graphics/Transform.java @@ -0,0 +1,341 @@ +/******************************************************************************* + * Copyright (c) 2000, 2006 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.swt.graphics; + +import org.eclipse.swt.*; +import org.eclipse.swt.internal.wpf.*; + +/** + * Instances of this class represent transformation matrices for + * points expressed as (x, y) pairs of floating point numbers. + * <p> + * Application code must explicitly invoke the <code>Transform.dispose()</code> + * method to release the operating system resources managed by each instance + * when those instances are no longer required. + * </p> + * + * @since 3.1 + */ +public class Transform extends Resource { + + /** + * the OS resource for the Transform + * (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> + */ + public int handle; + +/** + * Constructs a new identity Transform. + * + * @param device the device on which to allocate the Transform + * + * @exception IllegalArgumentException <ul> + * <li>ERROR_NULL_ARGUMENT - if device is null and there is no current device</li> + * </ul> + * @exception SWTError <ul> + * <li>ERROR_NO_HANDLES if a handle for the Transform could not be obtained/li> + * </ul> + * + * @see #dispose() + */ +public Transform (Device device) { + this(device, 1, 0, 0, 1, 0, 0); +} + +/** + * Constructs a new Transform given an array of elements that represent the + * matrix that describes the transformation. + * + * @param device the device on which to allocate the Transform + * @param elements an array of floats that describe the transformation matrix + * + * @exception IllegalArgumentException <ul> + * <li>ERROR_NULL_ARGUMENT - if device is null and there is no current device, or the elements array is null</li> + * <li>ERROR_INVALID_ARGUMENT - if the elements array is too small to hold the matrix values</li> + * </ul> + * @exception SWTError <ul> + * <li>ERROR_NO_HANDLES if a handle for the Transform could not be obtained/li> + * </ul> + * + * @see #dispose() + */ +public Transform(Device device, float[] elements) { + this (device, checkTransform(elements)[0], elements[1], elements[2], elements[3], elements[4], elements[5]); +} + +/** + * Constructs a new Transform given all of the elements that represent the + * matrix that describes the transformation. + * + * @param device the device on which to allocate the Transform + * @param m11 the first element of the first row of the matrix + * @param m12 the second element of the first row of the matrix + * @param m21 the first element of the second row of the matrix + * @param m22 the second element of the second row of the matrix + * @param dx the third element of the first row of the matrix + * @param dy the third element of the second row of the matrix + * + * @exception IllegalArgumentException <ul> + * <li>ERROR_NULL_ARGUMENT - if device is null and there is no current device</li> + * </ul> + * @exception SWTError <ul> + * <li>ERROR_NO_HANDLES if a handle for the Transform could not be obtained/li> + * </ul> + * + * @see #dispose() + */ +public Transform (Device device, float m11, float m12, float m21, float m22, float dx, float dy) { + if (device == null) device = Device.getDevice(); + if (device == null) SWT.error(SWT.ERROR_NULL_ARGUMENT); + this.device = device; + handle = OS.gcnew_Matrix(m11, m12, m21, m22, dx, dy); + if (handle == 0) SWT.error(SWT.ERROR_NO_HANDLES); + if (device.tracking) device.new_Object(this); +} + +static float[] checkTransform(float[] elements) { + if (elements == null) SWT.error(SWT.ERROR_NULL_ARGUMENT); + if (elements.length < 6) SWT.error(SWT.ERROR_INVALID_ARGUMENT); + return elements; +} + +/** + * Disposes of the operating system resources associated with + * the Transform. Applications must dispose of all Transforms that + * they allocate. + */ +public void dispose() { + if (handle == 0) return; + if (device.isDisposed()) return; + OS.GCHandle_Free(handle); + handle = 0; + if (device.tracking) device.dispose_Object(this); + device = null; +} + +/** + * Fills the parameter with the values of the transformation matrix + * that the receiver represents, in the order {m11, m12, m21, m22, dx, dy}. + * + * @param elements array to hold the matrix values + * + * @exception SWTException <ul> + * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> + * </ul> + * @exception IllegalArgumentException <ul> + * <li>ERROR_NULL_ARGUMENT - if the parameter is null</li> + * <li>ERROR_INVALID_ARGUMENT - if the parameter is too small to hold the matrix values</li> + * </ul> + */ +public void getElements(float[] elements) { + if (isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); + if (elements == null) SWT.error(SWT.ERROR_NULL_ARGUMENT); + if (elements.length < 6) SWT.error(SWT.ERROR_INVALID_ARGUMENT); + elements[0] = (float)OS.Matrix_M11(handle); + elements[1] = (float)OS.Matrix_M12(handle); + elements[2] = (float)OS.Matrix_M21(handle); + elements[3] = (float)OS.Matrix_M22(handle); + elements[4] = (float)OS.Matrix_OffsetX(handle); + elements[5] = (float)OS.Matrix_OffsetY(handle); +} + +/** + * Modifies the receiver such that the matrix it represents becomes the + * the mathematical inverse of the matrix it previously represented. + * + * @exception SWTException <ul> + * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> + * <li>ERROR_CANNOT_INVERT_MATRIX - if the matrix is not invertable</li> + * </ul> + */ +public void invert() { + if (isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); + OS.Matrix_Invert(handle); + //TODO handle matrix invert exception + //SWT.error(SWT.ERROR_CANNOT_INVERT_MATRIX); +} + +/** + * Returns <code>true</code> if the Transform has been disposed, + * and <code>false</code> otherwise. + * <p> + * This method gets the dispose state for the Transform. + * When a Transform has been disposed, it is an error to + * invoke any other method using the Transform. + * + * @return <code>true</code> when the Transform is disposed, and <code>false</code> otherwise + */ +public boolean isDisposed() { + return handle == 0; +} + +/** + * Returns <code>true</code> if the Transform represents the identity matrix + * and false otherwise. + * + * @return <code>true</code> if the receiver is an identity Transform, and <code>false</code> otherwise + */ +public boolean isIdentity() { + if (isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); + return OS.Matrix_IsIdentity(handle); +} + +/** + * Modifies the receiver such that the matrix it represents becomes the + * the result of multiplying the matrix it previously represented by the + * argument. + * + * @param matrix the matrix to multiply the receiver by + * + * @exception SWTException <ul> + * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> + * </ul> + * @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> + */ +public void multiply(Transform matrix) { + if (isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); + if (matrix == null) SWT.error(SWT.ERROR_NULL_ARGUMENT); + if (matrix.isDisposed()) SWT.error(SWT.ERROR_INVALID_ARGUMENT); + int result = OS.Matrix_Multiply(handle, matrix.handle); + OS.Matrix_M11(handle, OS.Matrix_M11(result)); + OS.Matrix_M12(handle, OS.Matrix_M12(result)); + OS.Matrix_M21(handle, OS.Matrix_M21(result)); + OS.Matrix_M22(handle, OS.Matrix_M22(result)); + OS.Matrix_OffsetX(handle, OS.Matrix_OffsetX(result)); + OS.Matrix_OffsetY(handle, OS.Matrix_OffsetY(result)); + OS.GCHandle_Free(result); +} + +/** + * Modifies the receiver so that it represents a transformation that is + * equivalent to its previous transformation rotated by the specified angle. + * The angle is specified in degrees and for the identity transform 0 degrees + * is at the 3 o'clock position. A positive value indicates a clockwise rotation + * while a negative value indicates a counter-clockwise rotation. + * + * @param angle the angle to rotate the transformation by + * + * @exception SWTException <ul> + * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> + * </ul> + */ +public void rotate(float angle) { + if (isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); + OS.Matrix_RotatePrepend(handle, angle); +} + +/** + * Modifies the receiver so that it represents a transformation that is + * equivalent to its previous transformation scaled by (scaleX, scaleY). + * + * @param scaleX the amount to scale in the X direction + * @param scaleY the amount to scale in the Y direction + * + * @exception SWTException <ul> + * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> + * </ul> + */ +public void scale(float scaleX, float scaleY) { + if (isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); + OS.Matrix_ScalePrepend(handle, scaleX, scaleY); +} + +/** + * Modifies the receiver to represent a new transformation given all of + * the elements that represent the matrix that describes that transformation. + * + * @param m11 the first element of the first row of the matrix + * @param m12 the second element of the first row of the matrix + * @param m21 the first element of the second row of the matrix + * @param m22 the second element of the second row of the matrix + * @param dx the third element of the first row of the matrix + * @param dy the third element of the second row of the matrix + * + * @exception SWTException <ul> + * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> + * </ul> + */ +public void setElements(float m11, float m12, float m21, float m22, float dx, float dy) { + if (isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); + OS.Matrix_M11(handle, m11); + OS.Matrix_M12(handle, m12); + OS.Matrix_M21(handle, m21); + OS.Matrix_M22(handle, m22); + OS.Matrix_OffsetX(handle, dx); + OS.Matrix_OffsetY(handle, dy); +} + +/** + * Given an array containing points described by alternating x and y values, + * modify that array such that each point has been replaced with the result of + * applying the transformation represented by the receiver to that point. + * + * @param pointArray an array of alternating x and y values to be transformed + * + * @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 transform(float[] pointArray) { + if (isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); + if (pointArray == null) SWT.error(SWT.ERROR_NULL_ARGUMENT); + for (int i = 0; i < pointArray.length; i += 2) { + int point = OS.gcnew_Point(pointArray[i], pointArray[i + 1]); + int result = OS.Matrix_Transform(handle, point); + pointArray[i] = (float)OS.Point_X(result); + pointArray[i + 1] = (float)OS.Point_Y(result); + OS.GCHandle_Free(point); + OS.GCHandle_Free(result); + } +} + +/** + * Modifies the receiver so that it represents a transformation that is + * equivalent to its previous transformation translated by (offsetX, offsetY). + * + * @param offsetX the distance to translate in the X direction + * @param offsetY the distance to translate in the Y direction + * + * @exception SWTException <ul> + * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> + * </ul> + */ +public void translate(float offsetX, float offsetY) { + if (isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); + OS.Matrix_TranslatePrepend(handle, offsetX, offsetY); +} + +/** + * 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 "Transform {*DISPOSED*}"; + float[] elements = new float[6]; + getElements(elements); + return "Transform {" + elements [0] + "," + elements [1] + "," +elements [2] + "," +elements [3] + "," +elements [4] + "," +elements [5] + "}"; +} + +} |