# HG changeset patch # User Frank Benoit # Date 1201370732 -3600 # Node ID 5f2e72114476e223d8a95ba0e7eeedc4b05ead4f # Parent d2e87572b721e0e9f81f9eb3eab334181878d000 Image in work, this revision does not compile diff -r d2e87572b721 -r 5f2e72114476 dwt/dwthelper/utils.d --- a/dwt/dwthelper/utils.d Sat Jan 26 16:45:05 2008 +0100 +++ b/dwt/dwthelper/utils.d Sat Jan 26 19:05:32 2008 +0100 @@ -1,4 +1,4 @@ -/** +/** * Authors: Frank Benoit */ module dwt.dwthelper.utils; @@ -88,9 +88,24 @@ return str[ pos ]; } +public void getChars( char[] src, int srcBegin, int srcEnd, char[] dst, int dstBegin){ + dst[ dstBegin .. dstBegin + srcEnd - srcBegin ] = str[ srcBegin .. srcEnd ]; +} + +public bool endsWith( char[] src, char[] pattern ){ + if( src.length < pattern.length ){ + return false; + } + return src[ $-pattern.length .. $ ] == pattern; +} + +public char[] toLowerCase( char[] src ){ + return tango.text.Unicode.toLower( src ); +} + static char[] toHex(uint value, bool prefix = true, int radix = 8){ - return tango.text.convert.Integer.toString( - value, + return tango.text.convert.Integer.toString( + value, radix is 10 ? tango.text.convert.Integer.Style.Signed : radix is 8 ? tango.text.convert.Integer.Style.Octal : radix is 16 ? tango.text.convert.Integer.Style.Hex : diff -r d2e87572b721 -r 5f2e72114476 dwt/graphics/GC.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dwt/graphics/GC.d Sat Jan 26 19:05:32 2008 +0100 @@ -0,0 +1,4836 @@ +/******************************************************************************* + * Copyright (c) 2000, 2007 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +module dwt.graphics.GC; + +//PORTING_TYPE +class GC{ +} + +/++ +import dwt.DWT; +import dwt.DWTError; +import dwt.DWTException; +import dwt.internal.Compatibility; +import dwt.internal.gdip.Gdip; +import dwt.internal.gdip.PointF; +import dwt.internal.gdip.Rect; +import dwt.internal.gdip.RectF; +import dwt.internal.win32.BITMAP; +import dwt.internal.win32.BITMAPINFOHEADER; +import dwt.internal.win32.BLENDFUNCTION; +import dwt.internal.win32.GRADIENT_RECT; +import dwt.internal.win32.ICONINFO; +import dwt.internal.win32.LOGBRUSH; +import dwt.internal.win32.LOGFONT; +import dwt.internal.win32.LOGFONTA; +import dwt.internal.win32.LOGFONTW; +import dwt.internal.win32.LOGPEN; +import dwt.internal.win32.OS; +import dwt.internal.win32.POINT; +import dwt.internal.win32.RECT; +import dwt.internal.win32.SIZE; +import dwt.internal.win32.TCHAR; +import dwt.internal.win32.TEXTMETRIC; +import dwt.internal.win32.TEXTMETRICA; +import dwt.internal.win32.TEXTMETRICW; +import dwt.internal.win32.TRIVERTEX; + +/** + * Class GC is where all of the drawing capabilities that are + * supported by DWT are located. Instances are used to draw on either an + * Image, a Control, or directly on a Display. + *
+ *
Styles:
+ *
LEFT_TO_RIGHT, RIGHT_TO_LEFT
+ *
+ * + *

+ * The DWT drawing coordinate system is the two-dimensional space with the origin + * (0,0) at the top left corner of the drawing area and with (x,y) values increasing + * to the right and downward respectively. + *

+ * + *

+ * Application code must explicitly invoke the GC.dispose() + * method to release the operating system resources managed by each instance + * when those instances are no longer required. This is particularly + * important on Windows95 and Windows98 where the operating system has a limited + * number of device contexts available. + *

+ * + *

+ * Note: Only one of LEFT_TO_RIGHT and RIGHT_TO_LEFT may be specified. + *

+ * + * @see dwt.events.PaintEvent + */ + +public final class GC extends Resource { + + /** + * the handle to the OS device context + * (Warning: This field is platform dependent) + *

+ * IMPORTANT: This field is not part of the DWT + * public API. It is marked public only so that it can be shared + * within the packages provided by DWT. It is not available on all + * platforms and should never be accessed from application code. + *

+ */ + 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 LINE_MITERLIMIT = 1 << 7; + static final int FOREGROUND_TEXT = 1 << 8; + static final int BACKGROUND_TEXT = 1 << 9; + static final int BRUSH = 1 << 10; + static final int PEN = 1 << 11; + static final int NULL_BRUSH = 1 << 12; + static final int NULL_PEN = 1 << 13; + static final int DRAW_OFFSET = 1 << 14; + + static final int DRAW = FOREGROUND | LINE_STYLE | LINE_WIDTH | LINE_CAP | LINE_JOIN | LINE_MITERLIMIT | PEN | NULL_BRUSH | DRAW_OFFSET; + static final int FILL = BACKGROUND | BRUSH | NULL_PEN; + + static final float[] LINE_DOT_ZERO = new float[]{3, 3}; + static final float[] LINE_DASH_ZERO = new float[]{18, 6}; + static final float[] LINE_DASHDOT_ZERO = new float[]{9, 6, 3, 6}; + static final float[] LINE_DASHDOTDOT_ZERO = new float[]{9, 3, 3, 3, 3, 3}; + +/** + * 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 color, background color and font in the GC + * to match those in the drawable. + *

+ * You must dispose the graphics context when it is no longer required. + *

+ * @param drawable the drawable to draw on + * @exception IllegalArgumentException + * @exception DWTError + */ +public GC(Drawable drawable) { + this(drawable, DWT.NONE); +} + +/** + * Constructs a new instance of this class which has been + * configured to draw on the specified drawable. Sets the + * foreground color, background color and font in the GC + * to match those in the drawable. + *

+ * You must dispose the graphics context when it is no longer required. + *

+ * + * @param drawable the drawable to draw on + * @param style the style of GC to construct + * + * @exception IllegalArgumentException + * @exception DWTError + * + * @since 2.1.2 + */ +public GC(Drawable drawable, int style) { + if (drawable is null) DWT.error(DWT.ERROR_NULL_ARGUMENT); + GCData data = new GCData (); + data.style = checkStyle(style); + int hDC = drawable.internal_new_GC(data); + Device device = data.device; + if (device is null) device = Device.getDevice(); + if (device is null) DWT.error(DWT.ERROR_NULL_ARGUMENT); + this.device = data.device = device; + init (drawable, data, hDC); + if (device.tracking) device.new_Object(this); +} + +static int checkStyle(int style) { + if ((style & DWT.LEFT_TO_RIGHT) !is 0) style &= ~DWT.RIGHT_TO_LEFT; + return style & (DWT.LEFT_TO_RIGHT | DWT.RIGHT_TO_LEFT); +} + +void checkGC(int mask) { + int state = data.state; + if ((state & mask) is mask) return; + state = (state ^ mask) & mask; + data.state |= mask; + int gdipGraphics = data.gdipGraphics; + if (gdipGraphics !is 0) { + int pen = data.gdipPen; + float width = data.lineWidth; + if ((state & FOREGROUND) !is 0 || (pen is 0 && (state & (LINE_WIDTH | LINE_STYLE | LINE_MITERLIMIT | LINE_JOIN | LINE_CAP)) !is 0)) { + if (data.gdipFgBrush !is 0) Gdip.SolidBrush_delete(data.gdipFgBrush); + data.gdipFgBrush = 0; + int brush; + Pattern pattern = data.foregroundPattern; + if (pattern !is null) { + brush = pattern.handle; + if ((data.style & DWT.MIRRORED) !is 0) { + switch (Gdip.Brush_GetType(brush)) { + case Gdip.BrushTypeTextureFill: + brush = Gdip.Brush_Clone(brush); + if (brush is 0) DWT.error(DWT.ERROR_NO_HANDLES); + Gdip.TextureBrush_ScaleTransform(brush, -1, 1, Gdip.MatrixOrderPrepend); + data.gdipFgBrush = brush; + } + } + } else { + int foreground = data.foreground; + int rgb = ((foreground >> 16) & 0xFF) | (foreground & 0xFF00) | ((foreground & 0xFF) << 16); + int color = Gdip.Color_new(data.alpha << 24 | rgb); + if (color is 0) DWT.error(DWT.ERROR_NO_HANDLES); + brush = Gdip.SolidBrush_new(color); + if (brush is 0) DWT.error(DWT.ERROR_NO_HANDLES); + Gdip.Color_delete(color); + data.gdipFgBrush = brush; + } + if (pen !is 0) { + Gdip.Pen_SetBrush(pen, brush); + } else { + pen = data.gdipPen = Gdip.Pen_new(brush, width); + } + } + if ((state & LINE_WIDTH) !is 0) { + Gdip.Pen_SetWidth(pen, width); + switch (data.lineStyle) { + case DWT.LINE_CUSTOM: + state |= LINE_STYLE; + } + } + if ((state & LINE_STYLE) !is 0) { + float[] dashes = null; + float dashOffset = 0; + int dashStyle = Gdip.DashStyleSolid; + switch (data.lineStyle) { + case DWT.LINE_SOLID: break; + case DWT.LINE_DOT: dashStyle = Gdip.DashStyleDot; if (width is 0) dashes = LINE_DOT_ZERO; break; + case DWT.LINE_DASH: dashStyle = Gdip.DashStyleDash; if (width is 0) dashes = LINE_DASH_ZERO; break; + case DWT.LINE_DASHDOT: dashStyle = Gdip.DashStyleDashDot; if (width is 0) dashes = LINE_DASHDOT_ZERO; break; + case DWT.LINE_DASHDOTDOT: dashStyle = Gdip.DashStyleDashDotDot; if (width is 0) dashes = LINE_DASHDOTDOT_ZERO; break; + case DWT.LINE_CUSTOM: { + if (data.lineDashes !is null) { + dashOffset = data.lineDashesOffset / Math.max (1, width); + dashes = new float[data.lineDashes.length * 2]; + for (int i = 0; i < data.lineDashes.length; i++) { + float dash = data.lineDashes[i] / Math.max (1, width); + dashes[i] = dash; + dashes[i + data.lineDashes.length] = dash; + } + } + } + } + if (dashes !is null) { + Gdip.Pen_SetDashPattern(pen, dashes, dashes.length); + Gdip.Pen_SetDashStyle(pen, Gdip.DashStyleCustom); + Gdip.Pen_SetDashOffset(pen, dashOffset); + } else { + Gdip.Pen_SetDashStyle(pen, dashStyle); + } + } + if ((state & LINE_MITERLIMIT) !is 0) { + Gdip.Pen_SetMiterLimit(pen, data.lineMiterLimit); + } + if ((state & LINE_JOIN) !is 0) { + int joinStyle = 0; + switch (data.lineJoin) { + case DWT.JOIN_MITER: joinStyle = Gdip.LineJoinMiter; break; + case DWT.JOIN_BEVEL: joinStyle = Gdip.LineJoinBevel; break; + case DWT.JOIN_ROUND: joinStyle = Gdip.LineJoinRound; break; + } + Gdip.Pen_SetLineJoin(pen, joinStyle); + } + if ((state & LINE_CAP) !is 0) { + int dashCap = Gdip.DashCapFlat, capStyle = 0; + switch (data.lineCap) { + case DWT.CAP_FLAT: capStyle = Gdip.LineCapFlat; break; + case DWT.CAP_ROUND: capStyle = Gdip.LineCapRound; dashCap = Gdip.DashCapRound; break; + case DWT.CAP_SQUARE: capStyle = Gdip.LineCapSquare; break; + } + Gdip.Pen_SetLineCap(pen, capStyle, capStyle, dashCap); + } + if ((state & BACKGROUND) !is 0) { + if (data.gdipBgBrush !is 0) Gdip.SolidBrush_delete(data.gdipBgBrush); + data.gdipBgBrush = 0; + Pattern pattern = data.backgroundPattern; + if (pattern !is null) { + data.gdipBrush = pattern.handle; + if ((data.style & DWT.MIRRORED) !is 0) { + switch (Gdip.Brush_GetType(data.gdipBrush)) { + case Gdip.BrushTypeTextureFill: + int brush = Gdip.Brush_Clone(data.gdipBrush); + if (brush is 0) DWT.error(DWT.ERROR_NO_HANDLES); + Gdip.TextureBrush_ScaleTransform(brush, -1, 1, Gdip.MatrixOrderPrepend); + data.gdipBrush = data.gdipBgBrush = brush; + } + } + } else { + int background = data.background; + int rgb = ((background >> 16) & 0xFF) | (background & 0xFF00) | ((background & 0xFF) << 16); + int color = Gdip.Color_new(data.alpha << 24 | rgb); + if (color is 0) DWT.error(DWT.ERROR_NO_HANDLES); + int brush = Gdip.SolidBrush_new(color); + if (brush is 0) DWT.error(DWT.ERROR_NO_HANDLES); + Gdip.Color_delete(color); + data.gdipBrush = data.gdipBgBrush = brush; + } + } + if ((state & FONT) !is 0) { + OS.SelectObject(handle, data.hFont); + int font = createGdipFont(handle, data.hFont); + if (data.gdipFont !is 0) Gdip.Font_delete(data.gdipFont); + data.gdipFont = font; + } + if ((state & DRAW_OFFSET) !is 0) { + data.gdipXOffset = data.gdipYOffset = 0; + int matrix = Gdip.Matrix_new(1, 0, 0, 1, 0, 0); + float[] elements = new float[6]; + Gdip.Graphics_GetTransform(gdipGraphics, matrix); + Gdip.Matrix_GetElements(matrix, elements); + Gdip.Matrix_delete(matrix); + float scaling = elements[0]; + if (scaling < 0) scaling = -scaling; + float penWidth = data.lineWidth * scaling; + if (penWidth is 0 || ((int)penWidth % 2) is 1) { + data.gdipXOffset = 0.5f / scaling; + } + scaling = elements[3]; + if (scaling < 0) scaling = -scaling; + penWidth = data.lineWidth * scaling; + if (penWidth is 0 || ((int)penWidth % 2) is 1) { + data.gdipYOffset = 0.5f / scaling; + } + } + return; + } + if ((state & (FOREGROUND | LINE_CAP | LINE_JOIN | LINE_STYLE | LINE_WIDTH)) !is 0) { + int color = data.foreground; + int width = (int)data.lineWidth; + int[] dashes = null; + int lineStyle = OS.PS_SOLID; + switch (data.lineStyle) { + case DWT.LINE_SOLID: break; + case DWT.LINE_DASH: lineStyle = OS.PS_DASH; break; + case DWT.LINE_DOT: lineStyle = OS.PS_DOT; break; + case DWT.LINE_DASHDOT: lineStyle = OS.PS_DASHDOT; break; + case DWT.LINE_DASHDOTDOT: lineStyle = OS.PS_DASHDOTDOT; break; + case DWT.LINE_CUSTOM: { + if (data.lineDashes !is null) { + lineStyle = OS.PS_USERSTYLE; + dashes = new int[data.lineDashes.length]; + for (int i = 0; i < dashes.length; i++) { + dashes[i] = (int)data.lineDashes[i]; + } + } + break; + } + } + if ((state & LINE_STYLE) !is 0) { + OS.SetBkMode(handle, data.lineStyle is DWT.LINE_SOLID ? OS.OPAQUE : OS.TRANSPARENT); + } + int joinStyle = 0; + switch (data.lineJoin) { + case DWT.JOIN_MITER: joinStyle = OS.PS_JOIN_MITER; break; + case DWT.JOIN_ROUND: joinStyle = OS.PS_JOIN_ROUND; break; + case DWT.JOIN_BEVEL: joinStyle = OS.PS_JOIN_BEVEL; break; + } + int capStyle = 0; + switch (data.lineCap) { + case DWT.CAP_ROUND: capStyle = OS.PS_ENDCAP_ROUND; break; + case DWT.CAP_FLAT: capStyle = OS.PS_ENDCAP_FLAT; break; + case DWT.CAP_SQUARE: capStyle = OS.PS_ENDCAP_SQUARE;break; + } + int style = lineStyle | joinStyle | capStyle; + /* + * Feature in Windows. Windows does not honour line styles other then + * PS_SOLID for pens wider than 1 pixel created with CreatePen(). The fix + * is to use ExtCreatePen() instead. + */ + int newPen; + if (OS.IsWinCE || (width is 0 && lineStyle !is OS.PS_USERSTYLE) || style is 0) { + newPen = OS.CreatePen(style & OS.PS_STYLE_MASK, width, color); + } else { + LOGBRUSH logBrush = new LOGBRUSH(); + logBrush.lbStyle = OS.BS_SOLID; + logBrush.lbColor = color; + /* Feature in Windows. PS_GEOMETRIC pens cannot have zero width. */ + newPen = OS.ExtCreatePen (style | OS.PS_GEOMETRIC, Math.max(1, width), logBrush, dashes !is null ? dashes.length : 0, dashes); + } + OS.SelectObject(handle, newPen); + data.state |= PEN; + data.state &= ~NULL_PEN; + if (data.hPen !is 0) OS.DeleteObject(data.hPen); + data.hPen = data.hOldPen = newPen; + } else if ((state & PEN) !is 0) { + OS.SelectObject(handle, data.hOldPen); + data.state &= ~NULL_PEN; + } else if ((state & NULL_PEN) !is 0) { + data.hOldPen = OS.SelectObject(handle, OS.GetStockObject(OS.NULL_PEN)); + data.state &= ~PEN; + } + if ((state & BACKGROUND) !is 0) { + int newBrush = OS.CreateSolidBrush(data.background); + OS.SelectObject(handle, newBrush); + data.state |= BRUSH; + data.state &= ~NULL_BRUSH; + if (data.hBrush !is 0) OS.DeleteObject(data.hBrush); + data.hOldBrush = data.hBrush = newBrush; + } else if ((state & BRUSH) !is 0) { + OS.SelectObject(handle, data.hOldBrush); + data.state &= ~NULL_BRUSH; + } else if ((state & NULL_BRUSH) !is 0) { + data.hOldBrush = OS.SelectObject(handle, OS.GetStockObject(OS.NULL_BRUSH)); + data.state &= ~BRUSH; + } + if ((state & BACKGROUND_TEXT) !is 0) { + OS.SetBkColor(handle, data.background); + } + if ((state & FOREGROUND_TEXT) !is 0) { + OS.SetTextColor(handle, data.foreground); + } + if ((state & FONT) !is 0) { + OS.SelectObject(handle, data.hFont); + } +} + +/** + * Copies a rectangular area of the receiver at the specified + * position into the image, which must be of type DWT.BITMAP. + * + * @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 + * @exception DWTException + */ +public void copyArea(Image image, int x, int y) { + if (handle is 0) DWT.error(DWT.ERROR_GRAPHIC_DISPOSED); + if (image is null) DWT.error(DWT.ERROR_NULL_ARGUMENT); + if (image.type !is DWT.BITMAP || image.isDisposed()) DWT.error(DWT.ERROR_INVALID_ARGUMENT); + + /* Copy the bitmap area */ + Rectangle rect = image.getBounds(); + int memHdc = OS.CreateCompatibleDC(handle); + int hOldBitmap = OS.SelectObject(memHdc, image.handle); + OS.BitBlt(memHdc, 0, 0, rect.width, rect.height, handle, x, y, OS.SRCCOPY); + OS.SelectObject(memHdc, hOldBitmap); + OS.DeleteDC(memHdc); +} + +/** + * Copies a rectangular area of the receiver at the source + * position onto the receiver at the destination position. + * + * @param srcX the x coordinate in the receiver of the area to be copied + * @param srcY the y coordinate in the receiver of the area to be copied + * @param width the width of the area to copy + * @param height the height of the area to copy + * @param destX the x coordinate in the receiver of the area to copy to + * @param destY the y coordinate in the receiver of the area to copy to + * + * @exception DWTException + */ +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 true paint events will be generated for old and obscured areas + * + * @exception DWTException + * + * @since 3.1 + */ +public void copyArea(int srcX, int srcY, int width, int height, int destX, int destY, bool paint) { + if (handle is 0) DWT.error(DWT.ERROR_GRAPHIC_DISPOSED); + + /* + * 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 is 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) is 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 is 0 && OS.IsWinCE) { + OS.BitBlt(handle, destX, destY, width, height, handle, srcX, srcY, OS.SRCCOPY); + if (paint) { + int deltaX = destX - srcX, deltaY = destY - srcY; + bool disjoint = (destX + width < srcX) || (srcX + width < destX) || (destY + height < srcY) || (srcY + height < destY); + if (disjoint) { + OS.InvalidateRect(hwnd, lprcScroll, true); + } else { + if (deltaX !is 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 !is 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); + } + } + } + } + } +} + +static int createGdipFont(int hDC, int hFont) { + int font = Gdip.Font_new(hDC, hFont); + if (font is 0) DWT.error(DWT.ERROR_NO_HANDLES); + if (!Gdip.Font_IsAvailable(font)) { + Gdip.Font_delete(font); + LOGFONT logFont = OS.IsUnicode ? (LOGFONT)new LOGFONTW() : new LOGFONTA(); + OS.GetObject(hFont, LOGFONT.sizeof, logFont); + int size = Math.abs(logFont.lfHeight); + int style = Gdip.FontStyleRegular; + if (logFont.lfWeight is 700) style |= Gdip.FontStyleBold; + if (logFont.lfItalic !is 0) style |= Gdip.FontStyleItalic; + char[] chars; + if (OS.IsUnicode) { + chars = ((LOGFONTW)logFont).lfFaceName; + } else { + chars = new char[OS.LF_FACESIZE]; + byte[] bytes = ((LOGFONTA)logFont).lfFaceName; + OS.MultiByteToWideChar (OS.CP_ACP, OS.MB_PRECOMPOSED, bytes, bytes.length, chars, chars.length); + } + int index = 0; + while (index < chars.length) { + if (chars [index] is 0) break; + index++; + } + String name = new String (chars, 0, index); + if (Compatibility.equalsIgnoreCase(name, "Courier")) { //$NON-NLS-1$ + name = "Courier New"; //$NON-NLS-1$ + } + char[] buffer = new char[name.length() + 1]; + name.getChars(0, name.length(), buffer, 0); + font = Gdip.Font_new(buffer, size, style, Gdip.UnitPixel, 0); + } + if (font is 0) DWT.error(DWT.ERROR_NO_HANDLES); + return font; +} + +static void destroyGdipBrush(int brush) { + int type = Gdip.Brush_GetType(brush); + switch (type) { + case Gdip.BrushTypeSolidColor: + Gdip.SolidBrush_delete(brush); + break; + case Gdip.BrushTypeHatchFill: + Gdip.HatchBrush_delete(brush); + break; + case Gdip.BrushTypeLinearGradient: + Gdip.LinearGradientBrush_delete(brush); + break; + case Gdip.BrushTypeTextureFill: + Gdip.TextureBrush_delete(brush); + break; + } +} + +/** + * Disposes of the operating system resources associated with + * the graphics context. Applications must dispose of all GCs + * which they allocate. + * + * @exception DWTError + */ +public void dispose() { + if (handle is 0) return; + if (data.device.isDisposed()) return; + + disposeGdip(); + + /* Select stock pen and brush objects and free resources */ + if (data.hPen !is 0) { + OS.SelectObject(handle, OS.GetStockObject(OS.NULL_PEN)); + OS.DeleteObject(data.hPen); + data.hPen = 0; + } + if (data.hBrush !is 0) { + OS.SelectObject(handle, OS.GetStockObject(OS.NULL_BRUSH)); + OS.DeleteObject(data.hBrush); + data.hBrush = 0; + } + + /* + * Put back the original bitmap into the device context. + * This will ensure that we have not left a bitmap + * selected in it when we delete the HDC. + */ + int hNullBitmap = data.hNullBitmap; + if (hNullBitmap !is 0) { + OS.SelectObject(handle, hNullBitmap); + data.hNullBitmap = 0; + } + Image image = data.image; + if (image !is null) image.memGC = null; + + /* + * Dispose the HDC. + */ + Device device = data.device; + if (drawable !is null) drawable.internal_dispose_GC(handle, data); + drawable = null; + handle = 0; + data.image = null; + data.ps = null; + if (device.tracking) device.dispose_Object(this); + data.device = null; + data = null; +} + +void disposeGdip() { + if (data.gdipPen !is 0) Gdip.Pen_delete(data.gdipPen); + if (data.gdipBgBrush !is 0) destroyGdipBrush(data.gdipBgBrush); + if (data.gdipFgBrush !is 0) destroyGdipBrush(data.gdipFgBrush); + if (data.gdipFont !is 0) Gdip.Font_delete(data.gdipFont); + if (data.gdipGraphics !is 0) Gdip.Graphics_delete(data.gdipGraphics); + data.gdipGraphics = data.gdipBrush = data.gdipBgBrush = data.gdipFgBrush = + data.gdipFont = data.gdipPen = 0; +} + +/** + * Draws the outline of a circular or elliptical arc + * within the specified rectangular area. + *

+ * The resulting arc begins at startAngle and extends + * for arcAngle 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. + *

+ * The center of the arc is the center of the rectangle whose origin + * is (x, y) and whose size is specified by the + * width and height arguments. + *

+ * The resulting arc covers an area width + 1 pixels wide + * by height + 1 pixels tall. + *

+ * + * @param x the x coordinate of the upper-left corner of the arc to be drawn + * @param y the y coordinate of the upper-left corner of the arc to be drawn + * @param width the width of the arc to be drawn + * @param height the height of the arc to be drawn + * @param startAngle the beginning angle + * @param arcAngle the angular extent of the arc, relative to the start angle + * + * @exception DWTException + */ +public void drawArc (int x, int y, int width, int height, int startAngle, int arcAngle) { + if (handle is 0) DWT.error(DWT.ERROR_GRAPHIC_DISPOSED); + checkGC(DRAW); + if (width < 0) { + x = x + width; + width = -width; + } + if (height < 0) { + y = y + height; + height = -height; + } + if (width is 0 || height is 0 || arcAngle is 0) return; + int gdipGraphics = data.gdipGraphics; + if (gdipGraphics !is 0) { + Gdip.Graphics_TranslateTransform(gdipGraphics, data.gdipXOffset, data.gdipYOffset, Gdip.MatrixOrderPrepend); + if (width is height) { + Gdip.Graphics_DrawArc(gdipGraphics, data.gdipPen, x, y, width, height, -startAngle, -arcAngle); + } else { + int path = Gdip.GraphicsPath_new(Gdip.FillModeAlternate); + if (path is 0) DWT.error(DWT.ERROR_NO_HANDLES); + int matrix = Gdip.Matrix_new(width, 0, 0, height, x, y); + if (matrix is 0) DWT.error(DWT.ERROR_NO_HANDLES); + Gdip.GraphicsPath_AddArc(path, 0, 0, 1, 1, -startAngle, -arcAngle); + Gdip.GraphicsPath_Transform(path, matrix); + Gdip.Graphics_DrawPath(gdipGraphics, data.gdipPen, path); + Gdip.Matrix_delete(matrix); + Gdip.GraphicsPath_delete(path); + } + Gdip.Graphics_TranslateTransform(gdipGraphics, -data.gdipXOffset, -data.gdipYOffset, Gdip.MatrixOrderPrepend); + return; + } + if ((data.style & DWT.MIRRORED) !is 0) { + if (data.lineWidth !is 0 && data.lineWidth % 2 is 0) x--; + } + /* + * Feature in WinCE. The function Arc is not present in the + * WinCE SDK. The fix is to emulate arc drawing by using + * Polyline. + */ + if (OS.IsWinCE) { + /* compute arc with a simple linear interpolation */ + if (arcAngle < 0) { + startAngle += arcAngle; + arcAngle = -arcAngle; + } + if (arcAngle > 360) arcAngle = 360; + int[] points = new int[(arcAngle + 1) * 2]; + int cteX = 2 * x + width; + int cteY = 2 * y + height; + int index = 0; + for (int i = 0; i <= arcAngle; i++) { + points[index++] = (Compatibility.cos(startAngle + i, width) + cteX) >> 1; + points[index++] = (cteY - Compatibility.sin(startAngle + i, height)) >> 1; + } + OS.Polyline(handle, points, points.length / 2); + } else { + int x1, y1, x2, y2,tmp; + bool isNegative; + if (arcAngle >= 360 || arcAngle <= -360) { + x1 = x2 = x + width; + y1 = y2 = y + height / 2; + } else { + isNegative = arcAngle < 0; + + arcAngle = arcAngle + startAngle; + if (isNegative) { + // swap angles + tmp = startAngle; + startAngle = arcAngle; + arcAngle = tmp; + } + x1 = Compatibility.cos(startAngle, width) + x + width/2; + y1 = -1 * Compatibility.sin(startAngle, height) + y + height/2; + + x2 = Compatibility.cos(arcAngle, width) + x + width/2; + y2 = -1 * Compatibility.sin(arcAngle, height) + y + height/2; + } + OS.Arc(handle, x, y, x + width + 1, y + height + 1, x1, y1, x2, y2); + } +} + +/** + * Draws a rectangle, based on the specified arguments, which has + * the appearance of the platform's focus rectangle if the + * platform supports such a notion, and otherwise draws a simple + * rectangle in the receiver's foreground color. + * + * @param x the x coordinate of the rectangle + * @param y the y coordinate of the rectangle + * @param width the width of the rectangle + * @param height the height of the rectangle + * + * @exception DWTException + * + * @see #drawRectangle(int, int, int, int) + */ +public void drawFocus (int x, int y, int width, int height) { + if (handle is 0) DWT.error(DWT.ERROR_GRAPHIC_DISPOSED); + if ((data.uiState & OS.UISF_HIDEFOCUS) !is 0) return; + int hdc = handle, state = 0; + int gdipGraphics = data.gdipGraphics; + if (gdipGraphics !is 0) { + int clipRgn = 0; + Gdip.Graphics_SetPixelOffsetMode(gdipGraphics, Gdip.PixelOffsetModeNone); + int rgn = Gdip.Region_new(); + if (rgn is 0) DWT.error(DWT.ERROR_NO_HANDLES); + Gdip.Graphics_GetClip(gdipGraphics, rgn); + if (!Gdip.Region_IsInfinite(rgn, gdipGraphics)) { + clipRgn = Gdip.Region_GetHRGN(rgn, gdipGraphics); + } + Gdip.Region_delete(rgn); + Gdip.Graphics_SetPixelOffsetMode(gdipGraphics, Gdip.PixelOffsetModeHalf); + float[] lpXform = null; + int matrix = Gdip.Matrix_new(1, 0, 0, 1, 0, 0); + if (matrix is 0) DWT.error(DWT.ERROR_NO_HANDLES); + Gdip.Graphics_GetTransform(gdipGraphics, matrix); + if (!Gdip.Matrix_IsIdentity(matrix)) { + lpXform = new float[6]; + Gdip.Matrix_GetElements(matrix, lpXform); + } + Gdip.Matrix_delete(matrix); + hdc = Gdip.Graphics_GetHDC(gdipGraphics); + state = OS.SaveDC(hdc); + OS.SetBkColor(hdc, data.background); + OS.SetTextColor(hdc, data.foreground); + if (lpXform !is null) { + OS.SetGraphicsMode(hdc, OS.GM_ADVANCED); + OS.SetWorldTransform(hdc, lpXform); + } + if (clipRgn !is 0) { + OS.SelectClipRgn(hdc, clipRgn); + OS.DeleteObject(clipRgn); + } + } + RECT rect = new RECT(); + OS.SetRect(rect, x, y, x + width, y + height); + OS.DrawFocusRect(hdc, rect); + if (gdipGraphics !is 0) { + OS.RestoreDC(hdc, state); + Gdip.Graphics_ReleaseHDC(gdipGraphics, hdc); + } +} + +/** + * 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