Mercurial > projects > dwt2
comparison org.eclipse.swt.win32.win32.x86/src/org/eclipse/swt/graphics/GC.d @ 0:6dd524f61e62
add dwt win and basic java stuff
author | Frank Benoit <benoit@tionex.de> |
---|---|
date | Mon, 02 Mar 2009 14:44:16 +0100 |
parents | |
children | 6bf2837c50fe |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:6dd524f61e62 |
---|---|
1 /******************************************************************************* | |
2 * Copyright (c) 2000, 2008 IBM Corporation and others. | |
3 * All rights reserved. This program and the accompanying materials | |
4 * are made available under the terms of the Eclipse Public License v1.0 | |
5 * which accompanies this distribution, and is available at | |
6 * http://www.eclipse.org/legal/epl-v10.html | |
7 * | |
8 * Contributors: | |
9 * IBM Corporation - initial API and implementation | |
10 * Port to the D programming language: | |
11 * Frank Benoit <benoit@tionex.de> | |
12 *******************************************************************************/ | |
13 module org.eclipse.swt.graphics.GC; | |
14 | |
15 import org.eclipse.swt.SWT; | |
16 import org.eclipse.swt.SWTError; | |
17 import org.eclipse.swt.SWTException; | |
18 import org.eclipse.swt.internal.Compatibility; | |
19 import org.eclipse.swt.internal.gdip.Gdip; | |
20 import org.eclipse.swt.internal.win32.OS; | |
21 | |
22 import org.eclipse.swt.graphics.Color; | |
23 import org.eclipse.swt.graphics.Drawable; | |
24 import org.eclipse.swt.graphics.Resource; | |
25 import org.eclipse.swt.graphics.Device; | |
26 import org.eclipse.swt.graphics.Font; | |
27 import org.eclipse.swt.graphics.FontMetrics; | |
28 import org.eclipse.swt.graphics.GCData; | |
29 import org.eclipse.swt.graphics.Image; | |
30 import org.eclipse.swt.graphics.ImageData; | |
31 import org.eclipse.swt.graphics.Path; | |
32 import org.eclipse.swt.graphics.Pattern; | |
33 import org.eclipse.swt.graphics.Point; | |
34 import org.eclipse.swt.graphics.RGB; | |
35 import org.eclipse.swt.graphics.Rectangle; | |
36 import org.eclipse.swt.graphics.Region; | |
37 import org.eclipse.swt.graphics.Resource; | |
38 import org.eclipse.swt.graphics.Transform; | |
39 import org.eclipse.swt.graphics.LineAttributes; | |
40 | |
41 import java.lang.all; | |
42 import tango.text.convert.Format; | |
43 | |
44 /** | |
45 * Class <code>GC</code> is where all of the drawing capabilities that are | |
46 * supported by SWT are located. Instances are used to draw on either an | |
47 * <code>Image</code>, a <code>Control</code>, or directly on a <code>Display</code>. | |
48 * <dl> | |
49 * <dt><b>Styles:</b></dt> | |
50 * <dd>LEFT_TO_RIGHT, RIGHT_TO_LEFT</dd> | |
51 * </dl> | |
52 * | |
53 * <p> | |
54 * The SWT drawing coordinate system is the two-dimensional space with the origin | |
55 * (0,0) at the top left corner of the drawing area and with (x,y) values increasing | |
56 * to the right and downward respectively. | |
57 * </p> | |
58 * | |
59 * <p> | |
60 * Application code must explicitly invoke the <code>GC.dispose()</code> | |
61 * method to release the operating system resources managed by each instance | |
62 * when those instances are no longer required. This is <em>particularly</em> | |
63 * important on Windows95 and Windows98 where the operating system has a limited | |
64 * number of device contexts available. | |
65 * </p> | |
66 * | |
67 * <p> | |
68 * Note: Only one of LEFT_TO_RIGHT and RIGHT_TO_LEFT may be specified. | |
69 * </p> | |
70 * | |
71 * @see org.eclipse.swt.events.PaintEvent | |
72 * @see <a href="http://www.eclipse.org/swt/snippets/#gc">GC snippets</a> | |
73 * @see <a href="http://www.eclipse.org/swt/examples.php">SWT Examples: GraphicsExample, PaintExample</a> | |
74 * @see <a href="http://www.eclipse.org/swt/">Sample code and further information</a> | |
75 */ | |
76 | |
77 public final class GC : Resource { | |
78 | |
79 alias Resource.init_ init_; | |
80 | |
81 /** | |
82 * the handle to the OS device context | |
83 * (Warning: This field is platform dependent) | |
84 * <p> | |
85 * <b>IMPORTANT:</b> This field is <em>not</em> part of the SWT | |
86 * public API. It is marked public only so that it can be shared | |
87 * within the packages provided by SWT. It is not available on all | |
88 * platforms and should never be accessed from application code. | |
89 * </p> | |
90 */ | |
91 public HDC handle; | |
92 | |
93 Drawable drawable; | |
94 GCData data; | |
95 | |
96 static const int FOREGROUND = 1 << 0; | |
97 static const int BACKGROUND = 1 << 1; | |
98 static const int FONT = 1 << 2; | |
99 static const int LINE_STYLE = 1 << 3; | |
100 static const int LINE_WIDTH = 1 << 4; | |
101 static const int LINE_CAP = 1 << 5; | |
102 static const int LINE_JOIN = 1 << 6; | |
103 static const int LINE_MITERLIMIT = 1 << 7; | |
104 static const int FOREGROUND_TEXT = 1 << 8; | |
105 static const int BACKGROUND_TEXT = 1 << 9; | |
106 static const int BRUSH = 1 << 10; | |
107 static const int PEN = 1 << 11; | |
108 static const int NULL_BRUSH = 1 << 12; | |
109 static const int NULL_PEN = 1 << 13; | |
110 static const int DRAW_OFFSET = 1 << 14; | |
111 | |
112 static const int DRAW = FOREGROUND | LINE_STYLE | LINE_WIDTH | LINE_CAP | LINE_JOIN | LINE_MITERLIMIT | PEN | NULL_BRUSH | DRAW_OFFSET; | |
113 static const int FILL = BACKGROUND | BRUSH | NULL_PEN; | |
114 | |
115 static const float[] LINE_DOT_ZERO = [3, 3]; | |
116 static const float[] LINE_DASH_ZERO = [18, 6]; | |
117 static const float[] LINE_DASHDOT_ZERO = [9, 6, 3, 6]; | |
118 static const float[] LINE_DASHDOTDOT_ZERO = [9, 3, 3, 3, 3, 3]; | |
119 | |
120 /** | |
121 * Prevents uninitialized instances from being created outside the package. | |
122 */ | |
123 this() { | |
124 } | |
125 | |
126 /** | |
127 * Constructs a new instance of this class which has been | |
128 * configured to draw on the specified drawable. Sets the | |
129 * foreground color, background color and font in the GC | |
130 * to match those in the drawable. | |
131 * <p> | |
132 * You must dispose the graphics context when it is no longer required. | |
133 * </p> | |
134 * @param drawable the drawable to draw on | |
135 * @exception IllegalArgumentException <ul> | |
136 * <li>ERROR_NULL_ARGUMENT - if the drawable is null</li> | |
137 * <li>ERROR_NULL_ARGUMENT - if there is no current device</li> | |
138 * <li>ERROR_INVALID_ARGUMENT | |
139 * - if the drawable is an image that is not a bitmap or an icon | |
140 * - if the drawable is an image or printer that is already selected | |
141 * into another graphics context</li> | |
142 * </ul> | |
143 * @exception SWTError <ul> | |
144 * <li>ERROR_NO_HANDLES if a handle could not be obtained for GC creation</li> | |
145 * <li>ERROR_THREAD_INVALID_ACCESS if not called from the thread that created the drawable</li> | |
146 * </ul> | |
147 */ | |
148 public this(Drawable drawable) { | |
149 this(drawable, SWT.NONE); | |
150 } | |
151 | |
152 /** | |
153 * Constructs a new instance of this class which has been | |
154 * configured to draw on the specified drawable. Sets the | |
155 * foreground color, background color and font in the GC | |
156 * to match those in the drawable. | |
157 * <p> | |
158 * You must dispose the graphics context when it is no longer required. | |
159 * </p> | |
160 * | |
161 * @param drawable the drawable to draw on | |
162 * @param style the style of GC to construct | |
163 * | |
164 * @exception IllegalArgumentException <ul> | |
165 * <li>ERROR_NULL_ARGUMENT - if the drawable is null</li> | |
166 * <li>ERROR_NULL_ARGUMENT - if there is no current device</li> | |
167 * <li>ERROR_INVALID_ARGUMENT | |
168 * - if the drawable is an image that is not a bitmap or an icon | |
169 * - if the drawable is an image or printer that is already selected | |
170 * into another graphics context</li> | |
171 * </ul> | |
172 * @exception SWTError <ul> | |
173 * <li>ERROR_NO_HANDLES if a handle could not be obtained for GC creation</li> | |
174 * <li>ERROR_THREAD_INVALID_ACCESS if not called from the thread that created the drawable</li> | |
175 * </ul> | |
176 * | |
177 * @since 2.1.2 | |
178 */ | |
179 public this(Drawable drawable, int style) { | |
180 if (drawable is null) SWT.error(SWT.ERROR_NULL_ARGUMENT); | |
181 GCData data = new GCData (); | |
182 data.style = checkStyle(style); | |
183 auto hDC = drawable.internal_new_GC(data); | |
184 Device device = data.device; | |
185 if (device is null) device = Device.getDevice(); | |
186 if (device is null) SWT.error(SWT.ERROR_NULL_ARGUMENT); | |
187 this.device = data.device = device; | |
188 init_ (drawable, data, hDC); | |
189 init_(); | |
190 } | |
191 | |
192 static int checkStyle(int style) { | |
193 if ((style & SWT.LEFT_TO_RIGHT) !is 0) style &= ~SWT.RIGHT_TO_LEFT; | |
194 return style & (SWT.LEFT_TO_RIGHT | SWT.RIGHT_TO_LEFT); | |
195 } | |
196 | |
197 void checkGC(int mask) { | |
198 int state = data.state; | |
199 if ((state & mask) is mask) return; | |
200 state = (state ^ mask) & mask; | |
201 data.state |= mask; | |
202 auto gdipGraphics = data.gdipGraphics; | |
203 if (gdipGraphics !is null) { | |
204 auto pen = data.gdipPen; | |
205 float width = data.lineWidth; | |
206 if ((state & FOREGROUND) !is 0 || (pen is null && (state & (LINE_WIDTH | LINE_STYLE | LINE_MITERLIMIT | LINE_JOIN | LINE_CAP)) !is 0)) { | |
207 if (data.gdipFgBrush !is null) Gdip.SolidBrush_delete(data.gdipFgBrush); | |
208 data.gdipFgBrush = null; | |
209 Gdip.Brush brush; | |
210 Pattern pattern = data.foregroundPattern; | |
211 if (pattern !is null) { | |
212 brush = pattern.handle; | |
213 if ((data.style & SWT.MIRRORED) !is 0) { | |
214 switch (Gdip.Brush_GetType(brush)) { | |
215 case Gdip.BrushTypeTextureFill: | |
216 brush = Gdip.Brush_Clone(brush); | |
217 if (brush is null) SWT.error(SWT.ERROR_NO_HANDLES); | |
218 Gdip.TextureBrush_ScaleTransform( cast(Gdip.TextureBrush) brush, -1, 1, Gdip.MatrixOrderPrepend); | |
219 data.gdipFgBrush = cast(Gdip.SolidBrush)brush; | |
220 default: | |
221 } | |
222 } | |
223 } else { | |
224 auto foreground = data.foreground; | |
225 int rgb = ((foreground >> 16) & 0xFF) | (foreground & 0xFF00) | ((foreground & 0xFF) << 16); | |
226 auto color = Gdip.Color_new(data.alpha << 24 | rgb); | |
227 if (color is 0) SWT.error(SWT.ERROR_NO_HANDLES); | |
228 brush = cast(Gdip.Brush) Gdip.SolidBrush_new(color); | |
229 if (brush is null) SWT.error(SWT.ERROR_NO_HANDLES); | |
230 Gdip.Color_delete(color); | |
231 data.gdipFgBrush = cast(Gdip.SolidBrush)brush; | |
232 } | |
233 if (pen !is null) { | |
234 Gdip.Pen_SetBrush(pen, brush); | |
235 } else { | |
236 pen = data.gdipPen = Gdip.Pen_new(brush, width); | |
237 } | |
238 } | |
239 if ((state & LINE_WIDTH) !is 0) { | |
240 Gdip.Pen_SetWidth(pen, width); | |
241 switch (data.lineStyle) { | |
242 case SWT.LINE_CUSTOM: | |
243 state |= LINE_STYLE; | |
244 default: | |
245 } | |
246 } | |
247 if ((state & LINE_STYLE) !is 0) { | |
248 float[] dashes = null; | |
249 float dashOffset = 0; | |
250 int dashStyle = Gdip.DashStyleSolid; | |
251 switch (data.lineStyle) { | |
252 case SWT.LINE_SOLID: break; | |
253 case SWT.LINE_DOT: dashStyle = Gdip.DashStyleDot; if (width is 0) dashes = LINE_DOT_ZERO; break; | |
254 case SWT.LINE_DASH: dashStyle = Gdip.DashStyleDash; if (width is 0) dashes = LINE_DASH_ZERO; break; | |
255 case SWT.LINE_DASHDOT: dashStyle = Gdip.DashStyleDashDot; if (width is 0) dashes = LINE_DASHDOT_ZERO; break; | |
256 case SWT.LINE_DASHDOTDOT: dashStyle = Gdip.DashStyleDashDotDot; if (width is 0) dashes = LINE_DASHDOTDOT_ZERO; break; | |
257 case SWT.LINE_CUSTOM: { | |
258 if (data.lineDashes !is null) { | |
259 dashOffset = data.lineDashesOffset / Math.max (1, width); | |
260 dashes = new float[data.lineDashes.length * 2]; | |
261 for (int i = 0; i < data.lineDashes.length; i++) { | |
262 float dash = data.lineDashes[i] / Math.max (1, width); | |
263 dashes[i] = dash; | |
264 dashes[i + data.lineDashes.length] = dash; | |
265 } | |
266 } | |
267 } | |
268 default: | |
269 } | |
270 if (dashes !is null) { | |
271 Gdip.Pen_SetDashPattern(pen, dashes.ptr, dashes.length); | |
272 Gdip.Pen_SetDashStyle(pen, Gdip.DashStyleCustom); | |
273 Gdip.Pen_SetDashOffset(pen, dashOffset); | |
274 } else { | |
275 Gdip.Pen_SetDashStyle(pen, dashStyle); | |
276 } | |
277 } | |
278 if ((state & LINE_MITERLIMIT) !is 0) { | |
279 Gdip.Pen_SetMiterLimit(pen, data.lineMiterLimit); | |
280 } | |
281 if ((state & LINE_JOIN) !is 0) { | |
282 int joinStyle = 0; | |
283 switch (data.lineJoin) { | |
284 case SWT.JOIN_MITER: joinStyle = Gdip.LineJoinMiter; break; | |
285 case SWT.JOIN_BEVEL: joinStyle = Gdip.LineJoinBevel; break; | |
286 case SWT.JOIN_ROUND: joinStyle = Gdip.LineJoinRound; break; | |
287 default: | |
288 } | |
289 Gdip.Pen_SetLineJoin(pen, joinStyle); | |
290 } | |
291 if ((state & LINE_CAP) !is 0) { | |
292 int dashCap = Gdip.DashCapFlat, capStyle = 0; | |
293 switch (data.lineCap) { | |
294 case SWT.CAP_FLAT: capStyle = Gdip.LineCapFlat; break; | |
295 case SWT.CAP_ROUND: capStyle = Gdip.LineCapRound; dashCap = Gdip.DashCapRound; break; | |
296 case SWT.CAP_SQUARE: capStyle = Gdip.LineCapSquare; break; | |
297 default: | |
298 } | |
299 Gdip.Pen_SetLineCap(pen, capStyle, capStyle, dashCap); | |
300 } | |
301 if ((state & BACKGROUND) !is 0) { | |
302 if (data.gdipBgBrush !is null) Gdip.SolidBrush_delete(data.gdipBgBrush); | |
303 data.gdipBgBrush = null; | |
304 Pattern pattern = data.backgroundPattern; | |
305 if (pattern !is null) { | |
306 data.gdipBrush = pattern.handle; | |
307 if ((data.style & SWT.MIRRORED) !is 0) { | |
308 switch (Gdip.Brush_GetType(data.gdipBrush)) { | |
309 case Gdip.BrushTypeTextureFill: | |
310 auto brush = Gdip.Brush_Clone(data.gdipBrush); | |
311 if (brush is null) SWT.error(SWT.ERROR_NO_HANDLES); | |
312 Gdip.TextureBrush_ScaleTransform( cast(Gdip.TextureBrush)brush, -1, 1, Gdip.MatrixOrderPrepend); | |
313 data.gdipBrush = brush; | |
314 data.gdipBgBrush = cast(Gdip.SolidBrush) brush; | |
315 default: | |
316 } | |
317 } | |
318 } else { | |
319 auto background = data.background; | |
320 int rgb = ((background >> 16) & 0xFF) | (background & 0xFF00) | ((background & 0xFF) << 16); | |
321 auto color = Gdip.Color_new(data.alpha << 24 | rgb); | |
322 // if (color is null) SWT.error(SWT.ERROR_NO_HANDLES); | |
323 auto brush = Gdip.SolidBrush_new(color); | |
324 if (brush is null) SWT.error(SWT.ERROR_NO_HANDLES); | |
325 Gdip.Color_delete(color); | |
326 data.gdipBrush = cast(Gdip.Brush)brush; | |
327 data.gdipBgBrush = brush; | |
328 } | |
329 } | |
330 if ((state & FONT) !is 0) { | |
331 Font font = data.font; | |
332 OS.SelectObject(handle, font.handle); | |
333 auto gdipFont = createGdipFont(handle, font.handle); | |
334 if (data.gdipFont !is null) Gdip.Font_delete(data.gdipFont); | |
335 data.gdipFont = gdipFont; | |
336 } | |
337 if ((state & DRAW_OFFSET) !is 0) { | |
338 data.gdipXOffset = data.gdipYOffset = 0; | |
339 auto matrix = Gdip.Matrix_new(1, 0, 0, 1, 0, 0); | |
340 float[2] point; point[0]=1.0; point[1]=1.0; | |
341 Gdip.Graphics_GetTransform(gdipGraphics, matrix); | |
342 Gdip.Matrix_TransformPoints(matrix, cast(Gdip.PointF*)point.ptr, 1); | |
343 Gdip.Matrix_delete(matrix); | |
344 float scaling = point[0]; | |
345 if (scaling < 0) scaling = -scaling; | |
346 float penWidth = data.lineWidth * scaling; | |
347 if (penWidth is 0 || (cast(int)penWidth % 2) is 1) { | |
348 data.gdipXOffset = 0.5f / scaling; | |
349 } | |
350 scaling = point[1]; | |
351 if (scaling < 0) scaling = -scaling; | |
352 penWidth = data.lineWidth * scaling; | |
353 if (penWidth is 0 || (cast(int)penWidth % 2) is 1) { | |
354 data.gdipYOffset = 0.5f / scaling; | |
355 } | |
356 } | |
357 return; | |
358 } | |
359 if ((state & (FOREGROUND | LINE_CAP | LINE_JOIN | LINE_STYLE | LINE_WIDTH)) !is 0) { | |
360 int color = data.foreground; | |
361 int width = cast(int)data.lineWidth; | |
362 uint[] dashes = null; | |
363 int lineStyle = OS.PS_SOLID; | |
364 switch (data.lineStyle) { | |
365 case SWT.LINE_SOLID: break; | |
366 case SWT.LINE_DASH: lineStyle = OS.PS_DASH; break; | |
367 case SWT.LINE_DOT: lineStyle = OS.PS_DOT; break; | |
368 case SWT.LINE_DASHDOT: lineStyle = OS.PS_DASHDOT; break; | |
369 case SWT.LINE_DASHDOTDOT: lineStyle = OS.PS_DASHDOTDOT; break; | |
370 case SWT.LINE_CUSTOM: { | |
371 if (data.lineDashes !is null) { | |
372 lineStyle = OS.PS_USERSTYLE; | |
373 dashes = new uint[data.lineDashes.length]; | |
374 for (int i = 0; i < dashes.length; i++) { | |
375 dashes[i] = cast(int)data.lineDashes[i]; | |
376 } | |
377 } | |
378 break; | |
379 } | |
380 default: | |
381 } | |
382 if ((state & LINE_STYLE) !is 0) { | |
383 OS.SetBkMode(handle, data.lineStyle is SWT.LINE_SOLID ? OS.OPAQUE : OS.TRANSPARENT); | |
384 } | |
385 int joinStyle = 0; | |
386 switch (data.lineJoin) { | |
387 case SWT.JOIN_MITER: joinStyle = OS.PS_JOIN_MITER; break; | |
388 case SWT.JOIN_ROUND: joinStyle = OS.PS_JOIN_ROUND; break; | |
389 case SWT.JOIN_BEVEL: joinStyle = OS.PS_JOIN_BEVEL; break; | |
390 default: | |
391 } | |
392 int capStyle = 0; | |
393 switch (data.lineCap) { | |
394 case SWT.CAP_ROUND: capStyle = OS.PS_ENDCAP_ROUND; break; | |
395 case SWT.CAP_FLAT: capStyle = OS.PS_ENDCAP_FLAT; break; | |
396 case SWT.CAP_SQUARE: capStyle = OS.PS_ENDCAP_SQUARE;break; | |
397 default: | |
398 } | |
399 int style = lineStyle | joinStyle | capStyle; | |
400 /* | |
401 * Feature in Windows. Windows does not honour line styles other then | |
402 * PS_SOLID for pens wider than 1 pixel created with CreatePen(). The fix | |
403 * is to use ExtCreatePen() instead. | |
404 */ | |
405 HPEN newPen; | |
406 if (OS.IsWinCE || (width is 0 && lineStyle !is OS.PS_USERSTYLE) || style is 0) { | |
407 newPen = OS.CreatePen(style & OS.PS_STYLE_MASK, width, color); | |
408 } else { | |
409 LOGBRUSH logBrush; | |
410 logBrush.lbStyle = OS.BS_SOLID; | |
411 logBrush.lbColor = color; | |
412 /* Feature in Windows. PS_GEOMETRIC pens cannot have zero width. */ | |
413 newPen = OS.ExtCreatePen (style | OS.PS_GEOMETRIC, Math.max(1, width), &logBrush, dashes !is null ? dashes.length : 0, dashes.ptr); | |
414 } | |
415 OS.SelectObject(handle, newPen); | |
416 data.state |= PEN; | |
417 data.state &= ~NULL_PEN; | |
418 if (data.hPen !is null) OS.DeleteObject(data.hPen); | |
419 data.hPen = data.hOldPen = newPen; | |
420 } else if ((state & PEN) !is 0) { | |
421 OS.SelectObject(handle, data.hOldPen); | |
422 data.state &= ~NULL_PEN; | |
423 } else if ((state & NULL_PEN) !is 0) { | |
424 data.hOldPen = OS.SelectObject(handle, OS.GetStockObject(OS.NULL_PEN)); | |
425 data.state &= ~PEN; | |
426 } | |
427 if ((state & BACKGROUND) !is 0) { | |
428 auto newBrush = OS.CreateSolidBrush(data.background); | |
429 OS.SelectObject(handle, newBrush); | |
430 data.state |= BRUSH; | |
431 data.state &= ~NULL_BRUSH; | |
432 if (data.hBrush !is null) OS.DeleteObject(data.hBrush); | |
433 data.hOldBrush = data.hBrush = newBrush; | |
434 } else if ((state & BRUSH) !is 0) { | |
435 OS.SelectObject(handle, data.hOldBrush); | |
436 data.state &= ~NULL_BRUSH; | |
437 } else if ((state & NULL_BRUSH) !is 0) { | |
438 data.hOldBrush = OS.SelectObject(handle, OS.GetStockObject(OS.NULL_BRUSH)); | |
439 data.state &= ~BRUSH; | |
440 } | |
441 if ((state & BACKGROUND_TEXT) !is 0) { | |
442 OS.SetBkColor(handle, data.background); | |
443 } | |
444 if ((state & FOREGROUND_TEXT) !is 0) { | |
445 OS.SetTextColor(handle, data.foreground); | |
446 } | |
447 if ((state & FONT) !is 0) { | |
448 Font font = data.font; | |
449 OS.SelectObject(handle, font.handle); | |
450 } | |
451 } | |
452 | |
453 /** | |
454 * Copies a rectangular area of the receiver at the specified | |
455 * position into the image, which must be of type <code>SWT.BITMAP</code>. | |
456 * | |
457 * @param image the image to copy into | |
458 * @param x the x coordinate in the receiver of the area to be copied | |
459 * @param y the y coordinate in the receiver of the area to be copied | |
460 * | |
461 * @exception IllegalArgumentException <ul> | |
462 * <li>ERROR_NULL_ARGUMENT - if the image is null</li> | |
463 * <li>ERROR_INVALID_ARGUMENT - if the image is not a bitmap or has been disposed</li> | |
464 * </ul> | |
465 * @exception SWTException <ul> | |
466 * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> | |
467 * </ul> | |
468 */ | |
469 public void copyArea(Image image, int x, int y) { | |
470 if (handle is null) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); | |
471 if (image is null) SWT.error(SWT.ERROR_NULL_ARGUMENT); | |
472 if (image.type !is SWT.BITMAP || image.isDisposed()) SWT.error(SWT.ERROR_INVALID_ARGUMENT); | |
473 | |
474 /* Copy the bitmap area */ | |
475 Rectangle rect = image.getBounds(); | |
476 auto memHdc = OS.CreateCompatibleDC(handle); | |
477 auto hOldBitmap = OS.SelectObject(memHdc, image.handle); | |
478 OS.BitBlt(memHdc, 0, 0, rect.width, rect.height, handle, x, y, OS.SRCCOPY); | |
479 OS.SelectObject(memHdc, hOldBitmap); | |
480 OS.DeleteDC(memHdc); | |
481 } | |
482 | |
483 /** | |
484 * Copies a rectangular area of the receiver at the source | |
485 * position onto the receiver at the destination position. | |
486 * | |
487 * @param srcX the x coordinate in the receiver of the area to be copied | |
488 * @param srcY the y coordinate in the receiver of the area to be copied | |
489 * @param width the width of the area to copy | |
490 * @param height the height of the area to copy | |
491 * @param destX the x coordinate in the receiver of the area to copy to | |
492 * @param destY the y coordinate in the receiver of the area to copy to | |
493 * | |
494 * @exception SWTException <ul> | |
495 * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> | |
496 * </ul> | |
497 */ | |
498 public void copyArea(int srcX, int srcY, int width, int height, int destX, int destY) { | |
499 copyArea(srcX, srcY, width, height, destX, destY, true); | |
500 } | |
501 | |
502 /** | |
503 * Copies a rectangular area of the receiver at the source | |
504 * position onto the receiver at the destination position. | |
505 * | |
506 * @param srcX the x coordinate in the receiver of the area to be copied | |
507 * @param srcY the y coordinate in the receiver of the area to be copied | |
508 * @param width the width of the area to copy | |
509 * @param height the height of the area to copy | |
510 * @param destX the x coordinate in the receiver of the area to copy to | |
511 * @param destY the y coordinate in the receiver of the area to copy to | |
512 * @param paint if <code>true</code> paint events will be generated for old and obscured areas | |
513 * | |
514 * @exception SWTException <ul> | |
515 * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> | |
516 * </ul> | |
517 * | |
518 * @since 3.1 | |
519 */ | |
520 public void copyArea(int srcX, int srcY, int width, int height, int destX, int destY, bool paint) { | |
521 if (handle is null) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); | |
522 | |
523 /* | |
524 * Feature in WinCE. The function WindowFromDC is not part of the | |
525 * WinCE SDK. The fix is to remember the HWND. | |
526 */ | |
527 auto hwnd = data.hwnd; | |
528 if (hwnd is null) { | |
529 OS.BitBlt(handle, destX, destY, width, height, handle, srcX, srcY, OS.SRCCOPY); | |
530 } else { | |
531 RECT lprcClip; | |
532 auto hrgn = OS.CreateRectRgn(0, 0, 0, 0); | |
533 if (OS.GetClipRgn(handle, hrgn) is 1) { | |
534 OS.GetRgnBox(hrgn, &lprcClip); | |
535 } | |
536 OS.DeleteObject(hrgn); | |
537 RECT lprcScroll; | |
538 OS.SetRect(&lprcScroll, srcX, srcY, srcX + width, srcY + height); | |
539 int flags = paint ? OS.SW_INVALIDATE | OS.SW_ERASE : 0; | |
540 int res = OS.ScrollWindowEx(hwnd, destX - srcX, destY - srcY, &lprcScroll, &lprcClip, null, null, flags); | |
541 | |
542 /* | |
543 * Feature in WinCE. ScrollWindowEx does not accept combined | |
544 * vertical and horizontal scrolling. The fix is to do a | |
545 * BitBlt and invalidate the appropriate source area. | |
546 */ | |
547 static if (OS.IsWinCE) { | |
548 if (res is 0) { | |
549 OS.BitBlt(handle, destX, destY, width, height, handle, srcX, srcY, OS.SRCCOPY); | |
550 if (paint) { | |
551 int deltaX = destX - srcX, deltaY = destY - srcY; | |
552 bool disjoint = (destX + width < srcX) || (srcX + width < destX) || (destY + height < srcY) || (srcY + height < destY); | |
553 if (disjoint) { | |
554 OS.InvalidateRect(hwnd, &lprcScroll, true); | |
555 } else { | |
556 if (deltaX !is 0) { | |
557 int newX = destX - deltaX; | |
558 if (deltaX < 0) newX = destX + width; | |
559 OS.SetRect(&lprcScroll, newX, srcY, newX + Math.abs(deltaX), srcY + height); | |
560 OS.InvalidateRect(hwnd, &lprcScroll, true); | |
561 } | |
562 if (deltaY !is 0) { | |
563 int newY = destY - deltaY; | |
564 if (deltaY < 0) newY = destY + height; | |
565 OS.SetRect(&lprcScroll, srcX, newY, srcX + width, newY + Math.abs(deltaY)); | |
566 OS.InvalidateRect(hwnd, &lprcScroll, true); | |
567 } | |
568 } | |
569 } | |
570 } | |
571 } | |
572 } | |
573 } | |
574 | |
575 static Gdip.Font createGdipFont(HDC hDC, HFONT hFont) { | |
576 auto font = Gdip.Font_new(hDC, hFont); | |
577 if (font is null) SWT.error(SWT.ERROR_NO_HANDLES); | |
578 if (!Gdip.Font_IsAvailable(font)) { | |
579 Gdip.Font_delete(font); | |
580 LOGFONT logFont; | |
581 OS.GetObject(hFont, LOGFONT.sizeof, &logFont); | |
582 int size = Math.abs(logFont.lfHeight); | |
583 int style = Gdip.FontStyleRegular; | |
584 if (logFont.lfWeight is 700) style |= Gdip.FontStyleBold; | |
585 if (logFont.lfItalic !is 0) style |= Gdip.FontStyleItalic; | |
586 wchar[] chars; | |
587 static if (OS.IsUnicode) { | |
588 chars = logFont.lfFaceName; | |
589 } else { | |
590 chars = new wchar[OS.LF_FACESIZE]; | |
591 String bytes = logFont.lfFaceName; | |
592 OS.MultiByteToWideChar (OS.CP_ACP, OS.MB_PRECOMPOSED, bytes.ptr, bytes.length, chars, chars.length); | |
593 } | |
594 int index = 0; | |
595 while (index < chars.length) { | |
596 if (chars [index] is 0) break; | |
597 index++; | |
598 } | |
599 String name = WCHARsToStr( chars[ 0 .. index ] ); | |
600 if (Compatibility.equalsIgnoreCase(name, "Courier")) { //$NON-NLS-1$ | |
601 name = "Courier New"; //$NON-NLS-1$ | |
602 } | |
603 font = Gdip.Font_new( StrToWCHARz(name), size, style, Gdip.UnitPixel, null); | |
604 } | |
605 if (font is null) SWT.error(SWT.ERROR_NO_HANDLES); | |
606 return font; | |
607 } | |
608 | |
609 static void destroyGdipBrush(Gdip.Brush brush) { | |
610 int type = Gdip.Brush_GetType(brush); | |
611 switch (type) { | |
612 case Gdip.BrushTypeSolidColor: | |
613 Gdip.SolidBrush_delete( cast(Gdip.SolidBrush)brush); | |
614 break; | |
615 case Gdip.BrushTypeHatchFill: | |
616 Gdip.HatchBrush_delete(cast(Gdip.HatchBrush)brush); | |
617 break; | |
618 case Gdip.BrushTypeLinearGradient: | |
619 Gdip.LinearGradientBrush_delete(cast(Gdip.LinearGradientBrush)brush); | |
620 break; | |
621 case Gdip.BrushTypeTextureFill: | |
622 Gdip.TextureBrush_delete(cast(Gdip.TextureBrush)brush); | |
623 break; | |
624 default: | |
625 } | |
626 } | |
627 | |
628 /** | |
629 * Disposes of the operating system resources associated with | |
630 * the graphics context. Applications must dispose of all GCs | |
631 * which they allocate. | |
632 * | |
633 * @exception SWTError <ul> | |
634 * <li>ERROR_THREAD_INVALID_ACCESS if not called from the thread that created the drawable</li> | |
635 * </ul> | |
636 */ | |
637 void destroy() { | |
638 bool gdip = data.gdipGraphics !is null; | |
639 disposeGdip(); | |
640 if (gdip && (data.style & SWT.MIRRORED) !is 0) { | |
641 OS.SetLayout(handle, OS.GetLayout(handle) | OS.LAYOUT_RTL); | |
642 } | |
643 | |
644 /* Select stock pen and brush objects and free resources */ | |
645 if (data.hPen !is null) { | |
646 OS.SelectObject(handle, OS.GetStockObject(OS.NULL_PEN)); | |
647 OS.DeleteObject(data.hPen); | |
648 data.hPen = null; | |
649 } | |
650 if (data.hBrush !is null) { | |
651 OS.SelectObject(handle, OS.GetStockObject(OS.NULL_BRUSH)); | |
652 OS.DeleteObject(data.hBrush); | |
653 data.hBrush = null; | |
654 } | |
655 | |
656 /* | |
657 * Put back the original bitmap into the device context. | |
658 * This will ensure that we have not left a bitmap | |
659 * selected in it when we delete the HDC. | |
660 */ | |
661 auto hNullBitmap = data.hNullBitmap; | |
662 if (hNullBitmap !is null) { | |
663 OS.SelectObject(handle, hNullBitmap); | |
664 data.hNullBitmap = null; | |
665 } | |
666 Image image = data.image; | |
667 if (image !is null) image.memGC = null; | |
668 | |
669 /* | |
670 * Dispose the HDC. | |
671 */ | |
672 if (drawable !is null) drawable.internal_dispose_GC(handle, data); | |
673 drawable = null; | |
674 handle = null; | |
675 data.image = null; | |
676 data.ps = null; | |
677 data = null; | |
678 } | |
679 | |
680 void disposeGdip() { | |
681 if (data.gdipPen !is null) Gdip.Pen_delete(data.gdipPen); | |
682 if (data.gdipBgBrush !is null) destroyGdipBrush(cast(Gdip.Brush)data.gdipBgBrush); | |
683 if (data.gdipFgBrush !is null) destroyGdipBrush(cast(Gdip.Brush)data.gdipFgBrush); | |
684 if (data.gdipFont !is null) Gdip.Font_delete(data.gdipFont); | |
685 if (data.gdipGraphics !is null) Gdip.Graphics_delete(data.gdipGraphics); | |
686 data.gdipGraphics = null; | |
687 data.gdipBrush = null; | |
688 data.gdipBgBrush = null; | |
689 data.gdipFgBrush = null; | |
690 data.gdipFont = null; | |
691 data.gdipPen = null; | |
692 } | |
693 | |
694 /** | |
695 * Draws the outline of a circular or elliptical arc | |
696 * within the specified rectangular area. | |
697 * <p> | |
698 * The resulting arc begins at <code>startAngle</code> and extends | |
699 * for <code>arcAngle</code> degrees, using the current color. | |
700 * Angles are interpreted such that 0 degrees is at the 3 o'clock | |
701 * position. A positive value indicates a counter-clockwise rotation | |
702 * while a negative value indicates a clockwise rotation. | |
703 * </p><p> | |
704 * The center of the arc is the center of the rectangle whose origin | |
705 * is (<code>x</code>, <code>y</code>) and whose size is specified by the | |
706 * <code>width</code> and <code>height</code> arguments. | |
707 * </p><p> | |
708 * The resulting arc covers an area <code>width + 1</code> pixels wide | |
709 * by <code>height + 1</code> pixels tall. | |
710 * </p> | |
711 * | |
712 * @param x the x coordinate of the upper-left corner of the arc to be drawn | |
713 * @param y the y coordinate of the upper-left corner of the arc to be drawn | |
714 * @param width the width of the arc to be drawn | |
715 * @param height the height of the arc to be drawn | |
716 * @param startAngle the beginning angle | |
717 * @param arcAngle the angular extent of the arc, relative to the start angle | |
718 * | |
719 * @exception SWTException <ul> | |
720 * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> | |
721 * </ul> | |
722 */ | |
723 public void drawArc (int x, int y, int width, int height, int startAngle, int arcAngle) { | |
724 if (handle is null) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); | |
725 checkGC(DRAW); | |
726 if (width < 0) { | |
727 x = x + width; | |
728 width = -width; | |
729 } | |
730 if (height < 0) { | |
731 y = y + height; | |
732 height = -height; | |
733 } | |
734 if (width is 0 || height is 0 || arcAngle is 0) return; | |
735 auto gdipGraphics = data.gdipGraphics; | |
736 if (gdipGraphics !is null) { | |
737 Gdip.Graphics_TranslateTransform(gdipGraphics, data.gdipXOffset, data.gdipYOffset, Gdip.MatrixOrderPrepend); | |
738 if (width is height) { | |
739 Gdip.Graphics_DrawArc(gdipGraphics, data.gdipPen, x, y, width, height, -startAngle, -arcAngle); | |
740 } else { | |
741 auto path = Gdip.GraphicsPath_new(Gdip.FillModeAlternate); | |
742 if (path is null) SWT.error(SWT.ERROR_NO_HANDLES); | |
743 auto matrix = Gdip.Matrix_new(width, 0, 0, height, x, y); | |
744 if (matrix is null) SWT.error(SWT.ERROR_NO_HANDLES); | |
745 Gdip.GraphicsPath_AddArc(path, 0, 0, 1, 1, -startAngle, -arcAngle); | |
746 Gdip.GraphicsPath_Transform(path, matrix); | |
747 Gdip.Graphics_DrawPath(gdipGraphics, data.gdipPen, path); | |
748 Gdip.Matrix_delete(matrix); | |
749 Gdip.GraphicsPath_delete(path); | |
750 } | |
751 Gdip.Graphics_TranslateTransform(gdipGraphics, -data.gdipXOffset, -data.gdipYOffset, Gdip.MatrixOrderPrepend); | |
752 return; | |
753 } | |
754 if ((data.style & SWT.MIRRORED) !is 0) { | |
755 if (data.lineWidth !is 0 && data.lineWidth % 2 is 0) x--; | |
756 } | |
757 /* | |
758 * Feature in WinCE. The function Arc is not present in the | |
759 * WinCE SDK. The fix is to emulate arc drawing by using | |
760 * Polyline. | |
761 */ | |
762 static if (OS.IsWinCE) { | |
763 /* compute arc with a simple linear interpolation */ | |
764 if (arcAngle < 0) { | |
765 startAngle += arcAngle; | |
766 arcAngle = -arcAngle; | |
767 } | |
768 if (arcAngle > 360) arcAngle = 360; | |
769 int[] points = new int[(arcAngle + 1) * 2]; | |
770 int cteX = 2 * x + width; | |
771 int cteY = 2 * y + height; | |
772 int index = 0; | |
773 for (int i = 0; i <= arcAngle; i++) { | |
774 points[index++] = (Compatibility.cos(startAngle + i, width) + cteX) >> 1; | |
775 points[index++] = (cteY - Compatibility.sin(startAngle + i, height)) >> 1; | |
776 } | |
777 OS.Polyline(handle, cast(POINT*)points.ptr, points.length / 2); | |
778 } else { | |
779 int x1, y1, x2, y2,tmp; | |
780 bool isNegative; | |
781 if (arcAngle >= 360 || arcAngle <= -360) { | |
782 x1 = x2 = x + width; | |
783 y1 = y2 = y + height / 2; | |
784 } else { | |
785 isNegative = arcAngle < 0; | |
786 | |
787 arcAngle = arcAngle + startAngle; | |
788 if (isNegative) { | |
789 // swap angles | |
790 tmp = startAngle; | |
791 startAngle = arcAngle; | |
792 arcAngle = tmp; | |
793 } | |
794 x1 = Compatibility.cos(startAngle, width) + x + width/2; | |
795 y1 = -1 * Compatibility.sin(startAngle, height) + y + height/2; | |
796 | |
797 x2 = Compatibility.cos(arcAngle, width) + x + width/2; | |
798 y2 = -1 * Compatibility.sin(arcAngle, height) + y + height/2; | |
799 } | |
800 OS.Arc(handle, x, y, x + width + 1, y + height + 1, x1, y1, x2, y2); | |
801 } | |
802 } | |
803 | |
804 /** | |
805 * Draws a rectangle, based on the specified arguments, which has | |
806 * the appearance of the platform's <em>focus rectangle</em> if the | |
807 * platform supports such a notion, and otherwise draws a simple | |
808 * rectangle in the receiver's foreground color. | |
809 * | |
810 * @param x the x coordinate of the rectangle | |
811 * @param y the y coordinate of the rectangle | |
812 * @param width the width of the rectangle | |
813 * @param height the height of the rectangle | |
814 * | |
815 * @exception SWTException <ul> | |
816 * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> | |
817 * </ul> | |
818 * | |
819 * @see #drawRectangle(int, int, int, int) | |
820 */ | |
821 public void drawFocus (int x, int y, int width, int height) { | |
822 if (handle is null) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); | |
823 if ((data.uiState & OS.UISF_HIDEFOCUS) !is 0) return; | |
824 data.focusDrawn = true; | |
825 HDC hdc = handle; | |
826 int state = 0; | |
827 auto gdipGraphics = data.gdipGraphics; | |
828 if (gdipGraphics !is null) { | |
829 HRGN clipRgn; | |
830 Gdip.Graphics_SetPixelOffsetMode(gdipGraphics, Gdip.PixelOffsetModeNone); | |
831 auto rgn = Gdip.Region_new(); | |
832 if (rgn is null) SWT.error(SWT.ERROR_NO_HANDLES); | |
833 Gdip.Graphics_GetClip(gdipGraphics, rgn); | |
834 if (!Gdip.Region_IsInfinite(rgn, gdipGraphics)) { | |
835 clipRgn = Gdip.Region_GetHRGN(rgn, gdipGraphics); | |
836 } | |
837 Gdip.Region_delete(rgn); | |
838 Gdip.Graphics_SetPixelOffsetMode(gdipGraphics, Gdip.PixelOffsetModeHalf); | |
839 float[6] lpXform; | |
840 bool gotElements = false; | |
841 auto matrix = Gdip.Matrix_new(1, 0, 0, 1, 0, 0); | |
842 if (matrix is null) SWT.error(SWT.ERROR_NO_HANDLES); | |
843 Gdip.Graphics_GetTransform(gdipGraphics, matrix); | |
844 if (!Gdip.Matrix_IsIdentity(matrix)) { | |
845 gotElements = true; | |
846 Gdip.Matrix_GetElements(matrix, lpXform.ptr); | |
847 } | |
848 Gdip.Matrix_delete(matrix); | |
849 hdc = Gdip.Graphics_GetHDC(gdipGraphics); | |
850 state = OS.SaveDC(hdc); | |
851 if (gotElements) { | |
852 OS.SetGraphicsMode(hdc, OS.GM_ADVANCED); | |
853 OS.SetWorldTransform(hdc, cast(XFORM*)lpXform.ptr); | |
854 } | |
855 if (clipRgn !is null) { | |
856 OS.SelectClipRgn(hdc, clipRgn); | |
857 OS.DeleteObject(clipRgn); | |
858 } | |
859 } | |
860 OS.SetBkColor(hdc, 0xFFFFFF); | |
861 OS.SetTextColor(hdc, 0x000000); | |
862 RECT rect; | |
863 OS.SetRect(&rect, x, y, x + width, y + height); | |
864 OS.DrawFocusRect(hdc, &rect); | |
865 if (gdipGraphics !is null) { | |
866 OS.RestoreDC(hdc, state); | |
867 Gdip.Graphics_ReleaseHDC(gdipGraphics, hdc); | |
868 } else { | |
869 data.state &= ~(BACKGROUND_TEXT | FOREGROUND_TEXT); | |
870 } | |
871 } | |
872 | |
873 /** | |
874 * Draws the given image in the receiver at the specified | |
875 * coordinates. | |
876 * | |
877 * @param image the image to draw | |
878 * @param x the x coordinate of where to draw | |
879 * @param y the y coordinate of where to draw | |
880 * | |
881 * @exception IllegalArgumentException <ul> | |
882 * <li>ERROR_NULL_ARGUMENT - if the image is null</li> | |
883 * <li>ERROR_INVALID_ARGUMENT - if the image has been disposed</li> | |
884 * <li>ERROR_INVALID_ARGUMENT - if the given coordinates are outside the bounds of the image</li> | |
885 * @exception SWTException <ul> | |
886 * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> | |
887 * </ul> | |
888 * @exception SWTError <ul> | |
889 * <li>ERROR_NO_HANDLES - if no handles are available to perform the operation</li> | |
890 * </ul> | |
891 */ | |
892 public void drawImage(Image image, int x, int y) { | |
893 if (handle is null) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); | |
894 if (image is null) SWT.error (SWT.ERROR_NULL_ARGUMENT); | |
895 if (image.isDisposed()) SWT.error(SWT.ERROR_INVALID_ARGUMENT); | |
896 drawImage(image, 0, 0, -1, -1, x, y, -1, -1, true); | |
897 } | |
898 | |
899 /** | |
900 * Copies a rectangular area from the source image into a (potentially | |
901 * different sized) rectangular area in the receiver. If the source | |
902 * and destination areas are of differing sizes, then the source | |
903 * area will be stretched or shrunk to fit the destination area | |
904 * as it is copied. The copy fails if any part of the source rectangle | |
905 * lies outside the bounds of the source image, or if any of the width | |
906 * or height arguments are negative. | |
907 * | |
908 * @param image the source image | |
909 * @param srcX the x coordinate in the source image to copy from | |
910 * @param srcY the y coordinate in the source image to copy from | |
911 * @param srcWidth the width in pixels to copy from the source | |
912 * @param srcHeight the height in pixels to copy from the source | |
913 * @param destX the x coordinate in the destination to copy to | |
914 * @param destY the y coordinate in the destination to copy to | |
915 * @param destWidth the width in pixels of the destination rectangle | |
916 * @param destHeight the height in pixels of the destination rectangle | |
917 * | |
918 * @exception IllegalArgumentException <ul> | |
919 * <li>ERROR_NULL_ARGUMENT - if the image is null</li> | |
920 * <li>ERROR_INVALID_ARGUMENT - if the image has been disposed</li> | |
921 * <li>ERROR_INVALID_ARGUMENT - if any of the width or height arguments are negative. | |
922 * <li>ERROR_INVALID_ARGUMENT - if the source rectangle is not contained within the bounds of the source image</li> | |
923 * </ul> | |
924 * @exception SWTException <ul> | |
925 * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> | |
926 * </ul> | |
927 * @exception SWTError <ul> | |
928 * <li>ERROR_NO_HANDLES - if no handles are available to perform the operation</li> | |
929 * </ul> | |
930 */ | |
931 public void drawImage(Image image, int srcX, int srcY, int srcWidth, int srcHeight, int destX, int destY, int destWidth, int destHeight) { | |
932 if (handle is null) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); | |
933 if (srcWidth is 0 || srcHeight is 0 || destWidth is 0 || destHeight is 0) return; | |
934 if (srcX < 0 || srcY < 0 || srcWidth < 0 || srcHeight < 0 || destWidth < 0 || destHeight < 0) { | |
935 SWT.error (SWT.ERROR_INVALID_ARGUMENT); | |
936 } | |
937 if (image is null) SWT.error (SWT.ERROR_NULL_ARGUMENT); | |
938 if (image.isDisposed()) SWT.error(SWT.ERROR_INVALID_ARGUMENT); | |
939 drawImage(image, srcX, srcY, srcWidth, srcHeight, destX, destY, destWidth, destHeight, false); | |
940 } | |
941 | |
942 void drawImage(Image srcImage, int srcX, int srcY, int srcWidth, int srcHeight, int destX, int destY, int destWidth, int destHeight, bool simple) { | |
943 if (data.gdipGraphics !is null) { | |
944 //TODO - cache bitmap | |
945 int /*long*/ [] gdipImage = srcImage.createGdipImage(); | |
946 auto img = cast(Gdip.Image) gdipImage[0]; | |
947 int imgWidth = Gdip.Image_GetWidth(img); | |
948 int imgHeight = Gdip.Image_GetHeight(img); | |
949 if (simple) { | |
950 srcWidth = destWidth = imgWidth; | |
951 srcHeight = destHeight = imgHeight; | |
952 } else { | |
953 if (srcX + srcWidth > imgWidth || srcY + srcHeight > imgHeight) { | |
954 SWT.error (SWT.ERROR_INVALID_ARGUMENT); | |
955 } | |
956 simple = srcX is 0 && srcY is 0 && | |
957 srcWidth is destWidth && destWidth is imgWidth && | |
958 srcHeight is destHeight && destHeight is imgHeight; | |
959 } | |
960 Gdip.Rect rect; | |
961 rect.X = destX; | |
962 rect.Y = destY; | |
963 rect.Width = destWidth; | |
964 rect.Height = destHeight; | |
965 /* | |
966 * Note that if the wrap mode is not WrapModeTileFlipXY, the scaled image | |
967 * is translucent around the borders. | |
968 */ | |
969 auto attrib = Gdip.ImageAttributes_new(); | |
970 Gdip.ImageAttributes_SetWrapMode(attrib, Gdip.WrapModeTileFlipXY); | |
971 if (data.alpha != 0xFF) { | |
972 | |
973 Gdip.ColorMatrix matrix = | |
974 { [ [1,0,0,0,0], | |
975 [0,1,0,0,0], | |
976 [0,0,1,0,0], | |
977 [0,0,0,data.alpha / cast(float)0xFF,0,], | |
978 [0,0,0,0,1] ] }; | |
979 /* | |
980 float[] matrix = [ cast(float) | |
981 1,0,0,0,0, | |
982 0,1,0,0,0, | |
983 0,0,1,0,0, | |
984 0,0,0,data.alpha / cast(float)0xFF,0, | |
985 0,0,0,0,1, | |
986 ];*/ | |
987 Gdip.ImageAttributes_SetColorMatrix(attrib, matrix, Gdip.ColorMatrixFlagsDefault, Gdip.ColorAdjustTypeBitmap); | |
988 } | |
989 int gstate = 0; | |
990 if ((data.style & SWT.MIRRORED) != 0) { | |
991 gstate = Gdip.Graphics_Save(data.gdipGraphics); | |
992 Gdip.Graphics_ScaleTransform(data.gdipGraphics, -1, 1, Gdip.MatrixOrderPrepend); | |
993 Gdip.Graphics_TranslateTransform(data.gdipGraphics, - 2 * destX - destWidth, 0, Gdip.MatrixOrderPrepend); | |
994 } | |
995 Gdip.Graphics_DrawImage(data.gdipGraphics, img, rect, srcX, srcY, srcWidth, srcHeight, Gdip.UnitPixel, attrib, null, null); | |
996 if ((data.style & SWT.MIRRORED) != 0) { | |
997 Gdip.Graphics_Restore(data.gdipGraphics, gstate); | |
998 } | |
999 Gdip.ImageAttributes_delete(attrib); | |
1000 Gdip.Bitmap_delete( cast(Gdip.Bitmap) img); | |
1001 if (gdipImage[1] != 0) { | |
1002 auto hHeap = OS.GetProcessHeap (); | |
1003 OS.HeapFree(hHeap, 0, cast(void*)gdipImage[1]); | |
1004 } | |
1005 return; | |
1006 } | |
1007 switch (srcImage.type) { | |
1008 case SWT.BITMAP: | |
1009 drawBitmap(srcImage, srcX, srcY, srcWidth, srcHeight, destX, destY, destWidth, destHeight, simple); | |
1010 break; | |
1011 case SWT.ICON: | |
1012 drawIcon(srcImage, srcX, srcY, srcWidth, srcHeight, destX, destY, destWidth, destHeight, simple); | |
1013 break; | |
1014 default: | |
1015 } | |
1016 } | |
1017 | |
1018 void drawIcon(Image srcImage, int srcX, int srcY, int srcWidth, int srcHeight, int destX, int destY, int destWidth, int destHeight, bool simple) { | |
1019 int technology = OS.GetDeviceCaps(handle, OS.TECHNOLOGY); | |
1020 | |
1021 bool drawIcon = true; | |
1022 int flags = OS.DI_NORMAL; | |
1023 int offsetX = 0, offsetY = 0; | |
1024 if (!OS.IsWinCE && OS.WIN32_VERSION >= OS.VERSION(5, 1)) { | |
1025 if ((OS.GetLayout(handle) & OS.LAYOUT_RTL) !is 0) { | |
1026 flags |= OS.DI_NOMIRROR; | |
1027 /* | |
1028 * Bug in Windows. For some reason, DrawIconEx() does not take | |
1029 * into account the window origin when the DI_NOMIRROR and | |
1030 * LAYOUT_RTL are set. The fix is to set the window origin to | |
1031 * (0, 0) and offset the drawing ourselves. | |
1032 */ | |
1033 POINT pt; | |
1034 OS.GetWindowOrgEx(handle, &pt); | |
1035 offsetX = pt.x; | |
1036 offsetY = pt.y; | |
1037 } | |
1038 } else { | |
1039 if (!OS.IsWinCE && OS.WIN32_VERSION >= OS.VERSION(4, 10)) { | |
1040 drawIcon = (OS.GetLayout(handle) & OS.LAYOUT_RTL) is 0; | |
1041 } | |
1042 } | |
1043 | |
1044 /* Simple case: no stretching, entire icon */ | |
1045 if (simple && technology !is OS.DT_RASPRINTER && drawIcon) { | |
1046 if (offsetX !is 0 || offsetY !is 0) OS.SetWindowOrgEx(handle, 0, 0, null); | |
1047 OS.DrawIconEx(handle, destX - offsetX, destY - offsetY, srcImage.handle, 0, 0, 0, null, flags); | |
1048 if (offsetX !is 0 || offsetY !is 0) OS.SetWindowOrgEx(handle, offsetX, offsetY, null); | |
1049 return; | |
1050 } | |
1051 | |
1052 /* Get the icon info */ | |
1053 ICONINFO srcIconInfo; | |
1054 static if (OS.IsWinCE) { | |
1055 Image.GetIconInfo(srcImage, &srcIconInfo); | |
1056 } else { | |
1057 OS.GetIconInfo(srcImage.handle, &srcIconInfo); | |
1058 } | |
1059 | |
1060 /* Get the icon width and height */ | |
1061 auto hBitmap = srcIconInfo.hbmColor; | |
1062 if (hBitmap is null) hBitmap = srcIconInfo.hbmMask; | |
1063 BITMAP bm; | |
1064 OS.GetObject(hBitmap, BITMAP.sizeof, &bm); | |
1065 int iconWidth = bm.bmWidth, iconHeight = bm.bmHeight; | |
1066 if (hBitmap is srcIconInfo.hbmMask) iconHeight /= 2; | |
1067 | |
1068 if (simple) { | |
1069 srcWidth = destWidth = iconWidth; | |
1070 srcHeight = destHeight = iconHeight; | |
1071 } | |
1072 | |
1073 /* Draw the icon */ | |
1074 bool failed = srcX + srcWidth > iconWidth || srcY + srcHeight > iconHeight; | |
1075 if (!failed) { | |
1076 simple = srcX is 0 && srcY is 0 && | |
1077 srcWidth is destWidth && srcHeight is destHeight && | |
1078 srcWidth is iconWidth && srcHeight is iconHeight; | |
1079 if (!drawIcon) { | |
1080 drawBitmapMask(srcImage, srcIconInfo.hbmColor, srcIconInfo.hbmMask, srcX, srcY, srcWidth, srcHeight, destX, destY, destWidth, destHeight, simple, iconWidth, iconHeight, false); | |
1081 } else if (simple && technology !is OS.DT_RASPRINTER) { | |
1082 /* Simple case: no stretching, entire icon */ | |
1083 if (offsetX !is 0 || offsetY !is 0) OS.SetWindowOrgEx(handle, 0, 0, null); | |
1084 OS.DrawIconEx(handle, destX - offsetX, destY - offsetY, srcImage.handle, 0, 0, 0, null, flags); | |
1085 if (offsetX !is 0 || offsetY !is 0) OS.SetWindowOrgEx(handle, offsetX, offsetY, null); | |
1086 } else { | |
1087 /* Create the icon info and HDC's */ | |
1088 ICONINFO newIconInfo; | |
1089 newIconInfo.fIcon = true; | |
1090 auto srcHdc = OS.CreateCompatibleDC(handle); | |
1091 auto dstHdc = OS.CreateCompatibleDC(handle); | |
1092 | |
1093 /* Blt the color bitmap */ | |
1094 int srcColorY = srcY; | |
1095 auto srcColor = srcIconInfo.hbmColor; | |
1096 if (srcColor is null) { | |
1097 srcColor = srcIconInfo.hbmMask; | |
1098 srcColorY += iconHeight; | |
1099 } | |
1100 auto oldSrcBitmap = OS.SelectObject(srcHdc, srcColor); | |
1101 newIconInfo.hbmColor = OS.CreateCompatibleBitmap(srcHdc, destWidth, destHeight); | |
1102 if (newIconInfo.hbmColor is null) SWT.error(SWT.ERROR_NO_HANDLES); | |
1103 auto oldDestBitmap = OS.SelectObject(dstHdc, newIconInfo.hbmColor); | |
1104 bool stretch = !simple && (srcWidth !is destWidth || srcHeight !is destHeight); | |
1105 if (stretch) { | |
1106 static if (!OS.IsWinCE) OS.SetStretchBltMode(dstHdc, OS.COLORONCOLOR); | |
1107 OS.StretchBlt(dstHdc, 0, 0, destWidth, destHeight, srcHdc, srcX, srcColorY, srcWidth, srcHeight, OS.SRCCOPY); | |
1108 } else { | |
1109 OS.BitBlt(dstHdc, 0, 0, destWidth, destHeight, srcHdc, srcX, srcColorY, OS.SRCCOPY); | |
1110 } | |
1111 | |
1112 /* Blt the mask bitmap */ | |
1113 OS.SelectObject(srcHdc, srcIconInfo.hbmMask); | |
1114 newIconInfo.hbmMask = OS.CreateBitmap(destWidth, destHeight, 1, 1, null); | |
1115 if (newIconInfo.hbmMask is null) SWT.error(SWT.ERROR_NO_HANDLES); | |
1116 OS.SelectObject(dstHdc, newIconInfo.hbmMask); | |
1117 if (stretch) { | |
1118 OS.StretchBlt(dstHdc, 0, 0, destWidth, destHeight, srcHdc, srcX, srcY, srcWidth, srcHeight, OS.SRCCOPY); | |
1119 } else { | |
1120 OS.BitBlt(dstHdc, 0, 0, destWidth, destHeight, srcHdc, srcX, srcY, OS.SRCCOPY); | |
1121 } | |
1122 | |
1123 if (technology is OS.DT_RASPRINTER) { | |
1124 OS.SelectObject(srcHdc, newIconInfo.hbmColor); | |
1125 OS.SelectObject(dstHdc, newIconInfo.hbmMask); | |
1126 drawBitmapTransparentByClipping(srcHdc, dstHdc, 0, 0, destWidth, destHeight, destX, destY, destWidth, destHeight, true, destWidth, destHeight); | |
1127 OS.SelectObject(srcHdc, oldSrcBitmap); | |
1128 OS.SelectObject(dstHdc, oldDestBitmap); | |
1129 } else { | |
1130 OS.SelectObject(srcHdc, oldSrcBitmap); | |
1131 OS.SelectObject(dstHdc, oldDestBitmap); | |
1132 auto hIcon = OS.CreateIconIndirect(&newIconInfo); | |
1133 if (hIcon is null) SWT.error(SWT.ERROR_NO_HANDLES); | |
1134 if (offsetX !is 0 || offsetY !is 0) OS.SetWindowOrgEx(handle, 0, 0, null); | |
1135 OS.DrawIconEx(handle, destX - offsetX, destY - offsetY, hIcon, destWidth, destHeight, 0, null, flags); | |
1136 if (offsetX !is 0 || offsetY !is 0) OS.SetWindowOrgEx(handle, offsetX, offsetY, null); | |
1137 OS.DestroyIcon(hIcon); | |
1138 } | |
1139 | |
1140 /* Destroy the new icon src and mask and hdc's*/ | |
1141 OS.DeleteObject(newIconInfo.hbmMask); | |
1142 OS.DeleteObject(newIconInfo.hbmColor); | |
1143 OS.DeleteDC(dstHdc); | |
1144 OS.DeleteDC(srcHdc); | |
1145 } | |
1146 } | |
1147 | |
1148 /* Free icon info */ | |
1149 OS.DeleteObject(srcIconInfo.hbmMask); | |
1150 if (srcIconInfo.hbmColor !is null) { | |
1151 OS.DeleteObject(srcIconInfo.hbmColor); | |
1152 } | |
1153 | |
1154 if (failed) SWT.error(SWT.ERROR_INVALID_ARGUMENT); | |
1155 } | |
1156 | |
1157 void drawBitmap(Image srcImage, int srcX, int srcY, int srcWidth, int srcHeight, int destX, int destY, int destWidth, int destHeight, bool simple) { | |
1158 BITMAP bm; | |
1159 OS.GetObject(srcImage.handle, BITMAP.sizeof, &bm); | |
1160 int imgWidth = bm.bmWidth; | |
1161 int imgHeight = bm.bmHeight; | |
1162 if (simple) { | |
1163 srcWidth = destWidth = imgWidth; | |
1164 srcHeight = destHeight = imgHeight; | |
1165 } else { | |
1166 if (srcX + srcWidth > imgWidth || srcY + srcHeight > imgHeight) { | |
1167 SWT.error (SWT.ERROR_INVALID_ARGUMENT); | |
1168 } | |
1169 simple = srcX is 0 && srcY is 0 && | |
1170 srcWidth is destWidth && destWidth is imgWidth && | |
1171 srcHeight is destHeight && destHeight is imgHeight; | |
1172 } | |
1173 bool mustRestore = false; | |
1174 GC memGC = srcImage.memGC; | |
1175 if (memGC !is null && !memGC.isDisposed()) { | |
1176 memGC.flush(); | |
1177 mustRestore = true; | |
1178 GCData data = memGC.data; | |
1179 if (data.hNullBitmap !is null) { | |
1180 OS.SelectObject(memGC.handle, data.hNullBitmap); | |
1181 data.hNullBitmap = null; | |
1182 } | |
1183 } | |
1184 if (srcImage.alpha !is -1 || srcImage.alphaData !is null) { | |
1185 drawBitmapAlpha(srcImage, srcX, srcY, srcWidth, srcHeight, destX, destY, destWidth, destHeight, simple, bm, imgWidth, imgHeight); | |
1186 } else if (srcImage.transparentPixel !is -1) { | |
1187 drawBitmapTransparent(srcImage, srcX, srcY, srcWidth, srcHeight, destX, destY, destWidth, destHeight, simple, bm, imgWidth, imgHeight); | |
1188 } else { | |
1189 drawBitmap(srcImage, srcX, srcY, srcWidth, srcHeight, destX, destY, destWidth, destHeight, simple, bm, imgWidth, imgHeight); | |
1190 } | |
1191 if (mustRestore) { | |
1192 auto hOldBitmap = OS.SelectObject(memGC.handle, srcImage.handle); | |
1193 memGC.data.hNullBitmap = hOldBitmap; | |
1194 } | |
1195 } | |
1196 | |
1197 void drawBitmapAlpha(Image srcImage, int srcX, int srcY, int srcWidth, int srcHeight, int destX, int destY, int destWidth, int destHeight, bool simple, BITMAP bm, int imgWidth, int imgHeight) { | |
1198 /* Simple cases */ | |
1199 if (srcImage.alpha is 0) return; | |
1200 if (srcImage.alpha is 255) { | |
1201 drawBitmap(srcImage, srcX, srcY, srcWidth, srcHeight, destX, destY, destWidth, destHeight, simple, bm, imgWidth, imgHeight); | |
1202 return; | |
1203 } | |
1204 | |
1205 if (OS.IsWinNT && OS.WIN32_VERSION >= OS.VERSION(4, 10)) { | |
1206 BLENDFUNCTION blend; | |
1207 blend.BlendOp = OS.AC_SRC_OVER; | |
1208 auto srcHdc = OS.CreateCompatibleDC(handle); | |
1209 auto oldSrcBitmap = OS.SelectObject(srcHdc, srcImage.handle); | |
1210 if (srcImage.alpha !is -1) { | |
1211 blend.SourceConstantAlpha = cast(byte)srcImage.alpha; | |
1212 OS.AlphaBlend(handle, destX, destY, destWidth, destHeight, srcHdc, srcX, srcY, srcWidth, srcHeight, blend); | |
1213 } else { | |
1214 auto memDib = Image.createDIB(srcWidth, srcHeight, 32); | |
1215 if (memDib is null) SWT.error(SWT.ERROR_NO_HANDLES); | |
1216 auto memHdc = OS.CreateCompatibleDC(handle); | |
1217 auto oldMemBitmap = OS.SelectObject(memHdc, memDib); | |
1218 BITMAP dibBM; | |
1219 OS.GetObject(memDib, BITMAP.sizeof, &dibBM); | |
1220 OS.BitBlt(memHdc, 0, 0, srcWidth, srcHeight, srcHdc, srcX, srcY, OS.SRCCOPY); | |
1221 byte[] srcData = new byte[dibBM.bmWidthBytes * dibBM.bmHeight]; | |
1222 srcData[] = (cast(byte*)dibBM.bmBits)[ 0 .. srcData.length ]; | |
1223 final int apinc = imgWidth - srcWidth; | |
1224 int ap = srcY * imgWidth + srcX, sp = 0; | |
1225 byte[] alphaData = srcImage.alphaData; | |
1226 for (int y = 0; y < srcHeight; ++y) { | |
1227 for (int x = 0; x < srcWidth; ++x) { | |
1228 int alpha = alphaData[ap++] & 0xff; | |
1229 int r = ((srcData[sp + 0] & 0xFF) * alpha) + 128; | |
1230 r = (r + (r >> 8)) >> 8; | |
1231 int g = ((srcData[sp + 1] & 0xFF) * alpha) + 128; | |
1232 g = (g + (g >> 8)) >> 8; | |
1233 int b = ((srcData[sp + 2] & 0xFF) * alpha) + 128; | |
1234 b = (b + (b >> 8)) >> 8; | |
1235 srcData[sp+0] = cast(byte)r; | |
1236 srcData[sp+1] = cast(byte)g; | |
1237 srcData[sp+2] = cast(byte)b; | |
1238 srcData[sp+3] = cast(byte)alpha; | |
1239 sp += 4; | |
1240 } | |
1241 ap += apinc; | |
1242 } | |
1243 (cast(byte*)dibBM.bmBits)[ 0 .. srcData.length ] = srcData[]; | |
1244 blend.SourceConstantAlpha = 0xff; | |
1245 blend.AlphaFormat = OS.AC_SRC_ALPHA; | |
1246 OS.AlphaBlend(handle, destX, destY, destWidth, destHeight, memHdc, 0, 0, srcWidth, srcHeight, blend); | |
1247 OS.SelectObject(memHdc, oldMemBitmap); | |
1248 OS.DeleteDC(memHdc); | |
1249 OS.DeleteObject(memDib); | |
1250 } | |
1251 OS.SelectObject(srcHdc, oldSrcBitmap); | |
1252 OS.DeleteDC(srcHdc); | |
1253 return; | |
1254 } | |
1255 | |
1256 /* Check clipping */ | |
1257 Rectangle rect = getClipping(); | |
1258 rect = rect.intersection(new Rectangle(destX, destY, destWidth, destHeight)); | |
1259 if (rect.isEmpty()) return; | |
1260 | |
1261 /* | |
1262 * Optimization. Recalculate src and dest rectangles so that | |
1263 * only the clipping area is drawn. | |
1264 */ | |
1265 int sx1 = srcX + (((rect.x - destX) * srcWidth) / destWidth); | |
1266 int sx2 = srcX + ((((rect.x + rect.width) - destX) * srcWidth) / destWidth); | |
1267 int sy1 = srcY + (((rect.y - destY) * srcHeight) / destHeight); | |
1268 int sy2 = srcY + ((((rect.y + rect.height) - destY) * srcHeight) / destHeight); | |
1269 destX = rect.x; | |
1270 destY = rect.y; | |
1271 destWidth = rect.width; | |
1272 destHeight = rect.height; | |
1273 srcX = sx1; | |
1274 srcY = sy1; | |
1275 srcWidth = Math.max(1, sx2 - sx1); | |
1276 srcHeight = Math.max(1, sy2 - sy1); | |
1277 | |
1278 /* Create resources */ | |
1279 auto srcHdc = OS.CreateCompatibleDC(handle); | |
1280 auto oldSrcBitmap = OS.SelectObject(srcHdc, srcImage.handle); | |
1281 auto memHdc = OS.CreateCompatibleDC(handle); | |
1282 auto memDib = Image.createDIB(Math.max(srcWidth, destWidth), Math.max(srcHeight, destHeight), 32); | |
1283 if (memDib is null) SWT.error(SWT.ERROR_NO_HANDLES); | |
1284 auto oldMemBitmap = OS.SelectObject(memHdc, memDib); | |
1285 | |
1286 BITMAP dibBM; | |
1287 OS.GetObject(memDib, BITMAP.sizeof, &dibBM); | |
1288 int sizeInBytes = dibBM.bmWidthBytes * dibBM.bmHeight; | |
1289 | |
1290 /* Get the background pixels */ | |
1291 OS.BitBlt(memHdc, 0, 0, destWidth, destHeight, handle, destX, destY, OS.SRCCOPY); | |
1292 byte[] destData = new byte[sizeInBytes]; | |
1293 destData[] = (cast(byte*)dibBM.bmBits)[ 0 .. sizeInBytes ]; | |
1294 | |
1295 /* Get the foreground pixels */ | |
1296 OS.BitBlt(memHdc, 0, 0, srcWidth, srcHeight, srcHdc, srcX, srcY, OS.SRCCOPY); | |
1297 byte[] srcData = new byte[sizeInBytes]; | |
1298 srcData[] = (cast(byte*)dibBM.bmBits)[ 0 .. sizeInBytes ]; | |
1299 | |
1300 /* Merge the alpha channel in place */ | |
1301 int alpha = srcImage.alpha; | |
1302 final bool hasAlphaChannel = (srcImage.alpha is -1); | |
1303 if (hasAlphaChannel) { | |
1304 final int apinc = imgWidth - srcWidth; | |
1305 final int spinc = dibBM.bmWidthBytes - srcWidth * 4; | |
1306 int ap = srcY * imgWidth + srcX, sp = 3; | |
1307 byte[] alphaData = srcImage.alphaData; | |
1308 for (int y = 0; y < srcHeight; ++y) { | |
1309 for (int x = 0; x < srcWidth; ++x) { | |
1310 srcData[sp] = alphaData[ap++]; | |
1311 sp += 4; | |
1312 } | |
1313 ap += apinc; | |
1314 sp += spinc; | |
1315 } | |
1316 } | |
1317 | |
1318 /* Scale the foreground pixels with alpha */ | |
1319 (cast(byte*)dibBM.bmBits)[ 0 .. sizeInBytes ] = srcData[]; | |
1320 /* | |
1321 * Bug in WinCE and Win98. StretchBlt does not correctly stretch when | |
1322 * the source and destination HDCs are the same. The workaround is to | |
1323 * stretch to a temporary HDC and blit back into the original HDC. | |
1324 * Note that on WinCE StretchBlt correctly compresses the image when the | |
1325 * source and destination HDCs are the same. | |
1326 */ | |
1327 if ((OS.IsWinCE && (destWidth > srcWidth || destHeight > srcHeight)) || (!OS.IsWinNT && !OS.IsWinCE)) { | |
1328 auto tempHdc = OS.CreateCompatibleDC(handle); | |
1329 auto tempDib = Image.createDIB(destWidth, destHeight, 32); | |
1330 if (tempDib is null) SWT.error(SWT.ERROR_NO_HANDLES); | |
1331 auto oldTempBitmap = OS.SelectObject(tempHdc, tempDib); | |
1332 if (!simple && (srcWidth !is destWidth || srcHeight !is destHeight)) { | |
1333 static if (!OS.IsWinCE) OS.SetStretchBltMode(memHdc, OS.COLORONCOLOR); | |
1334 OS.StretchBlt(tempHdc, 0, 0, destWidth, destHeight, memHdc, 0, 0, srcWidth, srcHeight, OS.SRCCOPY); | |
1335 } else { | |
1336 OS.BitBlt(tempHdc, 0, 0, destWidth, destHeight, memHdc, 0, 0, OS.SRCCOPY); | |
1337 } | |
1338 OS.BitBlt(memHdc, 0, 0, destWidth, destHeight, tempHdc, 0, 0, OS.SRCCOPY); | |
1339 OS.SelectObject(tempHdc, oldTempBitmap); | |
1340 OS.DeleteObject(tempDib); | |
1341 OS.DeleteDC(tempHdc); | |
1342 } else { | |
1343 if (!simple && (srcWidth !is destWidth || srcHeight !is destHeight)) { | |
1344 static if (!OS.IsWinCE) OS.SetStretchBltMode(memHdc, OS.COLORONCOLOR); | |
1345 OS.StretchBlt(memHdc, 0, 0, destWidth, destHeight, memHdc, 0, 0, srcWidth, srcHeight, OS.SRCCOPY); | |
1346 } else { | |
1347 OS.BitBlt(memHdc, 0, 0, destWidth, destHeight, memHdc, 0, 0, OS.SRCCOPY); | |
1348 } | |
1349 } | |
1350 srcData[] = (cast(byte*)dibBM.bmBits)[ 0 .. sizeInBytes ]; | |
1351 | |
1352 /* Compose the pixels */ | |
1353 final int dpinc = dibBM.bmWidthBytes - destWidth * 4; | |
1354 int dp = 0; | |
1355 for (int y = 0; y < destHeight; ++y) { | |
1356 for (int x = 0; x < destWidth; ++x) { | |
1357 if (hasAlphaChannel) alpha = srcData[dp + 3] & 0xff; | |
1358 destData[dp] += ((srcData[dp] & 0xff) - (destData[dp] & 0xff)) * alpha / 255; | |
1359 destData[dp + 1] += ((srcData[dp + 1] & 0xff) - (destData[dp + 1] & 0xff)) * alpha / 255; | |
1360 destData[dp + 2] += ((srcData[dp + 2] & 0xff) - (destData[dp + 2] & 0xff)) * alpha / 255; | |
1361 dp += 4; | |
1362 } | |
1363 dp += dpinc; | |
1364 } | |
1365 | |
1366 /* Draw the composed pixels */ | |
1367 (cast(byte*)dibBM.bmBits)[ 0 .. sizeInBytes ] = destData[]; | |
1368 OS.BitBlt(handle, destX, destY, destWidth, destHeight, memHdc, 0, 0, OS.SRCCOPY); | |
1369 | |
1370 /* Free resources */ | |
1371 OS.SelectObject(memHdc, oldMemBitmap); | |
1372 OS.DeleteDC(memHdc); | |
1373 OS.DeleteObject(memDib); | |
1374 OS.SelectObject(srcHdc, oldSrcBitmap); | |
1375 OS.DeleteDC(srcHdc); | |
1376 } | |
1377 | |
1378 void drawBitmapTransparentByClipping(HDC srcHdc, HDC maskHdc, int srcX, int srcY, int srcWidth, int srcHeight, int destX, int destY, int destWidth, int destHeight, bool simple, int imgWidth, int imgHeight) { | |
1379 /* Create a clipping region from the mask */ | |
1380 auto rgn = OS.CreateRectRgn(0, 0, 0, 0); | |
1381 for (int y=0; y<imgHeight; y++) { | |
1382 for (int x=0; x<imgWidth; x++) { | |
1383 if (OS.GetPixel(maskHdc, x, y) is 0) { | |
1384 auto tempRgn = OS.CreateRectRgn(x, y, x+1, y+1); | |
1385 OS.CombineRgn(rgn, rgn, tempRgn, OS.RGN_OR); | |
1386 OS.DeleteObject(tempRgn); | |
1387 } | |
1388 } | |
1389 } | |
1390 /* Stretch the clipping mask if needed */ | |
1391 if (destWidth !is srcWidth || destHeight !is srcHeight) { | |
1392 int nBytes = OS.GetRegionData (rgn, 0, null); | |
1393 int[] lpRgnData = new int[nBytes / 4]; | |
1394 OS.GetRegionData (rgn, nBytes, cast(RGNDATA*)lpRgnData.ptr); | |
1395 float[6] lpXform; | |
1396 lpXform[] = 0.0f; | |
1397 lpXform[0] = cast(float)destWidth/srcWidth; | |
1398 lpXform[3] = cast(float)destHeight/srcHeight; | |
1399 auto tmpRgn = OS.ExtCreateRegion(cast(XFORM*)lpXform.ptr, nBytes, cast(RGNDATA*)lpRgnData.ptr); | |
1400 OS.DeleteObject(rgn); | |
1401 rgn = tmpRgn; | |
1402 } | |
1403 OS.OffsetRgn(rgn, destX, destY); | |
1404 auto clip = OS.CreateRectRgn(0, 0, 0, 0); | |
1405 int result = OS.GetClipRgn(handle, clip); | |
1406 if (result is 1) OS.CombineRgn(rgn, rgn, clip, OS.RGN_AND); | |
1407 OS.SelectClipRgn(handle, rgn); | |
1408 int rop2 = 0; | |
1409 static if (!OS.IsWinCE) { | |
1410 rop2 = OS.GetROP2(handle); | |
1411 } else { | |
1412 rop2 = OS.SetROP2 (handle, OS.R2_COPYPEN); | |
1413 OS.SetROP2 (handle, rop2); | |
1414 } | |
1415 int dwRop = rop2 is OS.R2_XORPEN ? OS.SRCINVERT : OS.SRCCOPY; | |
1416 if (!simple && (srcWidth !is destWidth || srcHeight !is destHeight)) { | |
1417 int mode = 0; | |
1418 static if (!OS.IsWinCE) mode = OS.SetStretchBltMode(handle, OS.COLORONCOLOR); | |
1419 OS.StretchBlt(handle, destX, destY, destWidth, destHeight, srcHdc, srcX, srcY, srcWidth, srcHeight, dwRop); | |
1420 static if (!OS.IsWinCE) OS.SetStretchBltMode(handle, mode); | |
1421 } else { | |
1422 OS.BitBlt(handle, destX, destY, destWidth, destHeight, srcHdc, srcX, srcY, dwRop); | |
1423 } | |
1424 OS.SelectClipRgn(handle, result is 1 ? clip : null); | |
1425 OS.DeleteObject(clip); | |
1426 OS.DeleteObject(rgn); | |
1427 } | |
1428 | |
1429 void drawBitmapMask(Image srcImage, HBITMAP srcColor, HBITMAP srcMask, int srcX, int srcY, int srcWidth, int srcHeight, int destX, int destY, int destWidth, int destHeight, bool simple, int imgWidth, int imgHeight, bool offscreen) { | |
1430 int srcColorY = srcY; | |
1431 if (srcColor is null) { | |
1432 srcColor = srcMask; | |
1433 srcColorY += imgHeight; | |
1434 } | |
1435 auto srcHdc = OS.CreateCompatibleDC(handle); | |
1436 auto oldSrcBitmap = OS.SelectObject(srcHdc, srcColor); | |
1437 auto destHdc = handle; | |
1438 int x = destX, y = destY; | |
1439 HDC tempHdc; | |
1440 HBITMAP tempBitmap; | |
1441 HBITMAP oldTempBitmap; | |
1442 int oldBkColor = 0, oldTextColor = 0; | |
1443 if (offscreen) { | |
1444 tempHdc = OS.CreateCompatibleDC(handle); | |
1445 tempBitmap = OS.CreateCompatibleBitmap(handle, destWidth, destHeight); | |
1446 oldTempBitmap = OS.SelectObject(tempHdc, tempBitmap); | |
1447 OS.BitBlt(tempHdc, 0, 0, destWidth, destHeight, handle, destX, destY, OS.SRCCOPY); | |
1448 destHdc = tempHdc; | |
1449 x = y = 0; | |
1450 } else { | |
1451 oldBkColor = OS.SetBkColor(handle, 0xFFFFFF); | |
1452 oldTextColor = OS.SetTextColor(handle, 0); | |
1453 } | |
1454 if (!simple && (srcWidth !is destWidth || srcHeight !is destHeight)) { | |
1455 int mode = 0; | |
1456 static if (!OS.IsWinCE) mode = OS.SetStretchBltMode(handle, OS.COLORONCOLOR); | |
1457 OS.StretchBlt(destHdc, x, y, destWidth, destHeight, srcHdc, srcX, srcColorY, srcWidth, srcHeight, OS.SRCINVERT); | |
1458 OS.SelectObject(srcHdc, srcMask); | |
1459 OS.StretchBlt(destHdc, x, y, destWidth, destHeight, srcHdc, srcX, srcY, srcWidth, srcHeight, OS.SRCAND); | |
1460 OS.SelectObject(srcHdc, srcColor); | |
1461 OS.StretchBlt(destHdc, x, y, destWidth, destHeight, srcHdc, srcX, srcColorY, srcWidth, srcHeight, OS.SRCINVERT); | |
1462 static if (!OS.IsWinCE) OS.SetStretchBltMode(handle, mode); | |
1463 } else { | |
1464 OS.BitBlt(destHdc, x, y, destWidth, destHeight, srcHdc, srcX, srcColorY, OS.SRCINVERT); | |
1465 OS.SetTextColor(destHdc, 0); | |
1466 OS.SelectObject(srcHdc, srcMask); | |
1467 OS.BitBlt(destHdc, x, y, destWidth, destHeight, srcHdc, srcX, srcY, OS.SRCAND); | |
1468 OS.SelectObject(srcHdc, srcColor); | |
1469 OS.BitBlt(destHdc, x, y, destWidth, destHeight, srcHdc, srcX, srcColorY, OS.SRCINVERT); | |
1470 } | |
1471 if (offscreen) { | |
1472 OS.BitBlt(handle, destX, destY, destWidth, destHeight, tempHdc, 0, 0, OS.SRCCOPY); | |
1473 OS.SelectObject(tempHdc, oldTempBitmap); | |
1474 OS.DeleteDC(tempHdc); | |
1475 OS.DeleteObject(tempBitmap); | |
1476 } else { | |
1477 OS.SetBkColor(handle, oldBkColor); | |
1478 OS.SetTextColor(handle, oldTextColor); | |
1479 } | |
1480 OS.SelectObject(srcHdc, oldSrcBitmap); | |
1481 OS.DeleteDC(srcHdc); | |
1482 } | |
1483 | |
1484 void drawBitmapTransparent(Image srcImage, int srcX, int srcY, int srcWidth, int srcHeight, int destX, int destY, int destWidth, int destHeight, bool simple, BITMAP bm, int imgWidth, int imgHeight) { | |
1485 | |
1486 /* Find the RGB values for the transparent pixel. */ | |
1487 bool isDib = bm.bmBits !is null; | |
1488 auto hBitmap = srcImage.handle; | |
1489 auto srcHdc = OS.CreateCompatibleDC(handle); | |
1490 auto oldSrcBitmap = OS.SelectObject(srcHdc, hBitmap); | |
1491 byte[] originalColors = null; | |
1492 int transparentColor = srcImage.transparentColor; | |
1493 if (transparentColor is -1) { | |
1494 int transBlue = 0, transGreen = 0, transRed = 0; | |
1495 bool fixPalette = false; | |
1496 if (bm.bmBitsPixel <= 8) { | |
1497 if (isDib) { | |
1498 /* Palette-based DIBSECTION */ | |
1499 static if (OS.IsWinCE) { | |
1500 byte* pBits = cast(byte*)bm.bmBits; | |
1501 //OS.MoveMemory(pBits, bm.bmBits, 1); | |
1502 byte oldValue = pBits[0]; | |
1503 int mask = (0xFF << (8 - bm.bmBitsPixel)) & 0x00FF; | |
1504 pBits[0] = cast(byte)((srcImage.transparentPixel << (8 - bm.bmBitsPixel)) | (pBits[0] & ~mask)); | |
1505 //OS.MoveMemory(bm.bmBits, pBits, 1); | |
1506 int color = OS.GetPixel(srcHdc, 0, 0); | |
1507 pBits[0] = oldValue; | |
1508 //OS.MoveMemory(bm.bmBits, pBits, 1); | |
1509 transBlue = (color & 0xFF0000) >> 16; | |
1510 transGreen = (color & 0xFF00) >> 8; | |
1511 transRed = color & 0xFF; | |
1512 } else { | |
1513 int maxColors = 1 << bm.bmBitsPixel; | |
1514 byte[] oldColors = new byte[maxColors * 4]; | |
1515 OS.GetDIBColorTable(srcHdc, 0, maxColors, cast(RGBQUAD*)oldColors.ptr); | |
1516 int offset = srcImage.transparentPixel * 4; | |
1517 for (int i = 0; i < oldColors.length; i += 4) { | |
1518 if (i !is offset) { | |
1519 if (oldColors[offset] is oldColors[i] && oldColors[offset+1] is oldColors[i+1] && oldColors[offset+2] is oldColors[i+2]) { | |
1520 fixPalette = true; | |
1521 break; | |
1522 } | |
1523 } | |
1524 } | |
1525 if (fixPalette) { | |
1526 byte[] newColors = new byte[oldColors.length]; | |
1527 transRed = transGreen = transBlue = 0xff; | |
1528 newColors[offset] = cast(byte)transBlue; | |
1529 newColors[offset+1] = cast(byte)transGreen; | |
1530 newColors[offset+2] = cast(byte)transRed; | |
1531 OS.SetDIBColorTable(srcHdc, 0, maxColors, cast(RGBQUAD*)newColors.ptr); | |
1532 originalColors = oldColors; | |
1533 } else { | |
1534 transBlue = oldColors[offset] & 0xFF; | |
1535 transGreen = oldColors[offset+1] & 0xFF; | |
1536 transRed = oldColors[offset+2] & 0xFF; | |
1537 } | |
1538 } | |
1539 } else { | |
1540 /* Palette-based bitmap */ | |
1541 int numColors = 1 << bm.bmBitsPixel; | |
1542 /* Set the few fields necessary to get the RGB data out */ | |
1543 BITMAPINFOHEADER bmiHeader; | |
1544 bmiHeader.biSize = BITMAPINFOHEADER.sizeof; | |
1545 bmiHeader.biPlanes = bm.bmPlanes; | |
1546 bmiHeader.biBitCount = bm.bmBitsPixel; | |
1547 byte[] bmi = new byte[BITMAPINFOHEADER.sizeof + numColors * 4]; | |
1548 bmi[] = (cast(byte*)&bmiHeader)[ 0 .. BITMAPINFOHEADER.sizeof ]; | |
1549 static if (OS.IsWinCE) SWT.error(SWT.ERROR_NOT_IMPLEMENTED); | |
1550 OS.GetDIBits(srcHdc, srcImage.handle, 0, 0, null, cast(BITMAPINFO*)bmi.ptr, OS.DIB_RGB_COLORS); | |
1551 int offset = BITMAPINFOHEADER.sizeof + 4 * srcImage.transparentPixel; | |
1552 transRed = bmi[offset + 2] & 0xFF; | |
1553 transGreen = bmi[offset + 1] & 0xFF; | |
1554 transBlue = bmi[offset] & 0xFF; | |
1555 } | |
1556 } else { | |
1557 /* Direct color image */ | |
1558 int pixel = srcImage.transparentPixel; | |
1559 switch (bm.bmBitsPixel) { | |
1560 case 16: | |
1561 transBlue = (pixel & 0x1F) << 3; | |
1562 transGreen = (pixel & 0x3E0) >> 2; | |
1563 transRed = (pixel & 0x7C00) >> 7; | |
1564 break; | |
1565 case 24: | |
1566 transBlue = (pixel & 0xFF0000) >> 16; | |
1567 transGreen = (pixel & 0xFF00) >> 8; | |
1568 transRed = pixel & 0xFF; | |
1569 break; | |
1570 case 32: | |
1571 transBlue = (pixel & 0xFF000000) >>> 24; | |
1572 transGreen = (pixel & 0xFF0000) >> 16; | |
1573 transRed = (pixel & 0xFF00) >> 8; | |
1574 break; | |
1575 default: | |
1576 } | |
1577 } | |
1578 transparentColor = transBlue << 16 | transGreen << 8 | transRed; | |
1579 if (!fixPalette) srcImage.transparentColor = transparentColor; | |
1580 } | |
1581 | |
1582 static if (OS.IsWinCE) { | |
1583 /* | |
1584 * Note in WinCE. TransparentImage uses the first entry of a palette | |
1585 * based image when there are multiple entries that have the same | |
1586 * transparent color. | |
1587 */ | |
1588 OS.TransparentImage(handle, destX, destY, destWidth, destHeight, srcHdc, srcX, srcY, srcWidth, srcHeight, transparentColor); | |
1589 } else if (originalColors is null && OS.IsWinNT && OS.WIN32_VERSION >= OS.VERSION(4, 10)) { | |
1590 int mode = OS.SetStretchBltMode(handle, OS.COLORONCOLOR); | |
1591 OS.TransparentBlt(handle, destX, destY, destWidth, destHeight, srcHdc, srcX, srcY, srcWidth, srcHeight, transparentColor); | |
1592 OS.SetStretchBltMode(handle, mode); | |
1593 } else { | |
1594 /* Create the mask for the source image */ | |
1595 auto maskHdc = OS.CreateCompatibleDC(handle); | |
1596 auto maskBitmap = OS.CreateBitmap(imgWidth, imgHeight, 1, 1, null); | |
1597 auto oldMaskBitmap = OS.SelectObject(maskHdc, maskBitmap); | |
1598 OS.SetBkColor(srcHdc, transparentColor); | |
1599 OS.BitBlt(maskHdc, 0, 0, imgWidth, imgHeight, srcHdc, 0, 0, OS.SRCCOPY); | |
1600 if (originalColors !is null) OS.SetDIBColorTable(srcHdc, 0, 1 << bm.bmBitsPixel, cast(RGBQUAD*)originalColors.ptr); | |
1601 | |
1602 if (OS.GetDeviceCaps(handle, OS.TECHNOLOGY) is OS.DT_RASPRINTER) { | |
1603 /* Most printers do not support BitBlt(), draw the source bitmap transparently using clipping */ | |
1604 drawBitmapTransparentByClipping(srcHdc, maskHdc, srcX, srcY, srcWidth, srcHeight, destX, destY, destWidth, destHeight, simple, imgWidth, imgHeight); | |
1605 } else { | |
1606 /* Draw the source bitmap transparently using invert/and mask/invert */ | |
1607 auto tempHdc = OS.CreateCompatibleDC(handle); | |
1608 auto tempBitmap = OS.CreateCompatibleBitmap(handle, destWidth, destHeight); | |
1609 auto oldTempBitmap = OS.SelectObject(tempHdc, tempBitmap); | |
1610 OS.BitBlt(tempHdc, 0, 0, destWidth, destHeight, handle, destX, destY, OS.SRCCOPY); | |
1611 if (!simple && (srcWidth !is destWidth || srcHeight !is destHeight)) { | |
1612 static if (!OS.IsWinCE) OS.SetStretchBltMode(tempHdc, OS.COLORONCOLOR); | |
1613 OS.StretchBlt(tempHdc, 0, 0, destWidth, destHeight, srcHdc, srcX, srcY, srcWidth, srcHeight, OS.SRCINVERT); | |
1614 OS.StretchBlt(tempHdc, 0, 0, destWidth, destHeight, maskHdc, srcX, srcY, srcWidth, srcHeight, OS.SRCAND); | |
1615 OS.StretchBlt(tempHdc, 0, 0, destWidth, destHeight, srcHdc, srcX, srcY, srcWidth, srcHeight, OS.SRCINVERT); | |
1616 } else { | |
1617 OS.BitBlt(tempHdc, 0, 0, destWidth, destHeight, srcHdc, srcX, srcY, OS.SRCINVERT); | |
1618 OS.BitBlt(tempHdc, 0, 0, destWidth, destHeight, maskHdc, srcX, srcY, OS.SRCAND); | |
1619 OS.BitBlt(tempHdc, 0, 0, destWidth, destHeight, srcHdc, srcX, srcY, OS.SRCINVERT); | |
1620 } | |
1621 OS.BitBlt(handle, destX, destY, destWidth, destHeight, tempHdc, 0, 0, OS.SRCCOPY); | |
1622 OS.SelectObject(tempHdc, oldTempBitmap); | |
1623 OS.DeleteDC(tempHdc); | |
1624 OS.DeleteObject(tempBitmap); | |
1625 } | |
1626 OS.SelectObject(maskHdc, oldMaskBitmap); | |
1627 OS.DeleteDC(maskHdc); | |
1628 OS.DeleteObject(maskBitmap); | |
1629 } | |
1630 OS.SelectObject(srcHdc, oldSrcBitmap); | |
1631 if (hBitmap !is srcImage.handle) OS.DeleteObject(hBitmap); | |
1632 OS.DeleteDC(srcHdc); | |
1633 } | |
1634 | |
1635 void drawBitmap(Image srcImage, int srcX, int srcY, int srcWidth, int srcHeight, int destX, int destY, int destWidth, int destHeight, bool simple, BITMAP bm, int imgWidth, int imgHeight) { | |
1636 auto srcHdc = OS.CreateCompatibleDC(handle); | |
1637 auto oldSrcBitmap = OS.SelectObject(srcHdc, srcImage.handle); | |
1638 int rop2 = 0; | |
1639 static if (!OS.IsWinCE) { | |
1640 rop2 = OS.GetROP2(handle); | |
1641 } else { | |
1642 rop2 = OS.SetROP2 (handle, OS.R2_COPYPEN); | |
1643 OS.SetROP2 (handle, rop2); | |
1644 } | |
1645 int dwRop = rop2 is OS.R2_XORPEN ? OS.SRCINVERT : OS.SRCCOPY; | |
1646 if (!simple && (srcWidth !is destWidth || srcHeight !is destHeight)) { | |
1647 int mode = 0; | |
1648 static if (!OS.IsWinCE) mode = OS.SetStretchBltMode(handle, OS.COLORONCOLOR); | |
1649 OS.StretchBlt(handle, destX, destY, destWidth, destHeight, srcHdc, srcX, srcY, srcWidth, srcHeight, dwRop); | |
1650 static if (!OS.IsWinCE) OS.SetStretchBltMode(handle, mode); | |
1651 } else { | |
1652 OS.BitBlt(handle, destX, destY, destWidth, destHeight, srcHdc, srcX, srcY, dwRop); | |
1653 } | |
1654 OS.SelectObject(srcHdc, oldSrcBitmap); | |
1655 OS.DeleteDC(srcHdc); | |
1656 } | |
1657 | |
1658 /** | |
1659 * Draws a line, using the foreground color, between the points | |
1660 * (<code>x1</code>, <code>y1</code>) and (<code>x2</code>, <code>y2</code>). | |
1661 * | |
1662 * @param x1 the first point's x coordinate | |
1663 * @param y1 the first point's y coordinate | |
1664 * @param x2 the second point's x coordinate | |
1665 * @param y2 the second point's y coordinate | |
1666 * | |
1667 * @exception SWTException <ul> | |
1668 * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> | |
1669 * </ul> | |
1670 */ | |
1671 public void drawLine (int x1, int y1, int x2, int y2) { | |
1672 if (handle is null) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); | |
1673 checkGC(DRAW); | |
1674 auto gdipGraphics = data.gdipGraphics; | |
1675 if (gdipGraphics !is null) { | |
1676 Gdip.Graphics_TranslateTransform(gdipGraphics, data.gdipXOffset, data.gdipYOffset, Gdip.MatrixOrderPrepend); | |
1677 Gdip.Graphics_DrawLine(gdipGraphics, data.gdipPen, x1, y1, x2, y2); | |
1678 Gdip.Graphics_TranslateTransform(gdipGraphics, -data.gdipXOffset, -data.gdipYOffset, Gdip.MatrixOrderPrepend); | |
1679 return; | |
1680 } | |
1681 if ((data.style & SWT.MIRRORED) !is 0) { | |
1682 if (data.lineWidth !is 0 && data.lineWidth % 2 is 0) { | |
1683 x1--; | |
1684 x2--; | |
1685 } | |
1686 } | |
1687 static if (OS.IsWinCE) { | |
1688 int [4] points; points[0] = x1; points[1] = y1; points[2] = x2; points[3] = y2; | |
1689 OS.Polyline (handle, cast(POINT*)points.ptr, points.length / 2); | |
1690 } else { | |
1691 OS.MoveToEx (handle, x1, y1, null); | |
1692 OS.LineTo (handle, x2, y2); | |
1693 } | |
1694 if (data.lineWidth <= 1) { | |
1695 OS.SetPixel (handle, x2, y2, data.foreground); | |
1696 } | |
1697 } | |
1698 | |
1699 /** | |
1700 * Draws the outline of an oval, using the foreground color, | |
1701 * within the specified rectangular area. | |
1702 * <p> | |
1703 * The result is a circle or ellipse that fits within the | |
1704 * rectangle specified by the <code>x</code>, <code>y</code>, | |
1705 * <code>width</code>, and <code>height</code> arguments. | |
1706 * </p><p> | |
1707 * The oval covers an area that is <code>width + 1</code> | |
1708 * pixels wide and <code>height + 1</code> pixels tall. | |
1709 * </p> | |
1710 * | |
1711 * @param x the x coordinate of the upper left corner of the oval to be drawn | |
1712 * @param y the y coordinate of the upper left corner of the oval to be drawn | |
1713 * @param width the width of the oval to be drawn | |
1714 * @param height the height of the oval to be drawn | |
1715 * | |
1716 * @exception SWTException <ul> | |
1717 * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> | |
1718 * </ul> | |
1719 */ | |
1720 public void drawOval (int x, int y, int width, int height) { | |
1721 if (handle is null) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); | |
1722 checkGC(DRAW); | |
1723 auto gdipGraphics = data.gdipGraphics; | |
1724 if (gdipGraphics !is null) { | |
1725 Gdip.Graphics_TranslateTransform(gdipGraphics, data.gdipXOffset, data.gdipYOffset, Gdip.MatrixOrderPrepend); | |
1726 Gdip.Graphics_DrawEllipse(gdipGraphics, data.gdipPen, x, y, width, height); | |
1727 Gdip.Graphics_TranslateTransform(gdipGraphics, -data.gdipXOffset, -data.gdipYOffset, Gdip.MatrixOrderPrepend); | |
1728 return; | |
1729 } | |
1730 if ((data.style & SWT.MIRRORED) !is 0) { | |
1731 if (data.lineWidth !is 0 && data.lineWidth % 2 is 0) x--; | |
1732 } | |
1733 OS.Ellipse(handle, x, y, x + width + 1, y + height + 1); | |
1734 } | |
1735 | |
1736 /** | |
1737 * Draws the path described by the parameter. | |
1738 * <p> | |
1739 * This operation requires the operating system's advanced | |
1740 * graphics subsystem which may not be available on some | |
1741 * platforms. | |
1742 * </p> | |
1743 * | |
1744 * @param path the path to draw | |
1745 * | |
1746 * @exception IllegalArgumentException <ul> | |
1747 * <li>ERROR_NULL_ARGUMENT - if the parameter is null</li> | |
1748 * <li>ERROR_INVALID_ARGUMENT - if the parameter has been disposed</li> | |
1749 * </ul> | |
1750 * @exception SWTException <ul> | |
1751 * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> | |
1752 * <li>ERROR_NO_GRAPHICS_LIBRARY - if advanced graphics are not available</li> | |
1753 * </ul> | |
1754 * | |
1755 * @see Path | |
1756 * | |
1757 * @since 3.1 | |
1758 */ | |
1759 public void drawPath (Path path) { | |
1760 if (handle is null) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); | |
1761 if (path is null) SWT.error(SWT.ERROR_NULL_ARGUMENT); | |
1762 if (path.handle is null) SWT.error(SWT.ERROR_INVALID_ARGUMENT); | |
1763 initGdip(); | |
1764 checkGC(DRAW); | |
1765 auto gdipGraphics = data.gdipGraphics; | |
1766 Gdip.Graphics_TranslateTransform(gdipGraphics, data.gdipXOffset, data.gdipYOffset, Gdip.MatrixOrderPrepend); | |
1767 Gdip.Graphics_DrawPath(gdipGraphics, data.gdipPen, path.handle); | |
1768 Gdip.Graphics_TranslateTransform(gdipGraphics, -data.gdipXOffset, -data.gdipYOffset, Gdip.MatrixOrderPrepend); | |
1769 } | |
1770 | |
1771 /** | |
1772 * Draws a pixel, using the foreground color, at the specified | |
1773 * point (<code>x</code>, <code>y</code>). | |
1774 * <p> | |
1775 * Note that the receiver's line attributes do not affect this | |
1776 * operation. | |
1777 * </p> | |
1778 * | |
1779 * @param x the point's x coordinate | |
1780 * @param y the point's y coordinate | |
1781 * | |
1782 * @exception SWTException <ul> | |
1783 * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> | |
1784 * </ul> | |
1785 * | |
1786 * @since 3.0 | |
1787 */ | |
1788 public void drawPoint (int x, int y) { | |
1789 if (handle is null) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); | |
1790 if (data.gdipGraphics !is null) { | |
1791 checkGC(DRAW); | |
1792 Gdip.Graphics_FillRectangle(data.gdipGraphics, getFgBrush(), x, y, 1, 1); | |
1793 return; | |
1794 } | |
1795 OS.SetPixel (handle, x, y, data.foreground); | |
1796 } | |
1797 | |
1798 /** | |
1799 * Draws the closed polygon which is defined by the specified array | |
1800 * of integer coordinates, using the receiver's foreground color. The array | |
1801 * contains alternating x and y values which are considered to represent | |
1802 * points which are the vertices of the polygon. Lines are drawn between | |
1803 * each consecutive pair, and between the first pair and last pair in the | |
1804 * array. | |
1805 * | |
1806 * @param pointArray an array of alternating x and y values which are the vertices of the polygon | |
1807 * | |
1808 * @exception SWTException <ul> | |
1809 * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> | |
1810 * </ul> | |
1811 */ | |
1812 public void drawPolygon( int[] pointArray) { | |
1813 if (handle is null) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); | |
1814 // SWT extension: allow null array | |
1815 //if (pointArray is null) SWT.error(SWT.ERROR_NULL_ARGUMENT); | |
1816 checkGC(DRAW); | |
1817 auto gdipGraphics = data.gdipGraphics; | |
1818 if (gdipGraphics !is null) { | |
1819 Gdip.Graphics_TranslateTransform(gdipGraphics, data.gdipXOffset, data.gdipYOffset, Gdip.MatrixOrderPrepend); | |
1820 Gdip.Graphics_DrawPolygon(gdipGraphics, data.gdipPen, cast(Gdip.Point*)pointArray.ptr, pointArray.length/2); | |
1821 Gdip.Graphics_TranslateTransform(gdipGraphics, -data.gdipXOffset, -data.gdipYOffset, Gdip.MatrixOrderPrepend); | |
1822 return; | |
1823 } | |
1824 if ((data.style & SWT.MIRRORED) !is 0) { | |
1825 if (data.lineWidth !is 0 && data.lineWidth % 2 is 0) { | |
1826 for (int i = 0; i < pointArray.length; i+=2) { | |
1827 pointArray[i]--; | |
1828 } | |
1829 } | |
1830 } | |
1831 OS.Polygon(handle, cast(POINT*)pointArray.ptr, pointArray.length/2); | |
1832 if ((data.style & SWT.MIRRORED) !is 0) { | |
1833 if (data.lineWidth !is 0 && data.lineWidth % 2 is 0) { | |
1834 for (int i = 0; i < pointArray.length; i+=2) { | |
1835 pointArray[i]++; | |
1836 } | |
1837 } | |
1838 } | |
1839 } | |
1840 | |
1841 /** | |
1842 * Draws the polyline which is defined by the specified array | |
1843 * of integer coordinates, using the receiver's foreground color. The array | |
1844 * contains alternating x and y values which are considered to represent | |
1845 * points which are the corners of the polyline. Lines are drawn between | |
1846 * each consecutive pair, but not between the first pair and last pair in | |
1847 * the array. | |
1848 * | |
1849 * @param pointArray an array of alternating x and y values which are the corners of the polyline | |
1850 * | |
1851 * @exception SWTException <ul> | |
1852 * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> | |
1853 * </ul> | |
1854 */ | |
1855 public void drawPolyline(int[] pointArray) { | |
1856 if (handle is null) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); | |
1857 // SWT externsion: allow null array | |
1858 //if (pointArray is null) SWT.error(SWT.ERROR_NULL_ARGUMENT); | |
1859 checkGC(DRAW); | |
1860 auto gdipGraphics = data.gdipGraphics; | |
1861 if (gdipGraphics !is null) { | |
1862 Gdip.Graphics_TranslateTransform(gdipGraphics, data.gdipXOffset, data.gdipYOffset, Gdip.MatrixOrderPrepend); | |
1863 Gdip.Graphics_DrawLines(gdipGraphics, data.gdipPen, cast(Gdip.Point*)pointArray.ptr, pointArray.length / 2); | |
1864 Gdip.Graphics_TranslateTransform(gdipGraphics, -data.gdipXOffset, -data.gdipYOffset, Gdip.MatrixOrderPrepend); | |
1865 return; | |
1866 } | |
1867 if ((data.style & SWT.MIRRORED) !is 0) { | |
1868 if (data.lineWidth !is 0 && data.lineWidth % 2 is 0) { | |
1869 for (int i = 0; i < pointArray.length; i+=2) { | |
1870 pointArray[i]--; | |
1871 } | |
1872 } | |
1873 } | |
1874 OS.Polyline(handle, cast(POINT*)pointArray.ptr, pointArray.length / 2); | |
1875 int length_ = pointArray.length; | |
1876 if (length_ >= 2) { | |
1877 if (data.lineWidth <= 1) { | |
1878 OS.SetPixel (handle, pointArray[length_ - 2], pointArray[length_ - 1], data.foreground); | |
1879 } | |
1880 } | |
1881 if ((data.style & SWT.MIRRORED) !is 0) { | |
1882 if (data.lineWidth !is 0 && data.lineWidth % 2 is 0) { | |
1883 for (int i = 0; i < pointArray.length; i+=2) { | |
1884 pointArray[i]++; | |
1885 } | |
1886 } | |
1887 } | |
1888 } | |
1889 | |
1890 /** | |
1891 * Draws the outline of the rectangle specified by the arguments, | |
1892 * using the receiver's foreground color. The left and right edges | |
1893 * of the rectangle are at <code>x</code> and <code>x + width</code>. | |
1894 * The top and bottom edges are at <code>y</code> and <code>y + height</code>. | |
1895 * | |
1896 * @param x the x coordinate of the rectangle to be drawn | |
1897 * @param y the y coordinate of the rectangle to be drawn | |
1898 * @param width the width of the rectangle to be drawn | |
1899 * @param height the height of the rectangle to be drawn | |
1900 * | |
1901 * @exception SWTException <ul> | |
1902 * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> | |
1903 * </ul> | |
1904 */ | |
1905 public void drawRectangle (int x, int y, int width, int height) { | |
1906 if (handle is null) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); | |
1907 checkGC(DRAW); | |
1908 auto gdipGraphics = data.gdipGraphics; | |
1909 if (gdipGraphics !is null) { | |
1910 if (width < 0) { | |
1911 x = x + width; | |
1912 width = -width; | |
1913 } | |
1914 if (height < 0) { | |
1915 y = y + height; | |
1916 height = -height; | |
1917 } | |
1918 Gdip.Graphics_TranslateTransform(gdipGraphics, data.gdipXOffset, data.gdipYOffset, Gdip.MatrixOrderPrepend); | |
1919 Gdip.Graphics_DrawRectangle(gdipGraphics, data.gdipPen, x, y, width, height); | |
1920 Gdip.Graphics_TranslateTransform(gdipGraphics, -data.gdipXOffset, -data.gdipYOffset, Gdip.MatrixOrderPrepend); | |
1921 return; | |
1922 } | |
1923 if ((data.style & SWT.MIRRORED) !is 0) { | |
1924 /* | |
1925 * Note that Rectangle() subtracts one pixel in MIRRORED mode when | |
1926 * the pen was created with CreatePen() and its width is 0 or 1. | |
1927 */ | |
1928 if (data.lineWidth > 1) { | |
1929 if ((data.lineWidth % 2) is 1) x++; | |
1930 } else { | |
1931 if (data.hPen !is null && OS.GetObject(data.hPen, 0, null) !is LOGPEN.sizeof) { | |
1932 x++; | |
1933 } | |
1934 } | |
1935 } | |
1936 OS.Rectangle (handle, x, y, x + width + 1, y + height + 1); | |
1937 } | |
1938 | |
1939 /** | |
1940 * Draws the outline of the specified rectangle, using the receiver's | |
1941 * foreground color. The left and right edges of the rectangle are at | |
1942 * <code>rect.x</code> and <code>rect.x + rect.width</code>. The top | |
1943 * and bottom edges are at <code>rect.y</code> and | |
1944 * <code>rect.y + rect.height</code>. | |
1945 * | |
1946 * @param rect the rectangle to draw | |
1947 * | |
1948 * @exception IllegalArgumentException <ul> | |
1949 * <li>ERROR_NULL_ARGUMENT - if the rectangle is null</li> | |
1950 * </ul> | |
1951 * @exception SWTException <ul> | |
1952 * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> | |
1953 * </ul> | |
1954 */ | |
1955 public void drawRectangle (Rectangle rect) { | |
1956 if (rect is null) SWT.error(SWT.ERROR_NULL_ARGUMENT); | |
1957 drawRectangle (rect.x, rect.y, rect.width, rect.height); | |
1958 } | |
1959 | |
1960 /** | |
1961 * Draws the outline of the round-cornered rectangle specified by | |
1962 * the arguments, using the receiver's foreground color. The left and | |
1963 * right edges of the rectangle are at <code>x</code> and <code>x + width</code>. | |
1964 * The top and bottom edges are at <code>y</code> and <code>y + height</code>. | |
1965 * The <em>roundness</em> of the corners is specified by the | |
1966 * <code>arcWidth</code> and <code>arcHeight</code> arguments, which | |
1967 * are respectively the width and height of the ellipse used to draw | |
1968 * the corners. | |
1969 * | |
1970 * @param x the x coordinate of the rectangle to be drawn | |
1971 * @param y the y coordinate of the rectangle to be drawn | |
1972 * @param width the width of the rectangle to be drawn | |
1973 * @param height the height of the rectangle to be drawn | |
1974 * @param arcWidth the width of the arc | |
1975 * @param arcHeight the height of the arc | |
1976 * | |
1977 * @exception SWTException <ul> | |
1978 * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> | |
1979 * </ul> | |
1980 */ | |
1981 public void drawRoundRectangle (int x, int y, int width, int height, int arcWidth, int arcHeight) { | |
1982 if (handle is null) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); | |
1983 checkGC(DRAW); | |
1984 if (data.gdipGraphics !is null) { | |
1985 drawRoundRectangleGdip(data.gdipGraphics, data.gdipPen, x, y, width, height, arcWidth, arcHeight); | |
1986 return; | |
1987 } | |
1988 if ((data.style & SWT.MIRRORED) !is 0) { | |
1989 if (data.lineWidth !is 0 && data.lineWidth % 2 is 0) x--; | |
1990 } | |
1991 static if (OS.IsWinCE) { | |
1992 /* | |
1993 * Bug in WinCE PPC. On certain devices, RoundRect does not draw | |
1994 * all the pixels. The workaround is to draw a round rectangle | |
1995 * using lines and arcs. | |
1996 */ | |
1997 if (width is 0 || height is 0) return; | |
1998 if (arcWidth is 0 || arcHeight is 0) { | |
1999 drawRectangle(x, y, width, height); | |
2000 return; | |
2001 } | |
2002 if (width < 0) { | |
2003 x += width; | |
2004 width = -width; | |
2005 } | |
2006 if (height < 0) { | |
2007 y += height; | |
2008 height = -height; | |
2009 } | |
2010 if (arcWidth < 0) arcWidth = -arcWidth; | |
2011 if (arcHeight < 0) arcHeight = -arcHeight; | |
2012 if (arcWidth > width) arcWidth = width; | |
2013 if (arcHeight > height) arcHeight = height; | |
2014 | |
2015 if (arcWidth < width) { | |
2016 drawLine(x+arcWidth/2, y, x+width-arcWidth/2, y); | |
2017 drawLine(x+arcWidth/2, y+height, x+width-arcWidth/2, y+height); | |
2018 } | |
2019 if (arcHeight < height) { | |
2020 drawLine(x, y+arcHeight/2, x, y+height-arcHeight/2); | |
2021 drawLine(x+width, y+arcHeight/2, x+width, y+height-arcHeight/2); | |
2022 } | |
2023 if (arcWidth !is 0 && arcHeight !is 0) { | |
2024 drawArc(x, y, arcWidth, arcHeight, 90, 90); | |
2025 drawArc(x+width-arcWidth, y, arcWidth, arcHeight, 0, 90); | |
2026 drawArc(x+width-arcWidth, y+height-arcHeight, arcWidth, arcHeight, 0, -90); | |
2027 drawArc(x, y+height-arcHeight, arcWidth, arcHeight, 180, 90); | |
2028 } | |
2029 } else { | |
2030 OS.RoundRect(handle, x,y,x+width+1,y+height+1, arcWidth, arcHeight); | |
2031 } | |
2032 } | |
2033 | |
2034 void drawRoundRectangleGdip (Gdip.Graphics gdipGraphics, Gdip.Pen pen, int x, int y, int width, int height, int arcWidth, int arcHeight) { | |
2035 int nx = x; | |
2036 int ny = y; | |
2037 int nw = width; | |
2038 int nh = height; | |
2039 int naw = arcWidth; | |
2040 int nah = arcHeight; | |
2041 | |
2042 if (nw < 0) { | |
2043 nw = 0 - nw; | |
2044 nx = nx - nw; | |
2045 } | |
2046 if (nh < 0) { | |
2047 nh = 0 - nh; | |
2048 ny = ny - nh; | |
2049 } | |
2050 if (naw < 0) | |
2051 naw = 0 - naw; | |
2052 if (nah < 0) | |
2053 nah = 0 - nah; | |
2054 | |
2055 Gdip.Graphics_TranslateTransform(gdipGraphics, data.gdipXOffset, data.gdipYOffset, Gdip.MatrixOrderPrepend); | |
2056 if (naw is 0 || nah is 0) { | |
2057 Gdip.Graphics_DrawRectangle(gdipGraphics, data.gdipPen, x, y, width, height); | |
2058 } else { | |
2059 auto path = Gdip.GraphicsPath_new(Gdip.FillModeAlternate); | |
2060 if (path is null) SWT.error(SWT.ERROR_NO_HANDLES); | |
2061 if (nw > naw) { | |
2062 if (nh > nah) { | |
2063 Gdip.GraphicsPath_AddArc(path, nx + nw - naw, ny, naw, nah, 0, -90); | |
2064 Gdip.GraphicsPath_AddArc(path, nx, ny, naw, nah, -90, -90); | |
2065 Gdip.GraphicsPath_AddArc(path, nx, ny + nh - nah, naw, nah, -180, -90); | |
2066 Gdip.GraphicsPath_AddArc(path, nx + nw - naw, ny + nh - nah, naw, nah, -270, -90); | |
2067 } else { | |
2068 Gdip.GraphicsPath_AddArc(path, nx + nw - naw, ny, naw, nh, -270, -180); | |
2069 Gdip.GraphicsPath_AddArc(path, nx, ny, naw, nh, -90, -180); | |
2070 } | |
2071 } else { | |
2072 if (nh > nah) { | |
2073 Gdip.GraphicsPath_AddArc(path, nx, ny, nw, nah, 0, -180); | |
2074 Gdip.GraphicsPath_AddArc(path, nx, ny + nh - nah, nw, nah, -180, -180); | |
2075 } else { | |
2076 Gdip.GraphicsPath_AddArc(path, nx, ny, nw, nh, 0, 360); | |
2077 } | |
2078 } | |
2079 Gdip.GraphicsPath_CloseFigure(path); | |
2080 Gdip.Graphics_DrawPath(gdipGraphics, pen, path); | |
2081 Gdip.GraphicsPath_delete(path); | |
2082 } | |
2083 Gdip.Graphics_TranslateTransform(gdipGraphics, -data.gdipXOffset, -data.gdipYOffset, Gdip.MatrixOrderPrepend); | |
2084 } | |
2085 | |
2086 /** | |
2087 * Draws the given string, using the receiver's current font and | |
2088 * foreground color. No tab expansion or carriage return processing | |
2089 * will be performed. The background of the rectangular area where | |
2090 * the string is being drawn will be filled with the receiver's | |
2091 * background color. | |
2092 * | |
2093 * @param string the string to be drawn | |
2094 * @param x the x coordinate of the top left corner of the rectangular area where the string is to be drawn | |
2095 * @param y the y coordinate of the top left corner of the rectangular area where the string is to be drawn | |
2096 * | |
2097 * @exception SWTException <ul> | |
2098 * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> | |
2099 * </ul> | |
2100 */ | |
2101 public void drawString (String string, int x, int y) { | |
2102 drawString(string, x, y, false); | |
2103 } | |
2104 | |
2105 /** | |
2106 * Draws the given string, using the receiver's current font and | |
2107 * foreground color. No tab expansion or carriage return processing | |
2108 * will be performed. If <code>isTransparent</code> is <code>true</code>, | |
2109 * then the background of the rectangular area where the string is being | |
2110 * drawn will not be modified, otherwise it will be filled with the | |
2111 * receiver's background color. | |
2112 * | |
2113 * @param string the string to be drawn | |
2114 * @param x the x coordinate of the top left corner of the rectangular area where the string is to be drawn | |
2115 * @param y the y coordinate of the top left corner of the rectangular area where the string is to be drawn | |
2116 * @param isTransparent if <code>true</code> the background will be transparent, otherwise it will be opaque | |
2117 * | |
2118 * @exception SWTException <ul> | |
2119 * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> | |
2120 * </ul> | |
2121 */ | |
2122 public void drawString (String string, int x, int y, bool isTransparent) { | |
2123 if (handle is null) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); | |
2124 // SWT extension: allow null string | |
2125 //if (string is null) SWT.error(SWT.ERROR_NULL_ARGUMENT); | |
2126 // TCHAR buffer = new TCHAR (getCodePage(), string, false); | |
2127 wchar[] wstr = StrToWCHARs( string ); | |
2128 int length_ = wstr.length; | |
2129 if (length_ is 0) return; | |
2130 wchar* buffer = wstr.ptr; | |
2131 auto gdipGraphics = data.gdipGraphics; | |
2132 if (gdipGraphics !is null) { | |
2133 checkGC(FONT | FOREGROUND | (isTransparent ? 0 : BACKGROUND)); | |
2134 Gdip.PointF pt; | |
2135 auto format = Gdip.StringFormat_Clone(Gdip.StringFormat_GenericTypographic()); | |
2136 int formatFlags = Gdip.StringFormat_GetFormatFlags(format) | Gdip.StringFormatFlagsMeasureTrailingSpaces; | |
2137 if ((data.style & SWT.MIRRORED) !is 0) formatFlags |= Gdip.StringFormatFlagsDirectionRightToLeft; | |
2138 Gdip.StringFormat_SetFormatFlags(format, formatFlags); | |
2139 if (!isTransparent) { | |
2140 Gdip.RectF bounds; | |
2141 Gdip.Graphics_MeasureString(gdipGraphics, buffer, length_, data.gdipFont, pt, format, bounds); | |
2142 Gdip.Graphics_FillRectangle(gdipGraphics, data.gdipBrush, x, y, Math.rndint(bounds.Width), Math.rndint(bounds.Height)); | |
2143 } | |
2144 int gstate = 0; | |
2145 auto brush = getFgBrush(); | |
2146 if ((data.style & SWT.MIRRORED) !is 0) { | |
2147 switch (Gdip.Brush_GetType(brush)) { | |
2148 case Gdip.BrushTypeLinearGradient: | |
2149 Gdip.LinearGradientBrush_ScaleTransform(cast(Gdip.LinearGradientBrush)brush, -1, 1, Gdip.MatrixOrderPrepend); | |
2150 Gdip.LinearGradientBrush_TranslateTransform(cast(Gdip.LinearGradientBrush)brush, - 2 * x, 0, Gdip.MatrixOrderPrepend); | |
2151 break; | |
2152 case Gdip.BrushTypeTextureFill: | |
2153 Gdip.TextureBrush_ScaleTransform(cast(Gdip.TextureBrush)brush, -1, 1, Gdip.MatrixOrderPrepend); | |
2154 Gdip.TextureBrush_TranslateTransform(cast(Gdip.TextureBrush)brush, - 2 * x, 0, Gdip.MatrixOrderPrepend); | |
2155 break; | |
2156 default: | |
2157 } | |
2158 gstate = Gdip.Graphics_Save(gdipGraphics); | |
2159 Gdip.Graphics_ScaleTransform(gdipGraphics, -1, 1, Gdip.MatrixOrderPrepend); | |
2160 Gdip.Graphics_TranslateTransform(gdipGraphics, - 2 * x, 0, Gdip.MatrixOrderPrepend); | |
2161 } | |
2162 pt.X = x; | |
2163 pt.Y = y; | |
2164 Gdip.Graphics_DrawString(gdipGraphics, buffer, length_, data.gdipFont, pt, format, brush); | |
2165 if ((data.style & SWT.MIRRORED) !is 0) { | |
2166 switch (Gdip.Brush_GetType(brush)) { | |
2167 case Gdip.BrushTypeLinearGradient: | |
2168 Gdip.LinearGradientBrush_ResetTransform(cast(Gdip.LinearGradientBrush)brush); | |
2169 break; | |
2170 case Gdip.BrushTypeTextureFill: | |
2171 Gdip.TextureBrush_ResetTransform(cast(Gdip.TextureBrush)brush); | |
2172 break; | |
2173 default: | |
2174 } | |
2175 Gdip.Graphics_Restore(gdipGraphics, gstate); | |
2176 } | |
2177 Gdip.StringFormat_delete(format); | |
2178 return; | |
2179 } | |
2180 int rop2 = 0; | |
2181 static if (OS.IsWinCE) { | |
2182 rop2 = OS.SetROP2(handle, OS.R2_COPYPEN); | |
2183 OS.SetROP2(handle, rop2); | |
2184 } else { | |
2185 rop2 = OS.GetROP2(handle); | |
2186 } | |
2187 checkGC(FONT | FOREGROUND_TEXT | BACKGROUND_TEXT); | |
2188 int oldBkMode = OS.SetBkMode(handle, isTransparent ? OS.TRANSPARENT : OS.OPAQUE); | |
2189 RECT rect; | |
2190 SIZE size; | |
2191 bool sizeValid = false; | |
2192 int flags = 0; | |
2193 if ((data.style & SWT.MIRRORED) !is 0) { | |
2194 if (!isTransparent) { | |
2195 sizeValid = true; | |
2196 OS.GetTextExtentPoint32W(handle, buffer, length_, &size); | |
2197 rect.left = x; | |
2198 rect.right = x + size.cx; | |
2199 rect.top = y; | |
2200 rect.bottom = y + size.cy; | |
2201 flags = OS.ETO_CLIPPED; | |
2202 } | |
2203 x--; | |
2204 } | |
2205 if (rop2 !is OS.R2_XORPEN) { | |
2206 OS.ExtTextOutW(handle, x, y, flags, &rect, buffer, length_, null); | |
2207 } else { | |
2208 int foreground = OS.GetTextColor(handle); | |
2209 if (isTransparent) { | |
2210 if (!sizeValid) { | |
2211 OS.GetTextExtentPoint32W(handle, buffer, length_, &size); | |
2212 } | |
2213 int width = size.cx, height = size.cy; | |
2214 auto hBitmap = OS.CreateCompatibleBitmap(handle, width, height); | |
2215 if (hBitmap is null) SWT.error(SWT.ERROR_NO_HANDLES); | |
2216 auto memDC = OS.CreateCompatibleDC(handle); | |
2217 auto hOldBitmap = OS.SelectObject(memDC, hBitmap); | |
2218 OS.PatBlt(memDC, 0, 0, width, height, OS.BLACKNESS); | |
2219 OS.SetBkMode(memDC, OS.TRANSPARENT); | |
2220 OS.SetTextColor(memDC, foreground); | |
2221 OS.SelectObject(memDC, OS.GetCurrentObject(handle, OS.OBJ_FONT)); | |
2222 OS.ExtTextOutW(memDC, 0, 0, 0, null, buffer, length_, null); | |
2223 OS.BitBlt(handle, x, y, width, height, memDC, 0, 0, OS.SRCINVERT); | |
2224 OS.SelectObject(memDC, hOldBitmap); | |
2225 OS.DeleteDC(memDC); | |
2226 OS.DeleteObject(hBitmap); | |
2227 } else { | |
2228 auto background = OS.GetBkColor(handle); | |
2229 OS.SetTextColor(handle, foreground ^ background); | |
2230 OS.ExtTextOutW(handle, x, y, flags, &rect, buffer, length_, null); | |
2231 OS.SetTextColor(handle, foreground); | |
2232 } | |
2233 } | |
2234 OS.SetBkMode(handle, oldBkMode); | |
2235 } | |
2236 | |
2237 /** | |
2238 * Draws the given string, using the receiver's current font and | |
2239 * foreground color. Tab expansion and carriage return processing | |
2240 * are performed. The background of the rectangular area where | |
2241 * the text is being drawn will be filled with the receiver's | |
2242 * background color. | |
2243 * | |
2244 * @param string the string to be drawn | |
2245 * @param x the x coordinate of the top left corner of the rectangular area where the text is to be drawn | |
2246 * @param y the y coordinate of the top left corner of the rectangular area where the text is to be drawn | |
2247 * | |
2248 * @exception SWTException <ul> | |
2249 * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> | |
2250 * </ul> | |
2251 */ | |
2252 public void drawText (String string, int x, int y) { | |
2253 drawText(string, x, y, SWT.DRAW_DELIMITER | SWT.DRAW_TAB); | |
2254 } | |
2255 | |
2256 /** | |
2257 * Draws the given string, using the receiver's current font and | |
2258 * foreground color. Tab expansion and carriage return processing | |
2259 * are performed. If <code>isTransparent</code> is <code>true</code>, | |
2260 * then the background of the rectangular area where the text is being | |
2261 * drawn will not be modified, otherwise it will be filled with the | |
2262 * receiver's background color. | |
2263 * | |
2264 * @param string the string to be drawn | |
2265 * @param x the x coordinate of the top left corner of the rectangular area where the text is to be drawn | |
2266 * @param y the y coordinate of the top left corner of the rectangular area where the text is to be drawn | |
2267 * @param isTransparent if <code>true</code> the background will be transparent, otherwise it will be opaque | |
2268 * | |
2269 * @exception SWTException <ul> | |
2270 * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> | |
2271 * </ul> | |
2272 */ | |
2273 public void drawText (String string, int x, int y, bool isTransparent) { | |
2274 int flags = SWT.DRAW_DELIMITER | SWT.DRAW_TAB; | |
2275 if (isTransparent) flags |= SWT.DRAW_TRANSPARENT; | |
2276 drawText(string, x, y, flags); | |
2277 } | |
2278 | |
2279 /** | |
2280 * Draws the given string, using the receiver's current font and | |
2281 * foreground color. Tab expansion, line delimiter and mnemonic | |
2282 * processing are performed according to the specified flags. If | |
2283 * <code>flags</code> includes <code>DRAW_TRANSPARENT</code>, | |
2284 * then the background of the rectangular area where the text is being | |
2285 * drawn will not be modified, otherwise it will be filled with the | |
2286 * receiver's background color. | |
2287 * <p> | |
2288 * The parameter <code>flags</code> may be a combination of: | |
2289 * <dl> | |
2290 * <dt><b>DRAW_DELIMITER</b></dt> | |
2291 * <dd>draw multiple lines</dd> | |
2292 * <dt><b>DRAW_TAB</b></dt> | |
2293 * <dd>expand tabs</dd> | |
2294 * <dt><b>DRAW_MNEMONIC</b></dt> | |
2295 * <dd>underline the mnemonic character</dd> | |
2296 * <dt><b>DRAW_TRANSPARENT</b></dt> | |
2297 * <dd>transparent background</dd> | |
2298 * </dl> | |
2299 * </p> | |
2300 * | |
2301 * @param string the string to be drawn | |
2302 * @param x the x coordinate of the top left corner of the rectangular area where the text is to be drawn | |
2303 * @param y the y coordinate of the top left corner of the rectangular area where the text is to be drawn | |
2304 * @param flags the flags specifying how to process the text | |
2305 * | |
2306 * @exception SWTException <ul> | |
2307 * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> | |
2308 * </ul> | |
2309 */ | |
2310 public void drawText (String string, int x, int y, int flags) { | |
2311 if (handle is null) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); | |
2312 // SWT extension: allow null string | |
2313 //if (string is null) SWT.error(SWT.ERROR_NULL_ARGUMENT); | |
2314 if (string.length is 0) return; | |
2315 auto gdipGraphics = data.gdipGraphics; | |
2316 if (gdipGraphics !is null) { | |
2317 checkGC(FONT | FOREGROUND | ((flags & SWT.DRAW_TRANSPARENT) !is 0 ? 0 : BACKGROUND)); | |
2318 wchar[] wstr = StrToWCHARs( string ); | |
2319 int length_ = wstr.length; | |
2320 wchar* buffer = wstr.ptr; | |
2321 Gdip.PointF pt; | |
2322 auto format = Gdip.StringFormat_Clone(Gdip.StringFormat_GenericTypographic()); | |
2323 int formatFlags = Gdip.StringFormat_GetFormatFlags(format) | Gdip.StringFormatFlagsMeasureTrailingSpaces; | |
2324 if ((data.style & SWT.MIRRORED) !is 0) formatFlags |= Gdip.StringFormatFlagsDirectionRightToLeft; | |
2325 Gdip.StringFormat_SetFormatFlags(format, formatFlags); | |
2326 float[] tabs = (flags & SWT.DRAW_TAB) !is 0 ? [ cast(float) measureSpace(data.gdipFont, format) * 8] : new float[1]; | |
2327 Gdip.StringFormat_SetTabStops(format, 0, tabs.length, tabs.ptr); | |
2328 int hotkeyPrefix = (flags & SWT.DRAW_MNEMONIC) !is 0 ? Gdip.HotkeyPrefixShow : Gdip.HotkeyPrefixNone; | |
2329 if ((flags & SWT.DRAW_MNEMONIC) !is 0 && (data.uiState & OS.UISF_HIDEACCEL) !is 0) hotkeyPrefix = Gdip.HotkeyPrefixHide; | |
2330 Gdip.StringFormat_SetHotkeyPrefix(format, hotkeyPrefix); | |
2331 if ((flags & SWT.DRAW_TRANSPARENT) is 0) { | |
2332 Gdip.RectF bounds; | |
2333 Gdip.Graphics_MeasureString(gdipGraphics, buffer, length_, data.gdipFont, pt, format, bounds); | |
2334 Gdip.Graphics_FillRectangle(gdipGraphics, data.gdipBrush, x, y, Math.rndint(bounds.Width), Math.rndint(bounds.Height)); | |
2335 } | |
2336 int gstate = 0; | |
2337 auto brush = getFgBrush(); | |
2338 if ((data.style & SWT.MIRRORED) !is 0) { | |
2339 switch (Gdip.Brush_GetType(brush)) { | |
2340 case Gdip.BrushTypeLinearGradient: | |
2341 Gdip.LinearGradientBrush_ScaleTransform(cast(Gdip.LinearGradientBrush)brush, -1, 1, Gdip.MatrixOrderPrepend); | |
2342 Gdip.LinearGradientBrush_TranslateTransform(cast(Gdip.LinearGradientBrush)brush, - 2 * x, 0, Gdip.MatrixOrderPrepend); | |
2343 break; | |
2344 case Gdip.BrushTypeTextureFill: | |
2345 Gdip.TextureBrush_ScaleTransform(cast(Gdip.TextureBrush)brush, -1, 1, Gdip.MatrixOrderPrepend); | |
2346 Gdip.TextureBrush_TranslateTransform(cast(Gdip.TextureBrush)brush, - 2 * x, 0, Gdip.MatrixOrderPrepend); | |
2347 break; | |
2348 default: | |
2349 } | |
2350 gstate = Gdip.Graphics_Save(gdipGraphics); | |
2351 Gdip.Graphics_ScaleTransform(gdipGraphics, -1, 1, Gdip.MatrixOrderPrepend); | |
2352 Gdip.Graphics_TranslateTransform(gdipGraphics, - 2 * x, 0, Gdip.MatrixOrderPrepend); | |
2353 } | |
2354 pt.X = x; | |
2355 pt.Y = y; | |
2356 Gdip.Graphics_DrawString(gdipGraphics, buffer, length_, data.gdipFont, pt, format, brush); | |
2357 if ((data.style & SWT.MIRRORED) !is 0) { | |
2358 switch (Gdip.Brush_GetType(brush)) { | |
2359 case Gdip.BrushTypeLinearGradient: | |
2360 Gdip.LinearGradientBrush_ResetTransform(cast(Gdip.LinearGradientBrush)brush); | |
2361 break; | |
2362 case Gdip.BrushTypeTextureFill: | |
2363 Gdip.TextureBrush_ResetTransform(cast(Gdip.TextureBrush)brush); | |
2364 break; | |
2365 default: | |
2366 } | |
2367 Gdip.Graphics_Restore(gdipGraphics, gstate); | |
2368 } | |
2369 Gdip.StringFormat_delete(format); | |
2370 return; | |
2371 } | |
2372 TCHAR[] wstr = StrToTCHARs( string ); | |
2373 TCHAR* buffer = wstr.ptr; | |
2374 int length_ = wstr.length; | |
2375 if (length_ is 0) return; | |
2376 RECT rect; | |
2377 /* | |
2378 * Feature in Windows. For some reason DrawText(), the maximum | |
2379 * value for the bottom and right coordinates for the RECT that | |
2380 * is used to position the text is different on between Windows | |
2381 * versions. If this value is larger than the maximum, nothing | |
2382 * is drawn. On Windows 98, the limit is 0x7FFF. On Windows CE, | |
2383 * NT, and 2000 it is 0x6FFFFFF. And on XP, it is 0x7FFFFFFF. | |
2384 * The fix is to use the the smaller limit for Windows 98 and the | |
2385 * larger limit on the other Windows platforms. | |
2386 */ | |
2387 int limit = OS.IsWin95 ? 0x7FFF : 0x6FFFFFF; | |
2388 OS.SetRect(&rect, x, y, limit, limit); | |
2389 int uFormat = OS.DT_LEFT; | |
2390 if ((flags & SWT.DRAW_DELIMITER) is 0) uFormat |= OS.DT_SINGLELINE; | |
2391 if ((flags & SWT.DRAW_TAB) !is 0) uFormat |= OS.DT_EXPANDTABS; | |
2392 if ((flags & SWT.DRAW_MNEMONIC) is 0) uFormat |= OS.DT_NOPREFIX; | |
2393 if ((flags & SWT.DRAW_MNEMONIC) !is 0 && (data.uiState & OS.UISF_HIDEACCEL) !is 0) { | |
2394 uFormat |= OS.DT_HIDEPREFIX; | |
2395 } | |
2396 int rop2 = 0; | |
2397 static if (OS.IsWinCE) { | |
2398 rop2 = OS.SetROP2(handle, OS.R2_COPYPEN); | |
2399 OS.SetROP2(handle, rop2); | |
2400 } else { | |
2401 rop2 = OS.GetROP2(handle); | |
2402 } | |
2403 checkGC(FONT | FOREGROUND_TEXT | BACKGROUND_TEXT); | |
2404 int oldBkMode = OS.SetBkMode(handle, (flags & SWT.DRAW_TRANSPARENT) !is 0 ? OS.TRANSPARENT : OS.OPAQUE); | |
2405 if (rop2 !is OS.R2_XORPEN) { | |
2406 OS.DrawText(handle, buffer, length_, &rect, uFormat); | |
2407 } else { | |
2408 int foreground = OS.GetTextColor(handle); | |
2409 if ((flags & SWT.DRAW_TRANSPARENT) !is 0) { | |
2410 OS.DrawText(handle, buffer, length_, &rect, uFormat | OS.DT_CALCRECT); | |
2411 int width = rect.right - rect.left; | |
2412 int height = rect.bottom - rect.top; | |
2413 auto hBitmap = OS.CreateCompatibleBitmap(handle, width, height); | |
2414 if (hBitmap is null) SWT.error(SWT.ERROR_NO_HANDLES); | |
2415 auto memDC = OS.CreateCompatibleDC(handle); | |
2416 auto hOldBitmap = OS.SelectObject(memDC, hBitmap); | |
2417 OS.PatBlt(memDC, 0, 0, width, height, OS.BLACKNESS); | |
2418 OS.SetBkMode(memDC, OS.TRANSPARENT); | |
2419 OS.SetTextColor(memDC, foreground); | |
2420 OS.SelectObject(memDC, OS.GetCurrentObject(handle, OS.OBJ_FONT)); | |
2421 OS.SetRect(&rect, 0, 0, 0x7FFF, 0x7FFF); | |
2422 OS.DrawText(memDC, buffer, length_, &rect, uFormat); | |
2423 OS.BitBlt(handle, x, y, width, height, memDC, 0, 0, OS.SRCINVERT); | |
2424 OS.SelectObject(memDC, hOldBitmap); | |
2425 OS.DeleteDC(memDC); | |
2426 OS.DeleteObject(hBitmap); | |
2427 } else { | |
2428 int background = OS.GetBkColor(handle); | |
2429 OS.SetTextColor(handle, foreground ^ background); | |
2430 OS.DrawText(handle, buffer, length_, &rect, uFormat); | |
2431 OS.SetTextColor(handle, foreground); | |
2432 } | |
2433 } | |
2434 OS.SetBkMode(handle, oldBkMode); | |
2435 } | |
2436 | |
2437 /** | |
2438 * Compares the argument to the receiver, and returns true | |
2439 * if they represent the <em>same</em> object using a class | |
2440 * specific comparison. | |
2441 * | |
2442 * @param object the object to compare with this object | |
2443 * @return <code>true</code> if the object is the same as this object and <code>false</code> otherwise | |
2444 * | |
2445 * @see #hashCode | |
2446 */ | |
2447 public bool equals (Object object) { | |
2448 return (object is this) || (null !is (cast(GC)object) && (handle is (cast(GC)object).handle)); | |
2449 } | |
2450 | |
2451 /** | |
2452 * Fills the interior of a circular or elliptical arc within | |
2453 * the specified rectangular area, with the receiver's background | |
2454 * color. | |
2455 * <p> | |
2456 * The resulting arc begins at <code>startAngle</code> and extends | |
2457 * for <code>arcAngle</code> degrees, using the current color. | |
2458 * Angles are interpreted such that 0 degrees is at the 3 o'clock | |
2459 * position. A positive value indicates a counter-clockwise rotation | |
2460 * while a negative value indicates a clockwise rotation. | |
2461 * </p><p> | |
2462 * The center of the arc is the center of the rectangle whose origin | |
2463 * is (<code>x</code>, <code>y</code>) and whose size is specified by the | |
2464 * <code>width</code> and <code>height</code> arguments. | |
2465 * </p><p> | |
2466 * The resulting arc covers an area <code>width + 1</code> pixels wide | |
2467 * by <code>height + 1</code> pixels tall. | |
2468 * </p> | |
2469 * | |
2470 * @param x the x coordinate of the upper-left corner of the arc to be filled | |
2471 * @param y the y coordinate of the upper-left corner of the arc to be filled | |
2472 * @param width the width of the arc to be filled | |
2473 * @param height the height of the arc to be filled | |
2474 * @param startAngle the beginning angle | |
2475 * @param arcAngle the angular extent of the arc, relative to the start angle | |
2476 * | |
2477 * @exception SWTException <ul> | |
2478 * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> | |
2479 * </ul> | |
2480 * | |
2481 * @see #drawArc | |
2482 */ | |
2483 public void fillArc (int x, int y, int width, int height, int startAngle, int arcAngle) { | |
2484 if (handle is null) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); | |
2485 checkGC(FILL); | |
2486 if (width < 0) { | |
2487 x = x + width; | |
2488 width = -width; | |
2489 } | |
2490 if (height < 0) { | |
2491 y = y + height; | |
2492 height = -height; | |
2493 } | |
2494 if (width is 0 || height is 0 || arcAngle is 0) return; | |
2495 auto gdipGraphics = data.gdipGraphics; | |
2496 if (gdipGraphics !is null) { | |
2497 if (width is height) { | |
2498 Gdip.Graphics_FillPie(gdipGraphics, data.gdipBrush, x, y, width, height, -startAngle, -arcAngle); | |
2499 } else { | |
2500 int state = Gdip.Graphics_Save(gdipGraphics); | |
2501 Gdip.Graphics_TranslateTransform(gdipGraphics, x, y, Gdip.MatrixOrderPrepend); | |
2502 Gdip.Graphics_ScaleTransform(gdipGraphics, width, height, Gdip.MatrixOrderPrepend); | |
2503 Gdip.Graphics_FillPie(gdipGraphics, data.gdipBrush, 0, 0, 1, 1, -startAngle, -arcAngle); | |
2504 Gdip.Graphics_Restore(gdipGraphics, state); | |
2505 } | |
2506 return; | |
2507 } | |
2508 | |
2509 if ((data.style & SWT.MIRRORED) !is 0) x--; | |
2510 /* | |
2511 * Feature in WinCE. The function Pie is not present in the | |
2512 * WinCE SDK. The fix is to emulate it by using Polygon. | |
2513 */ | |
2514 static if (OS.IsWinCE) { | |
2515 /* compute arc with a simple linear interpolation */ | |
2516 if (arcAngle < 0) { | |
2517 startAngle += arcAngle; | |
2518 arcAngle = -arcAngle; | |
2519 } | |
2520 bool drawSegments = true; | |
2521 if (arcAngle >= 360) { | |
2522 arcAngle = 360; | |
2523 drawSegments = false; | |
2524 } | |
2525 int[] points = new int[(arcAngle + 1) * 2 + (drawSegments ? 4 : 0)]; | |
2526 int cteX = 2 * x + width; | |
2527 int cteY = 2 * y + height; | |
2528 int index = (drawSegments ? 2 : 0); | |
2529 for (int i = 0; i <= arcAngle; i++) { | |
2530 points[index++] = (Compatibility.cos(startAngle + i, width) + cteX) >> 1; | |
2531 points[index++] = (cteY - Compatibility.sin(startAngle + i, height)) >> 1; | |
2532 } | |
2533 if (drawSegments) { | |
2534 points[0] = points[points.length - 2] = cteX >> 1; | |
2535 points[1] = points[points.length - 1] = cteY >> 1; | |
2536 } | |
2537 OS.Polygon(handle, cast(POINT*)points.ptr, points.length / 2); | |
2538 } else { | |
2539 int x1, y1, x2, y2,tmp; | |
2540 bool isNegative; | |
2541 if (arcAngle >= 360 || arcAngle <= -360) { | |
2542 x1 = x2 = x + width; | |
2543 y1 = y2 = y + height / 2; | |
2544 } else { | |
2545 isNegative = arcAngle < 0; | |
2546 | |
2547 arcAngle = arcAngle + startAngle; | |
2548 if (isNegative) { | |
2549 // swap angles | |
2550 tmp = startAngle; | |
2551 startAngle = arcAngle; | |
2552 arcAngle = tmp; | |
2553 } | |
2554 x1 = Compatibility.cos(startAngle, width) + x + width/2; | |
2555 y1 = -1 * Compatibility.sin(startAngle, height) + y + height/2; | |
2556 | |
2557 x2 = Compatibility.cos(arcAngle, width) + x + width/2; | |
2558 y2 = -1 * Compatibility.sin(arcAngle, height) + y + height/2; | |
2559 } | |
2560 OS.Pie(handle, x, y, x + width + 1, y + height + 1, x1, y1, x2, y2); | |
2561 } | |
2562 } | |
2563 | |
2564 /** | |
2565 * Fills the interior of the specified rectangle with a gradient | |
2566 * sweeping from left to right or top to bottom progressing | |
2567 * from the receiver's foreground color to its background color. | |
2568 * | |
2569 * @param x the x coordinate of the rectangle to be filled | |
2570 * @param y the y coordinate of the rectangle to be filled | |
2571 * @param width the width of the rectangle to be filled, may be negative | |
2572 * (inverts direction of gradient if horizontal) | |
2573 * @param height the height of the rectangle to be filled, may be negative | |
2574 * (inverts direction of gradient if vertical) | |
2575 * @param vertical if true sweeps from top to bottom, else | |
2576 * sweeps from left to right | |
2577 * | |
2578 * @exception SWTException <ul> | |
2579 * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> | |
2580 * </ul> | |
2581 * | |
2582 * @see #drawRectangle(int, int, int, int) | |
2583 */ | |
2584 public void fillGradientRectangle(int x, int y, int width, int height, bool vertical) { | |
2585 if (handle is null) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); | |
2586 if (width is 0 || height is 0) return; | |
2587 | |
2588 RGB backgroundRGB, foregroundRGB; | |
2589 backgroundRGB = getBackground().getRGB(); | |
2590 foregroundRGB = getForeground().getRGB(); | |
2591 | |
2592 RGB fromRGB, toRGB; | |
2593 fromRGB = foregroundRGB; | |
2594 toRGB = backgroundRGB; | |
2595 | |
2596 bool swapColors = false; | |
2597 if (width < 0) { | |
2598 x += width; width = -width; | |
2599 if (! vertical) swapColors = true; | |
2600 } | |
2601 if (height < 0) { | |
2602 y += height; height = -height; | |
2603 if (vertical) swapColors = true; | |
2604 } | |
2605 if (swapColors) { | |
2606 fromRGB = backgroundRGB; | |
2607 toRGB = foregroundRGB; | |
2608 } | |
2609 if (fromRGB ==/*eq*/ toRGB) { | |
2610 fillRectangle(x, y, width, height); | |
2611 return; | |
2612 } | |
2613 if (data.gdipGraphics !is null) { | |
2614 initGdip(); | |
2615 Gdip.PointF p1, p2; | |
2616 p1.X = x; | |
2617 p1.Y = y; | |
2618 if (vertical) { | |
2619 p2.X = p1.X; | |
2620 p2.Y = p1.Y + height; | |
2621 } else { | |
2622 p2.X = p1.X + width; | |
2623 p2.Y = p1.Y; | |
2624 } | |
2625 int rgb = ((fromRGB.red & 0xFF) << 16) | ((fromRGB.green & 0xFF) << 8) | (fromRGB.blue & 0xFF); | |
2626 auto fromGpColor = Gdip.Color_new(data.alpha << 24 | rgb); | |
2627 //if (fromGpColor is null) SWT.error(SWT.ERROR_NO_HANDLES); | |
2628 rgb = ((toRGB.red & 0xFF) << 16) | ((toRGB.green & 0xFF) << 8) | (toRGB.blue & 0xFF); | |
2629 auto toGpColor = Gdip.Color_new(data.alpha << 24 | rgb); | |
2630 //if (toGpColor is null) SWT.error(SWT.ERROR_NO_HANDLES); | |
2631 auto brush = Gdip.LinearGradientBrush_new(p1, p2, fromGpColor, toGpColor); | |
2632 Gdip.Graphics_FillRectangle(data.gdipGraphics, cast(Gdip.Brush)brush, x, y, width, height); | |
2633 Gdip.LinearGradientBrush_delete(brush); | |
2634 Gdip.Color_delete(fromGpColor); | |
2635 Gdip.Color_delete(toGpColor); | |
2636 return; | |
2637 } | |
2638 /* Use GradientFill if supported, only on Windows 98, 2000 and newer. */ | |
2639 /* | |
2640 * Bug in Windows: On Windows 2000 when the device is a printer, | |
2641 * GradientFill swaps red and blue color components, causing the | |
2642 * gradient to be printed in the wrong color. On Windows 98 when | |
2643 * the device is a printer, GradientFill does not fill completely | |
2644 * to the right edge of the rectangle. The fix is not to use | |
2645 * GradientFill for printer devices. | |
2646 */ | |
2647 int rop2 = 0; | |
2648 static if (OS.IsWinCE) { | |
2649 rop2 = OS.SetROP2(handle, OS.R2_COPYPEN); | |
2650 OS.SetROP2(handle, rop2); | |
2651 } else { | |
2652 rop2 = OS.GetROP2(handle); | |
2653 } | |
2654 if (OS.IsWinNT && rop2 !is OS.R2_XORPEN && OS.GetDeviceCaps(handle, OS.TECHNOLOGY) !is OS.DT_RASPRINTER) { | |
2655 final auto hHeap = OS.GetProcessHeap(); | |
2656 final auto pMesh = OS.HeapAlloc(hHeap, OS.HEAP_ZERO_MEMORY, GRADIENT_RECT.sizeof + TRIVERTEX.sizeof * 2); | |
2657 if (pMesh is null) SWT.error(SWT.ERROR_NO_HANDLES); | |
2658 auto pVertex = cast(TRIVERTEX*)( pMesh + GRADIENT_RECT.sizeof ); | |
2659 | |
2660 GRADIENT_RECT gradientRect; | |
2661 gradientRect.UpperLeft = 0; | |
2662 gradientRect.LowerRight = 1; | |
2663 *cast(GRADIENT_RECT*)pMesh = gradientRect; | |
2664 | |
2665 TRIVERTEX* trivertex = pVertex; | |
2666 trivertex.x = x; | |
2667 trivertex.y = y; | |
2668 trivertex.Red = cast(short)((fromRGB.red << 8) | fromRGB.red); | |
2669 trivertex.Green = cast(short)((fromRGB.green << 8) | fromRGB.green); | |
2670 trivertex.Blue = cast(short)((fromRGB.blue << 8) | fromRGB.blue); | |
2671 trivertex.Alpha = ushort.max; | |
2672 | |
2673 trivertex = pVertex+1; | |
2674 trivertex.x = x + width; | |
2675 trivertex.y = y + height; | |
2676 trivertex.Red = cast(short)((toRGB.red << 8) | toRGB.red); | |
2677 trivertex.Green = cast(short)((toRGB.green << 8) | toRGB.green); | |
2678 trivertex.Blue = cast(short)((toRGB.blue << 8) | toRGB.blue); | |
2679 trivertex.Alpha = ushort.max; | |
2680 | |
2681 bool success = cast(bool)OS.GradientFill(handle, pVertex, 2, pMesh, 1, vertical ? OS.GRADIENT_FILL_RECT_V : OS.GRADIENT_FILL_RECT_H); | |
2682 OS.HeapFree(hHeap, 0, pMesh); | |
2683 if (success) return; | |
2684 } | |
2685 | |
2686 final int depth = OS.GetDeviceCaps(handle, OS.BITSPIXEL); | |
2687 final int bitResolution = (depth >= 24) ? 8 : (depth >= 15) ? 5 : 0; | |
2688 ImageData.fillGradientRectangle(this, data.device, | |
2689 x, y, width, height, vertical, fromRGB, toRGB, | |
2690 bitResolution, bitResolution, bitResolution); | |
2691 } | |
2692 | |
2693 /** | |
2694 * Fills the interior of an oval, within the specified | |
2695 * rectangular area, with the receiver's background | |
2696 * color. | |
2697 * | |
2698 * @param x the x coordinate of the upper left corner of the oval to be filled | |
2699 * @param y the y coordinate of the upper left corner of the oval to be filled | |
2700 * @param width the width of the oval to be filled | |
2701 * @param height the height of the oval to be filled | |
2702 * | |
2703 * @exception SWTException <ul> | |
2704 * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> | |
2705 * </ul> | |
2706 * | |
2707 * @see #drawOval | |
2708 */ | |
2709 public void fillOval (int x, int y, int width, int height) { | |
2710 if (handle is null) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); | |
2711 checkGC(FILL); | |
2712 if (data.gdipGraphics !is null) { | |
2713 Gdip.Graphics_FillEllipse(data.gdipGraphics, data.gdipBrush, x, y, width, height); | |
2714 return; | |
2715 } | |
2716 if ((data.style & SWT.MIRRORED) !is 0) x--; | |
2717 OS.Ellipse(handle, x, y, x + width + 1, y + height + 1); | |
2718 } | |
2719 | |
2720 /** | |
2721 * Fills the path described by the parameter. | |
2722 * <p> | |
2723 * This operation requires the operating system's advanced | |
2724 * graphics subsystem which may not be available on some | |
2725 * platforms. | |
2726 * </p> | |
2727 * | |
2728 * @param path the path to fill | |
2729 * | |
2730 * @exception IllegalArgumentException <ul> | |
2731 * <li>ERROR_NULL_ARGUMENT - if the parameter is null</li> | |
2732 * <li>ERROR_INVALID_ARGUMENT - if the parameter has been disposed</li> | |
2733 * </ul> | |
2734 * @exception SWTException <ul> | |
2735 * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> | |
2736 * <li>ERROR_NO_GRAPHICS_LIBRARY - if advanced graphics are not available</li> | |
2737 * </ul> | |
2738 * | |
2739 * @see Path | |
2740 * | |
2741 * @since 3.1 | |
2742 */ | |
2743 public void fillPath (Path path) { | |
2744 if (handle is null) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); | |
2745 if (path is null) SWT.error(SWT.ERROR_NULL_ARGUMENT); | |
2746 if (path.handle is null) SWT.error(SWT.ERROR_INVALID_ARGUMENT); | |
2747 initGdip(); | |
2748 checkGC(FILL); | |
2749 int mode = OS.GetPolyFillMode(handle) is OS.WINDING ? Gdip.FillModeWinding : Gdip.FillModeAlternate; | |
2750 Gdip.GraphicsPath_SetFillMode(path.handle, mode); | |
2751 Gdip.Graphics_FillPath(data.gdipGraphics, data.gdipBrush, path.handle); | |
2752 } | |
2753 | |
2754 /** | |
2755 * Fills the interior of the closed polygon which is defined by the | |
2756 * specified array of integer coordinates, using the receiver's | |
2757 * background color. The array contains alternating x and y values | |
2758 * which are considered to represent points which are the vertices of | |
2759 * the polygon. Lines are drawn between each consecutive pair, and | |
2760 * between the first pair and last pair in the array. | |
2761 * | |
2762 * @param pointArray an array of alternating x and y values which are the vertices of the polygon | |
2763 * | |
2764 * @exception SWTException <ul> | |
2765 * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> | |
2766 * </ul> | |
2767 * | |
2768 * @see #drawPolygon | |
2769 */ | |
2770 public void fillPolygon(int[] pointArray) { | |
2771 if (handle is null) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); | |
2772 // SWT externsion: allow null array | |
2773 //if (pointArray is null) SWT.error(SWT.ERROR_NULL_ARGUMENT); | |
2774 checkGC(FILL); | |
2775 if (data.gdipGraphics !is null) { | |
2776 int mode = OS.GetPolyFillMode(handle) is OS.WINDING ? Gdip.FillModeWinding : Gdip.FillModeAlternate; | |
2777 Gdip.Graphics_FillPolygon(data.gdipGraphics, data.gdipBrush, cast(Gdip.Point*)pointArray.ptr, pointArray.length / 2, mode); | |
2778 return; | |
2779 } | |
2780 if ((data.style & SWT.MIRRORED) !is 0) { | |
2781 for (int i = 0; i < pointArray.length; i+=2) { | |
2782 pointArray[i]--; | |
2783 } | |
2784 } | |
2785 OS.Polygon(handle, cast(POINT*)pointArray.ptr, pointArray.length / 2); | |
2786 if ((data.style & SWT.MIRRORED) !is 0) { | |
2787 for (int i = 0; i < pointArray.length; i+=2) { | |
2788 pointArray[i]++; | |
2789 } | |
2790 } | |
2791 } | |
2792 | |
2793 /** | |
2794 * Fills the interior of the rectangle specified by the arguments, | |
2795 * using the receiver's background color. | |
2796 * | |
2797 * @param x the x coordinate of the rectangle to be filled | |
2798 * @param y the y coordinate of the rectangle to be filled | |
2799 * @param width the width of the rectangle to be filled | |
2800 * @param height the height of the rectangle to be filled | |
2801 * | |
2802 * @exception SWTException <ul> | |
2803 * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> | |
2804 * </ul> | |
2805 * | |
2806 * @see #drawRectangle(int, int, int, int) | |
2807 */ | |
2808 public void fillRectangle (int x, int y, int width, int height) { | |
2809 if (handle is null) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); | |
2810 checkGC(FILL); | |
2811 if (data.gdipGraphics !is null) { | |
2812 if (width < 0) { | |
2813 x = x + width; | |
2814 width = -width; | |
2815 } | |
2816 if (height < 0) { | |
2817 y = y + height; | |
2818 height = -height; | |
2819 } | |
2820 Gdip.Graphics_FillRectangle(data.gdipGraphics, data.gdipBrush, x, y, width, height); | |
2821 return; | |
2822 } | |
2823 int rop2 = 0; | |
2824 static if (OS.IsWinCE) { | |
2825 rop2 = OS.SetROP2(handle, OS.R2_COPYPEN); | |
2826 OS.SetROP2(handle, rop2); | |
2827 } else { | |
2828 rop2 = OS.GetROP2(handle); | |
2829 } | |
2830 int dwRop = rop2 is OS.R2_XORPEN ? OS.PATINVERT : OS.PATCOPY; | |
2831 OS.PatBlt(handle, x, y, width, height, dwRop); | |
2832 } | |
2833 | |
2834 /** | |
2835 * Fills the interior of the specified rectangle, using the receiver's | |
2836 * background color. | |
2837 * | |
2838 * @param rect the rectangle to be filled | |
2839 * | |
2840 * @exception IllegalArgumentException <ul> | |
2841 * <li>ERROR_NULL_ARGUMENT - if the rectangle is null</li> | |
2842 * </ul> | |
2843 * @exception SWTException <ul> | |
2844 * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> | |
2845 * </ul> | |
2846 * | |
2847 * @see #drawRectangle(int, int, int, int) | |
2848 */ | |
2849 public void fillRectangle (Rectangle rect) { | |
2850 if (rect is null) SWT.error(SWT.ERROR_NULL_ARGUMENT); | |
2851 fillRectangle (rect.x, rect.y, rect.width, rect.height); | |
2852 } | |
2853 | |
2854 /** | |
2855 * Fills the interior of the round-cornered rectangle specified by | |
2856 * the arguments, using the receiver's background color. | |
2857 * | |
2858 * @param x the x coordinate of the rectangle to be filled | |
2859 * @param y the y coordinate of the rectangle to be filled | |
2860 * @param width the width of the rectangle to be filled | |
2861 * @param height the height of the rectangle to be filled | |
2862 * @param arcWidth the width of the arc | |
2863 * @param arcHeight the height of the arc | |
2864 * | |
2865 * @exception SWTException <ul> | |
2866 * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> | |
2867 * </ul> | |
2868 * | |
2869 * @see #drawRoundRectangle | |
2870 */ | |
2871 public void fillRoundRectangle (int x, int y, int width, int height, int arcWidth, int arcHeight) { | |
2872 if (handle is null) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); | |
2873 checkGC(FILL); | |
2874 if (data.gdipGraphics !is null) { | |
2875 fillRoundRectangleGdip(data.gdipGraphics, data.gdipBrush, x, y, width, height, arcWidth, arcHeight); | |
2876 return; | |
2877 } | |
2878 if ((data.style & SWT.MIRRORED) !is 0) x--; | |
2879 OS.RoundRect(handle, x,y,x+width+1,y+height+1,arcWidth, arcHeight); | |
2880 } | |
2881 | |
2882 void fillRoundRectangleGdip (Gdip.Graphics gdipGraphics, Gdip.Brush brush, int x, int y, int width, int height, int arcWidth, int arcHeight) { | |
2883 int nx = x; | |
2884 int ny = y; | |
2885 int nw = width; | |
2886 int nh = height; | |
2887 int naw = arcWidth; | |
2888 int nah = arcHeight; | |
2889 | |
2890 if (nw < 0) { | |
2891 nw = 0 - nw; | |
2892 nx = nx - nw; | |
2893 } | |
2894 if (nh < 0) { | |
2895 nh = 0 - nh; | |
2896 ny = ny -nh; | |
2897 } | |
2898 if (naw < 0) | |
2899 naw = 0 - naw; | |
2900 if (nah < 0) | |
2901 nah = 0 - nah; | |
2902 | |
2903 if (naw is 0 || nah is 0) { | |
2904 Gdip.Graphics_FillRectangle(data.gdipGraphics, data.gdipBrush, x, y, width, height); | |
2905 } else { | |
2906 auto path = Gdip.GraphicsPath_new(Gdip.FillModeAlternate); | |
2907 if (path is null) SWT.error(SWT.ERROR_NO_HANDLES); | |
2908 if (nw > naw) { | |
2909 if (nh > nah) { | |
2910 Gdip.GraphicsPath_AddArc(path, nx + nw - naw, ny, naw, nah, 0, -90); | |
2911 Gdip.GraphicsPath_AddArc(path, nx, ny, naw, nah, -90, -90); | |
2912 Gdip.GraphicsPath_AddArc(path, nx, ny + nh - nah, naw, nah, -180, -90); | |
2913 Gdip.GraphicsPath_AddArc(path, nx + nw - naw, ny + nh - nah, naw, nah, -270, -90); | |
2914 } else { | |
2915 Gdip.GraphicsPath_AddArc(path, nx + nw - naw, ny, naw, nh, -270, -180); | |
2916 Gdip.GraphicsPath_AddArc(path, nx, ny, naw, nh, -90, -180); | |
2917 } | |
2918 } else { | |
2919 if (nh > nah) { | |
2920 Gdip.GraphicsPath_AddArc(path, nx, ny, nw, nah, 0, -180); | |
2921 Gdip.GraphicsPath_AddArc(path, nx, ny + nh - nah, nw, nah, -180, -180); | |
2922 } else { | |
2923 Gdip.GraphicsPath_AddArc(path, nx, ny, nw, nh, 0, 360); | |
2924 } | |
2925 } | |
2926 Gdip.GraphicsPath_CloseFigure(path); | |
2927 Gdip.Graphics_FillPath(gdipGraphics, brush, path); | |
2928 Gdip.GraphicsPath_delete(path); | |
2929 } | |
2930 } | |
2931 | |
2932 void flush () { | |
2933 if (data.gdipGraphics !is null) { | |
2934 Gdip.Graphics_Flush(data.gdipGraphics, 0); | |
2935 /* | |
2936 * Note Flush() does not flush the output to the | |
2937 * underline HDC. This is done by calling GetHDC() | |
2938 * followed by ReleaseHDC(). | |
2939 */ | |
2940 auto hdc = Gdip.Graphics_GetHDC(data.gdipGraphics); | |
2941 Gdip.Graphics_ReleaseHDC(data.gdipGraphics, hdc); | |
2942 } | |
2943 } | |
2944 | |
2945 /** | |
2946 * Returns the <em>advance width</em> of the specified character in | |
2947 * the font which is currently selected into the receiver. | |
2948 * <p> | |
2949 * The advance width is defined as the horizontal distance the cursor | |
2950 * should move after printing the character in the selected font. | |
2951 * </p> | |
2952 * | |
2953 * @param ch the character to measure | |
2954 * @return the distance in the x direction to move past the character before painting the next | |
2955 * | |
2956 * @exception SWTException <ul> | |
2957 * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> | |
2958 * </ul> | |
2959 */ | |
2960 public int getAdvanceWidth(char ch) { | |
2961 if (handle is null) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); | |
2962 checkGC(FONT); | |
2963 static if (OS.IsWinCE) { | |
2964 SIZE size; | |
2965 OS.GetTextExtentPoint32W(handle, [ch], 1, &size); | |
2966 return size.cx; | |
2967 } | |
2968 int tch = ch; | |
2969 if (ch > 0x7F) { | |
2970 char[1] str; | |
2971 str[0] = ch; | |
2972 TCHAR[] buffer = StrToTCHARs( str ); | |
2973 tch = buffer[0]; | |
2974 } | |
2975 int width; | |
2976 OS.GetCharWidth(handle, tch, tch, &width); | |
2977 return width; | |
2978 } | |
2979 | |
2980 /** | |
2981 * Returns <code>true</code> if receiver is using the operating system's | |
2982 * advanced graphics subsystem. Otherwise, <code>false</code> is returned | |
2983 * to indicate that normal graphics are in use. | |
2984 * <p> | |
2985 * Advanced graphics may not be installed for the operating system. In this | |
2986 * case, <code>false</code> is always returned. Some operating system have | |
2987 * only one graphics subsystem. If this subsystem supports advanced graphics, | |
2988 * then <code>true</code> is always returned. If any graphics operation such | |
2989 * as alpha, antialias, patterns, interpolation, paths, clipping or transformation | |
2990 * has caused the receiver to switch from regular to advanced graphics mode, | |
2991 * <code>true</code> is returned. If the receiver has been explicitly switched | |
2992 * to advanced mode and this mode is supported, <code>true</code> is returned. | |
2993 * </p> | |
2994 * | |
2995 * @return the advanced value | |
2996 * | |
2997 * @exception SWTException <ul> | |
2998 * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> | |
2999 * </ul> | |
3000 * | |
3001 * @see #setAdvanced | |
3002 * | |
3003 * @since 3.1 | |
3004 */ | |
3005 public bool getAdvanced() { | |
3006 if (handle is null) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); | |
3007 return data.gdipGraphics !is null; | |
3008 } | |
3009 | |
3010 /** | |
3011 * Returns the receiver's alpha value. The alpha value | |
3012 * is between 0 (transparent) and 255 (opaque). | |
3013 * | |
3014 * @return the alpha value | |
3015 * | |
3016 * @exception SWTException <ul> | |
3017 * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> | |
3018 * </ul> | |
3019 * | |
3020 * @since 3.1 | |
3021 */ | |
3022 public int getAlpha() { | |
3023 if (handle is null) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); | |
3024 return data.alpha; | |
3025 } | |
3026 | |
3027 /** | |
3028 * Returns the receiver's anti-aliasing setting value, which will be | |
3029 * one of <code>SWT.DEFAULT</code>, <code>SWT.OFF</code> or | |
3030 * <code>SWT.ON</code>. Note that this controls anti-aliasing for all | |
3031 * <em>non-text drawing</em> operations. | |
3032 * | |
3033 * @return the anti-aliasing setting | |
3034 * | |
3035 * @exception SWTException <ul> | |
3036 * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> | |
3037 * </ul> | |
3038 * | |
3039 * @see #getTextAntialias | |
3040 * | |
3041 * @since 3.1 | |
3042 */ | |
3043 public int getAntialias() { | |
3044 if (handle is null) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); | |
3045 if (data.gdipGraphics is null) return SWT.DEFAULT; | |
3046 int mode = Gdip.Graphics_GetSmoothingMode(data.gdipGraphics); | |
3047 switch (mode) { | |
3048 case Gdip.SmoothingModeDefault: return SWT.DEFAULT; | |
3049 case Gdip.SmoothingModeHighSpeed: | |
3050 case Gdip.SmoothingModeNone: return SWT.OFF; | |
3051 case Gdip.SmoothingModeAntiAlias: | |
3052 case Gdip.SmoothingModeAntiAlias8x8: | |
3053 case Gdip.SmoothingModeHighQuality: return SWT.ON; | |
3054 default: | |
3055 } | |
3056 return SWT.DEFAULT; | |
3057 } | |
3058 | |
3059 /** | |
3060 * Returns the background color. | |
3061 * | |
3062 * @return the receiver's background color | |
3063 * | |
3064 * @exception SWTException <ul> | |
3065 * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> | |
3066 * </ul> | |
3067 */ | |
3068 public Color getBackground() { | |
3069 if (handle is null) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); | |
3070 return Color.win32_new(data.device, data.background); | |
3071 } | |
3072 | |
3073 /** | |
3074 * Returns the background pattern. The default value is | |
3075 * <code>null</code>. | |
3076 * | |
3077 * @return the receiver's background pattern | |
3078 * | |
3079 * @exception SWTException <ul> | |
3080 * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> | |
3081 * </ul> | |
3082 * | |
3083 * @see Pattern | |
3084 * | |
3085 * @since 3.1 | |
3086 */ | |
3087 public Pattern getBackgroundPattern() { | |
3088 if (handle is null) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); | |
3089 return data.backgroundPattern; | |
3090 } | |
3091 | |
3092 /** | |
3093 * Returns the width of the specified character in the font | |
3094 * selected into the receiver. | |
3095 * <p> | |
3096 * The width is defined as the space taken up by the actual | |
3097 * character, not including the leading and tailing whitespace | |
3098 * or overhang. | |
3099 * </p> | |
3100 * | |
3101 * @param ch the character to measure | |
3102 * @return the width of the character | |
3103 * | |
3104 * @exception SWTException <ul> | |
3105 * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> | |
3106 * </ul> | |
3107 */ | |
3108 public int getCharWidth(char ch) { | |
3109 if (handle is null) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); | |
3110 checkGC(FONT); | |
3111 | |
3112 /* GetCharABCWidths only succeeds on truetype fonts */ | |
3113 static if (!OS.IsWinCE) { | |
3114 int tch = ch; | |
3115 if (ch > 0x7F) { | |
3116 char[1] str; | |
3117 str[0] = ch; | |
3118 TCHAR[] buffer = StrToTCHARs( str ); | |
3119 tch = buffer[0]; | |
3120 } | |
3121 ABC abc; | |
3122 if (OS.GetCharABCWidths(handle, tch, tch, &abc)) { | |
3123 return abc.abcA; | |
3124 } | |
3125 } | |
3126 | |
3127 /* It wasn't a truetype font */ | |
3128 TEXTMETRIC lptm; | |
3129 OS.GetTextMetrics(handle, &lptm); | |
3130 SIZE size; | |
3131 char[1] str; | |
3132 str[0] = ch; | |
3133 OS.GetTextExtentPoint32W(handle, StrToWCHARz( str ), 1, &size); | |
3134 return size.cx - lptm.tmOverhang; | |
3135 } | |
3136 | |
3137 /** | |
3138 * Returns the bounding rectangle of the receiver's clipping | |
3139 * region. If no clipping region is set, the return value | |
3140 * will be a rectangle which covers the entire bounds of the | |
3141 * object the receiver is drawing on. | |
3142 * | |
3143 * @return the bounding rectangle of the clipping region | |
3144 * | |
3145 * @exception SWTException <ul> | |
3146 * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> | |
3147 * </ul> | |
3148 */ | |
3149 public Rectangle getClipping() { | |
3150 if (handle is null) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); | |
3151 auto gdipGraphics = data.gdipGraphics; | |
3152 if (gdipGraphics !is null) { | |
3153 Gdip.Rect rect; | |
3154 Gdip.Graphics_SetPixelOffsetMode(gdipGraphics, Gdip.PixelOffsetModeNone); | |
3155 Gdip.Graphics_GetVisibleClipBounds(gdipGraphics, rect); | |
3156 Gdip.Graphics_SetPixelOffsetMode(gdipGraphics, Gdip.PixelOffsetModeHalf); | |
3157 return new Rectangle(rect.X, rect.Y, rect.Width, rect.Height); | |
3158 } | |
3159 RECT rect; | |
3160 OS.GetClipBox(handle, &rect); | |
3161 return new Rectangle(rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top); | |
3162 } | |
3163 | |
3164 /** | |
3165 * Sets the region managed by the argument to the current | |
3166 * clipping region of the receiver. | |
3167 * | |
3168 * @param region the region to fill with the clipping region | |
3169 * | |
3170 * @exception IllegalArgumentException <ul> | |
3171 * <li>ERROR_NULL_ARGUMENT - if the region is null</li> | |
3172 * <li>ERROR_INVALID_ARGUMENT - if the region is disposed</li> | |
3173 * </ul> | |
3174 * @exception SWTException <ul> | |
3175 * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> | |
3176 * </ul> | |
3177 */ | |
3178 public void getClipping (Region region) { | |
3179 if (handle is null) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); | |
3180 if (region is null) SWT.error (SWT.ERROR_NULL_ARGUMENT); | |
3181 if (region.isDisposed()) SWT.error (SWT.ERROR_INVALID_ARGUMENT); | |
3182 auto gdipGraphics = data.gdipGraphics; | |
3183 if (gdipGraphics !is null) { | |
3184 auto rgn = Gdip.Region_new(); | |
3185 Gdip.Graphics_GetClip(data.gdipGraphics, rgn); | |
3186 if (Gdip.Region_IsInfinite(rgn, gdipGraphics)) { | |
3187 Gdip.Rect rect; | |
3188 Gdip.Graphics_SetPixelOffsetMode(gdipGraphics, Gdip.PixelOffsetModeNone); | |
3189 Gdip.Graphics_GetVisibleClipBounds(gdipGraphics, rect); | |
3190 Gdip.Graphics_SetPixelOffsetMode(gdipGraphics, Gdip.PixelOffsetModeHalf); | |
3191 OS.SetRectRgn(region.handle, rect.X, rect.Y, rect.X + rect.Width, rect.Y + rect.Height); | |
3192 } else { | |
3193 auto matrix = Gdip.Matrix_new(1, 0, 0, 1, 0, 0); | |
3194 auto identity_ = Gdip.Matrix_new(1, 0, 0, 1, 0, 0); | |
3195 Gdip.Graphics_GetTransform(gdipGraphics, matrix); | |
3196 Gdip.Graphics_SetTransform(gdipGraphics, identity_); | |
3197 auto hRgn = Gdip.Region_GetHRGN(rgn, data.gdipGraphics); | |
3198 Gdip.Graphics_SetTransform(gdipGraphics, matrix); | |
3199 Gdip.Matrix_delete(identity_); | |
3200 Gdip.Matrix_delete(matrix); | |
3201 OS.CombineRgn(region.handle, hRgn, null, OS.RGN_COPY); | |
3202 OS.DeleteObject(hRgn); | |
3203 } | |
3204 Gdip.Region_delete(rgn); | |
3205 return; | |
3206 } | |
3207 POINT pt; | |
3208 static if (!OS.IsWinCE) OS.GetWindowOrgEx (handle, &pt); | |
3209 int result = OS.GetClipRgn (handle, region.handle); | |
3210 if (result !is 1) { | |
3211 RECT rect; | |
3212 OS.GetClipBox(handle, &rect); | |
3213 OS.SetRectRgn(region.handle, rect.left, rect.top, rect.right, rect.bottom); | |
3214 } else { | |
3215 OS.OffsetRgn (region.handle, pt.x, pt.y); | |
3216 } | |
3217 static if (!OS.IsWinCE) { | |
3218 auto metaRgn = OS.CreateRectRgn (0, 0, 0, 0); | |
3219 if (OS.GetMetaRgn (handle, metaRgn) !is 0) { | |
3220 OS.OffsetRgn (metaRgn, pt.x, pt.y); | |
3221 OS.CombineRgn (region.handle, metaRgn, region.handle, OS.RGN_AND); | |
3222 } | |
3223 OS.DeleteObject(metaRgn); | |
3224 auto hwnd = data.hwnd; | |
3225 if (hwnd !is null && data.ps !is null) { | |
3226 auto sysRgn = OS.CreateRectRgn (0, 0, 0, 0); | |
3227 if (OS.GetRandomRgn (handle, sysRgn, OS.SYSRGN) is 1) { | |
3228 if (OS.WIN32_VERSION >= OS.VERSION(4, 10)) { | |
3229 if ((OS.GetLayout(handle) & OS.LAYOUT_RTL) !is 0) { | |
3230 int nBytes = OS.GetRegionData (sysRgn, 0, null); | |
3231 int [] lpRgnData = new int [nBytes / 4]; | |
3232 OS.GetRegionData (sysRgn, nBytes, cast(RGNDATA*)lpRgnData.ptr); | |
3233 auto newSysRgn = OS.ExtCreateRegion( cast(XFORM*) [-1, 0, 0, 1, 0, 0].ptr, nBytes, cast(RGNDATA*)lpRgnData.ptr); | |
3234 OS.DeleteObject(sysRgn); | |
3235 sysRgn = newSysRgn; | |
3236 } | |
3237 } | |
3238 if (OS.IsWinNT) { | |
3239 OS.MapWindowPoints(null, hwnd, &pt, 1); | |
3240 OS.OffsetRgn(sysRgn, pt.x, pt.y); | |
3241 } | |
3242 OS.CombineRgn (region.handle, sysRgn, region.handle, OS.RGN_AND); | |
3243 } | |
3244 OS.DeleteObject(sysRgn); | |
3245 } | |
3246 } | |
3247 } | |
3248 | |
3249 int getCodePage () { | |
3250 if (OS.IsUnicode) return OS.CP_ACP; | |
3251 CHARSETINFO csi; | |
3252 auto cs = OS.GetTextCharset(handle); | |
3253 OS.TranslateCharsetInfo( cast(DWORD*)cs, &csi, OS.TCI_SRCCHARSET); | |
3254 return csi.ciACP; | |
3255 } | |
3256 | |
3257 Gdip.Brush getFgBrush() { | |
3258 return data.foregroundPattern !is null ? data.foregroundPattern.handle : cast(Gdip.Brush)data.gdipFgBrush; | |
3259 } | |
3260 | |
3261 /** | |
3262 * Returns the receiver's fill rule, which will be one of | |
3263 * <code>SWT.FILL_EVEN_ODD</code> or <code>SWT.FILL_WINDING</code>. | |
3264 * | |
3265 * @return the receiver's fill rule | |
3266 * | |
3267 * @exception SWTException <ul> | |
3268 * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> | |
3269 * </ul> | |
3270 * | |
3271 * @since 3.1 | |
3272 */ | |
3273 public int getFillRule() { | |
3274 if (handle is null) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); | |
3275 static if (OS.IsWinCE) return SWT.FILL_EVEN_ODD; | |
3276 return OS.GetPolyFillMode(handle) is OS.WINDING ? SWT.FILL_WINDING : SWT.FILL_EVEN_ODD; | |
3277 } | |
3278 | |
3279 /** | |
3280 * Returns the font currently being used by the receiver | |
3281 * to draw and measure text. | |
3282 * | |
3283 * @return the receiver's font | |
3284 * | |
3285 * @exception SWTException <ul> | |
3286 * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> | |
3287 * </ul> | |
3288 */ | |
3289 public Font getFont () { | |
3290 if (handle is null) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); | |
3291 return data.font; | |
3292 } | |
3293 | |
3294 /** | |
3295 * Returns a FontMetrics which contains information | |
3296 * about the font currently being used by the receiver | |
3297 * to draw and measure text. | |
3298 * | |
3299 * @return font metrics for the receiver's font | |
3300 * | |
3301 * @exception SWTException <ul> | |
3302 * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> | |
3303 * </ul> | |
3304 */ | |
3305 public FontMetrics getFontMetrics() { | |
3306 if (handle is null) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); | |
3307 checkGC(FONT); | |
3308 TEXTMETRIC lptm; | |
3309 OS.GetTextMetrics(handle, &lptm); | |
3310 return FontMetrics.win32_new(&lptm); | |
3311 } | |
3312 | |
3313 /** | |
3314 * Returns the receiver's foreground color. | |
3315 * | |
3316 * @return the color used for drawing foreground things | |
3317 * | |
3318 * @exception SWTException <ul> | |
3319 * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> | |
3320 * </ul> | |
3321 */ | |
3322 public Color getForeground() { | |
3323 if (handle is null) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); | |
3324 return Color.win32_new(data.device, data.foreground); | |
3325 } | |
3326 | |
3327 /** | |
3328 * Returns the foreground pattern. The default value is | |
3329 * <code>null</code>. | |
3330 * | |
3331 * @return the receiver's foreground pattern | |
3332 * | |
3333 * @exception SWTException <ul> | |
3334 * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> | |
3335 * </ul> | |
3336 * | |
3337 * @see Pattern | |
3338 * | |
3339 * @since 3.1 | |
3340 */ | |
3341 public Pattern getForegroundPattern() { | |
3342 if (handle is null) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); | |
3343 return data.foregroundPattern; | |
3344 } | |
3345 | |
3346 /** | |
3347 * Returns the GCData. | |
3348 * <p> | |
3349 * <b>IMPORTANT:</b> This method is <em>not</em> part of the public | |
3350 * API for <code>GC</code>. It is marked public only so that it | |
3351 * can be shared within the packages provided by SWT. It is not | |
3352 * available on all platforms, and should never be called from | |
3353 * application code. | |
3354 * </p> | |
3355 * | |
3356 * @return the receiver's GCData | |
3357 * | |
3358 * @exception SWTException <ul> | |
3359 * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> | |
3360 * </ul> | |
3361 * | |
3362 * @see GCData | |
3363 * | |
3364 * @since 3.2 | |
3365 */ | |
3366 public GCData getGCData() { | |
3367 if (handle is null) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); | |
3368 return data; | |
3369 } | |
3370 | |
3371 /** | |
3372 * Returns the receiver's interpolation setting, which will be one of | |
3373 * <code>SWT.DEFAULT</code>, <code>SWT.NONE</code>, | |
3374 * <code>SWT.LOW</code> or <code>SWT.HIGH</code>. | |
3375 * | |
3376 * @return the receiver's interpolation setting | |
3377 * | |
3378 * @exception SWTException <ul> | |
3379 * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> | |
3380 * </ul> | |
3381 * | |
3382 * @since 3.1 | |
3383 */ | |
3384 public int getInterpolation() { | |
3385 if (handle is null) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); | |
3386 if (data.gdipGraphics is null) return SWT.DEFAULT; | |
3387 int mode = Gdip.Graphics_GetInterpolationMode(data.gdipGraphics); | |
3388 switch (mode) { | |
3389 case Gdip.InterpolationModeDefault: return SWT.DEFAULT; | |
3390 case Gdip.InterpolationModeNearestNeighbor: return SWT.NONE; | |
3391 case Gdip.InterpolationModeBilinear: | |
3392 case Gdip.InterpolationModeLowQuality: return SWT.LOW; | |
3393 case Gdip.InterpolationModeBicubic: | |
3394 case Gdip.InterpolationModeHighQualityBilinear: | |
3395 case Gdip.InterpolationModeHighQualityBicubic: | |
3396 case Gdip.InterpolationModeHighQuality: return SWT.HIGH; | |
3397 default: | |
3398 } | |
3399 return SWT.DEFAULT; | |
3400 } | |
3401 | |
3402 /** | |
3403 * Returns the receiver's line attributes. | |
3404 * | |
3405 * @return the line attributes used for drawing lines | |
3406 * | |
3407 * @exception SWTException <ul> | |
3408 * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> | |
3409 * </ul> | |
3410 * | |
3411 * @since 3.3 | |
3412 */ | |
3413 public LineAttributes getLineAttributes() { | |
3414 if (handle is null) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); | |
3415 float[] dashes = null; | |
3416 if (data.lineDashes !is null) { | |
3417 dashes = new float[data.lineDashes.length]; | |
3418 System.arraycopy(data.lineDashes, 0, dashes, 0, dashes.length); | |
3419 } | |
3420 return new LineAttributes(data.lineWidth, data.lineCap, data.lineJoin, data.lineStyle, dashes, data.lineDashesOffset, data.lineMiterLimit); | |
3421 } | |
3422 | |
3423 /** | |
3424 * Returns the receiver's line cap style, which will be one | |
3425 * of the constants <code>SWT.CAP_FLAT</code>, <code>SWT.CAP_ROUND</code>, | |
3426 * or <code>SWT.CAP_SQUARE</code>. | |
3427 * | |
3428 * @return the cap style used for drawing lines | |
3429 * | |
3430 * @exception SWTException <ul> | |
3431 * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> | |
3432 * </ul> | |
3433 * | |
3434 * @since 3.1 | |
3435 */ | |
3436 public int getLineCap() { | |
3437 if (handle is null) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); | |
3438 return data.lineCap; | |
3439 } | |
3440 | |
3441 /** | |
3442 * Returns the receiver's line dash style. The default value is | |
3443 * <code>null</code>. | |
3444 * | |
3445 * @return the line dash style used for drawing lines | |
3446 * | |
3447 * @exception SWTException <ul> | |
3448 * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> | |
3449 * </ul> | |
3450 * | |
3451 * @since 3.1 | |
3452 */ | |
3453 public int[] getLineDash() { | |
3454 if (handle is null) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); | |
3455 if (data.lineDashes is null) return null; | |
3456 int[] lineDashes = new int[data.lineDashes.length]; | |
3457 for (int i = 0; i < lineDashes.length; i++) { | |
3458 lineDashes[i] = cast(int)data.lineDashes[i]; | |
3459 } | |
3460 return lineDashes; | |
3461 } | |
3462 | |
3463 /** | |
3464 * Returns the receiver's line join style, which will be one | |
3465 * of the constants <code>SWT.JOIN_MITER</code>, <code>SWT.JOIN_ROUND</code>, | |
3466 * or <code>SWT.JOIN_BEVEL</code>. | |
3467 * | |
3468 * @return the join style used for drawing lines | |
3469 * | |
3470 * @exception SWTException <ul> | |
3471 * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> | |
3472 * </ul> | |
3473 * | |
3474 * @since 3.1 | |
3475 */ | |
3476 public int getLineJoin() { | |
3477 if (handle is null) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); | |
3478 return data.lineJoin; | |
3479 } | |
3480 | |
3481 /** | |
3482 * Returns the receiver's line style, which will be one | |
3483 * of the constants <code>SWT.LINE_SOLID</code>, <code>SWT.LINE_DASH</code>, | |
3484 * <code>SWT.LINE_DOT</code>, <code>SWT.LINE_DASHDOT</code> or | |
3485 * <code>SWT.LINE_DASHDOTDOT</code>. | |
3486 * | |
3487 * @return the style used for drawing lines | |
3488 * | |
3489 * @exception SWTException <ul> | |
3490 * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> | |
3491 * </ul> | |
3492 */ | |
3493 public int getLineStyle() { | |
3494 if (handle is null) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); | |
3495 return data.lineStyle; | |
3496 } | |
3497 | |
3498 /** | |
3499 * Returns the width that will be used when drawing lines | |
3500 * for all of the figure drawing operations (that is, | |
3501 * <code>drawLine</code>, <code>drawRectangle</code>, | |
3502 * <code>drawPolyline</code>, and so forth. | |
3503 * | |
3504 * @return the receiver's line width | |
3505 * | |
3506 * @exception SWTException <ul> | |
3507 * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> | |
3508 * </ul> | |
3509 */ | |
3510 public int getLineWidth() { | |
3511 if (handle is null) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); | |
3512 return cast(int)data.lineWidth; | |
3513 } | |
3514 | |
3515 /** | |
3516 * Returns the receiver's style information. | |
3517 * <p> | |
3518 * Note that the value which is returned by this method <em>may | |
3519 * not match</em> the value which was provided to the constructor | |
3520 * when the receiver was created. This can occur when the underlying | |
3521 * operating system does not support a particular combination of | |
3522 * requested styles. | |
3523 * </p> | |
3524 * | |
3525 * @return the style bits | |
3526 * | |
3527 * @exception SWTException <ul> | |
3528 * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> | |
3529 * </ul> | |
3530 * | |
3531 * @since 2.1.2 | |
3532 */ | |
3533 public int getStyle () { | |
3534 if (handle is null) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); | |
3535 return data.style; | |
3536 } | |
3537 | |
3538 /** | |
3539 * Returns the receiver's text drawing anti-aliasing setting value, | |
3540 * which will be one of <code>SWT.DEFAULT</code>, <code>SWT.OFF</code> or | |
3541 * <code>SWT.ON</code>. Note that this controls anti-aliasing | |
3542 * <em>only</em> for text drawing operations. | |
3543 * | |
3544 * @return the anti-aliasing setting | |
3545 * | |
3546 * @exception SWTException <ul> | |
3547 * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> | |
3548 * </ul> | |
3549 * | |
3550 * @see #getAntialias | |
3551 * | |
3552 * @since 3.1 | |
3553 */ | |
3554 public int getTextAntialias() { | |
3555 if (handle is null) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); | |
3556 if (data.gdipGraphics is null) return SWT.DEFAULT; | |
3557 int mode = Gdip.Graphics_GetTextRenderingHint(data.gdipGraphics); | |
3558 switch (mode) { | |
3559 case Gdip.TextRenderingHintSystemDefault: return SWT.DEFAULT; | |
3560 case Gdip.TextRenderingHintSingleBitPerPixel: | |
3561 case Gdip.TextRenderingHintSingleBitPerPixelGridFit: return SWT.OFF; | |
3562 case Gdip.TextRenderingHintAntiAlias: | |
3563 case Gdip.TextRenderingHintAntiAliasGridFit: | |
3564 case Gdip.TextRenderingHintClearTypeGridFit: return SWT.ON; | |
3565 default: | |
3566 } | |
3567 return SWT.DEFAULT; | |
3568 } | |
3569 | |
3570 /** | |
3571 * Sets the parameter to the transform that is currently being | |
3572 * used by the receiver. | |
3573 * | |
3574 * @param transform the destination to copy the transform into | |
3575 * | |
3576 * @exception IllegalArgumentException <ul> | |
3577 * <li>ERROR_NULL_ARGUMENT - if the parameter is null</li> | |
3578 * <li>ERROR_INVALID_ARGUMENT - if the parameter has been disposed</li> | |
3579 * </ul> | |
3580 * @exception SWTException <ul> | |
3581 * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> | |
3582 * </ul> | |
3583 * | |
3584 * @see Transform | |
3585 * | |
3586 * @since 3.1 | |
3587 */ | |
3588 public void getTransform(Transform transform) { | |
3589 if (handle is null) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); | |
3590 if (transform is null) SWT.error(SWT.ERROR_NULL_ARGUMENT); | |
3591 if (transform.isDisposed()) SWT.error(SWT.ERROR_INVALID_ARGUMENT); | |
3592 auto gdipGraphics = data.gdipGraphics; | |
3593 if (gdipGraphics !is null) { | |
3594 Gdip.Graphics_GetTransform(gdipGraphics, transform.handle); | |
3595 auto identity_ = identity(); | |
3596 Gdip.Matrix_Invert(identity_); | |
3597 Gdip.Matrix_Multiply(transform.handle, identity_, Gdip.MatrixOrderAppend); | |
3598 Gdip.Matrix_delete(identity_); | |
3599 } else { | |
3600 transform.setElements(1, 0, 0, 1, 0, 0); | |
3601 } | |
3602 } | |
3603 | |
3604 /** | |
3605 * Returns <code>true</code> if this GC is drawing in the mode | |
3606 * where the resulting color in the destination is the | |
3607 * <em>exclusive or</em> of the color values in the source | |
3608 * and the destination, and <code>false</code> if it is | |
3609 * drawing in the mode where the destination color is being | |
3610 * replaced with the source color value. | |
3611 * | |
3612 * @return <code>true</code> true if the receiver is in XOR mode, and false otherwise | |
3613 * | |
3614 * @exception SWTException <ul> | |
3615 * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> | |
3616 * </ul> | |
3617 */ | |
3618 public bool getXORMode() { | |
3619 if (handle is null) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); | |
3620 int rop2 = 0; | |
3621 static if (OS.IsWinCE) { | |
3622 rop2 = OS.SetROP2 (handle, OS.R2_COPYPEN); | |
3623 OS.SetROP2 (handle, rop2); | |
3624 } else { | |
3625 rop2 = OS.GetROP2(handle); | |
3626 } | |
3627 return rop2 is OS.R2_XORPEN; | |
3628 } | |
3629 | |
3630 void initGdip() { | |
3631 data.device.checkGDIP(); | |
3632 auto gdipGraphics = data.gdipGraphics; | |
3633 if (gdipGraphics !is null) return; | |
3634 /* | |
3635 * Feature in GDI+. The GDI+ clipping set with Graphics->SetClip() | |
3636 * is always intersected with the GDI clipping at the time the | |
3637 * GDI+ graphics is created. This means that the clipping | |
3638 * cannot be reset. The fix is to clear the clipping before | |
3639 * the GDI+ graphics is created and reset it afterwards. | |
3640 */ | |
3641 auto hRgn = OS.CreateRectRgn(0, 0, 0, 0); | |
3642 auto result = OS.GetClipRgn(handle, hRgn); | |
3643 static if (!OS.IsWinCE) { | |
3644 POINT pt; | |
3645 OS.GetWindowOrgEx (handle, &pt); | |
3646 OS.OffsetRgn (hRgn, pt.x, pt.y); | |
3647 } | |
3648 OS.SelectClipRgn(handle, null); | |
3649 | |
3650 /* | |
3651 * Bug in GDI+. GDI+ does not work when the HDC layout is RTL. There | |
3652 * are many issues like pixel corruption, but the most visible problem | |
3653 * is that it does not have an effect when drawing to an bitmap. The | |
3654 * fix is to clear the bit before creating the GDI+ graphics and install | |
3655 * a mirroring matrix ourselves. | |
3656 */ | |
3657 if ((data.style & SWT.MIRRORED) !is 0) { | |
3658 OS.SetLayout(handle, OS.GetLayout(handle) & ~OS.LAYOUT_RTL); | |
3659 } | |
3660 | |
3661 gdipGraphics = data.gdipGraphics = Gdip.Graphics_new(handle); | |
3662 if (gdipGraphics is null) SWT.error(SWT.ERROR_NO_HANDLES); | |
3663 Gdip.Graphics_SetPageUnit(gdipGraphics, Gdip.UnitPixel); | |
3664 Gdip.Graphics_SetPixelOffsetMode(gdipGraphics, Gdip.PixelOffsetModeHalf); | |
3665 if ((data.style & SWT.MIRRORED) !is 0) { | |
3666 auto matrix = identity(); | |
3667 Gdip.Graphics_SetTransform(gdipGraphics, matrix); | |
3668 Gdip.Matrix_delete(matrix); | |
3669 } | |
3670 if (result is 1) setClipping(hRgn); | |
3671 OS.DeleteObject(hRgn); | |
3672 data.state = 0; | |
3673 if (data.hPen !is null) { | |
3674 OS.SelectObject(handle, OS.GetStockObject(OS.NULL_PEN)); | |
3675 OS.DeleteObject(data.hPen); | |
3676 data.hPen = null; | |
3677 } | |
3678 if (data.hBrush !is null) { | |
3679 OS.SelectObject(handle, OS.GetStockObject(OS.NULL_BRUSH)); | |
3680 OS.DeleteObject(data.hBrush); | |
3681 data.hBrush = null; | |
3682 } | |
3683 } | |
3684 | |
3685 Gdip.Matrix identity() { | |
3686 if ((data.style & SWT.MIRRORED) !is 0) { | |
3687 int width = 0; | |
3688 int technology = OS.GetDeviceCaps(handle, OS.TECHNOLOGY); | |
3689 if (technology is OS.DT_RASPRINTER) { | |
3690 width = OS.GetDeviceCaps(handle, OS.PHYSICALWIDTH); | |
3691 } else { | |
3692 Image image = data.image; | |
3693 if (image !is null) { | |
3694 BITMAP bm; | |
3695 OS.GetObject(image.handle, BITMAP.sizeof, &bm); | |
3696 width = bm.bmWidth; | |
3697 } else { | |
3698 HWND hwnd; | |
3699 static if( OS.IsWinCE ){ | |
3700 hwnd = data.hwnd; | |
3701 } | |
3702 else{ | |
3703 hwnd = OS.WindowFromDC(handle); | |
3704 } | |
3705 if (hwnd !is null) { | |
3706 RECT rect; | |
3707 OS.GetClientRect(hwnd, &rect); | |
3708 width = rect.right - rect.left; | |
3709 } else { | |
3710 auto hBitmap = OS.GetCurrentObject(handle, OS.OBJ_BITMAP); | |
3711 BITMAP bm; | |
3712 OS.GetObject(hBitmap, BITMAP.sizeof, &bm); | |
3713 width = bm.bmWidth; | |
3714 } | |
3715 } | |
3716 } | |
3717 POINT pt; | |
3718 static if (!OS.IsWinCE) OS.GetWindowOrgEx (handle, &pt); | |
3719 return Gdip.Matrix_new(-1, 0, 0, 1, width + 2 * pt.x, 0); | |
3720 } | |
3721 return Gdip.Matrix_new(1, 0, 0, 1, 0, 0); | |
3722 } | |
3723 | |
3724 void init_(Drawable drawable, GCData data, HDC hDC) { | |
3725 auto foreground = data.foreground; | |
3726 if (foreground !is -1) { | |
3727 data.state &= ~(FOREGROUND | FOREGROUND_TEXT | PEN); | |
3728 } else { | |
3729 data.foreground = OS.GetTextColor(hDC); | |
3730 } | |
3731 auto background = data.background; | |
3732 if (background !is -1) { | |
3733 data.state &= ~(BACKGROUND | BACKGROUND_TEXT | BRUSH); | |
3734 } else { | |
3735 data.background = OS.GetBkColor(hDC); | |
3736 } | |
3737 data.state &= ~(NULL_BRUSH | NULL_PEN); | |
3738 Font font = data.font; | |
3739 if (font !is null) { | |
3740 data.state &= ~FONT; | |
3741 } else { | |
3742 data.font = Font.win32_new(device, OS.GetCurrentObject(hDC, OS.OBJ_FONT)); | |
3743 } | |
3744 auto hPalette = data.device.hPalette; | |
3745 if (hPalette !is null) { | |
3746 OS.SelectPalette(hDC, hPalette, true); | |
3747 OS.RealizePalette(hDC); | |
3748 } | |
3749 Image image = data.image; | |
3750 if (image !is null) { | |
3751 data.hNullBitmap = OS.SelectObject(hDC, image.handle); | |
3752 image.memGC = this; | |
3753 } | |
3754 auto layout = data.layout; | |
3755 if (layout !is -1) { | |
3756 if (!OS.IsWinCE && OS.WIN32_VERSION >= OS.VERSION(4, 10)) { | |
3757 int flags = OS.GetLayout(hDC); | |
3758 if ((flags & OS.LAYOUT_RTL) !is (layout & OS.LAYOUT_RTL)) { | |
3759 flags &= ~OS.LAYOUT_RTL; | |
3760 OS.SetLayout(hDC, flags | layout); | |
3761 } | |
3762 if ((data.style & SWT.RIGHT_TO_LEFT) !is 0) data.style |= SWT.MIRRORED; | |
3763 } | |
3764 } | |
3765 this.drawable = drawable; | |
3766 this.data = data; | |
3767 handle = hDC; | |
3768 } | |
3769 | |
3770 /** | |
3771 * Returns an integer hash code for the receiver. Any two | |
3772 * objects that return <code>true</code> when passed to | |
3773 * <code>equals</code> must return the same value for this | |
3774 * method. | |
3775 * | |
3776 * @return the receiver's hash | |
3777 * | |
3778 * @exception SWTException <ul> | |
3779 * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> | |
3780 * </ul> | |
3781 * | |
3782 * @see #equals | |
3783 */ | |
3784 public override hash_t toHash () { | |
3785 return cast(hash_t)handle; | |
3786 } | |
3787 | |
3788 /** | |
3789 * Returns <code>true</code> if the receiver has a clipping | |
3790 * region set into it, and <code>false</code> otherwise. | |
3791 * If this method returns false, the receiver will draw on all | |
3792 * available space in the destination. If it returns true, | |
3793 * it will draw only in the area that is covered by the region | |
3794 * that can be accessed with <code>getClipping(region)</code>. | |
3795 * | |
3796 * @return <code>true</code> if the GC has a clipping region, and <code>false</code> otherwise | |
3797 * | |
3798 * @exception SWTException <ul> | |
3799 * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> | |
3800 * </ul> | |
3801 */ | |
3802 public bool isClipped() { | |
3803 if (handle is null) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); | |
3804 auto gdipGraphics = data.gdipGraphics; | |
3805 if (gdipGraphics !is null) { | |
3806 auto rgn = Gdip.Region_new(); | |
3807 Gdip.Graphics_GetClip(data.gdipGraphics, rgn); | |
3808 bool isInfinite = Gdip.Region_IsInfinite(rgn, gdipGraphics) !is 0; | |
3809 Gdip.Region_delete(rgn); | |
3810 return !isInfinite; | |
3811 } | |
3812 auto region = OS.CreateRectRgn(0, 0, 0, 0); | |
3813 int result = OS.GetClipRgn(handle, region); | |
3814 OS.DeleteObject(region); | |
3815 return result > 0; | |
3816 } | |
3817 | |
3818 /** | |
3819 * Returns <code>true</code> if the GC has been disposed, | |
3820 * and <code>false</code> otherwise. | |
3821 * <p> | |
3822 * This method gets the dispose state for the GC. | |
3823 * When a GC has been disposed, it is an error to | |
3824 * invoke any other method using the GC. | |
3825 * | |
3826 * @return <code>true</code> when the GC is disposed and <code>false</code> otherwise | |
3827 */ | |
3828 override public bool isDisposed() { | |
3829 return handle is null; | |
3830 } | |
3831 | |
3832 float measureSpace(Gdip.Font font, Gdip.StringFormat format) { | |
3833 Gdip.PointF pt; | |
3834 Gdip.RectF bounds; | |
3835 Gdip.Graphics_MeasureString(data.gdipGraphics, (" "w).ptr, 1, font, pt, format, bounds); | |
3836 return bounds.Width; | |
3837 } | |
3838 | |
3839 /** | |
3840 * Sets the receiver to always use the operating system's advanced graphics | |
3841 * subsystem for all graphics operations if the argument is <code>true</code>. | |
3842 * If the argument is <code>false</code>, the advanced graphics subsystem is | |
3843 * no longer used, advanced graphics state is cleared and the normal graphics | |
3844 * subsystem is used from now on. | |
3845 * <p> | |
3846 * Normally, the advanced graphics subsystem is invoked automatically when | |
3847 * any one of the alpha, antialias, patterns, interpolation, paths, clipping | |
3848 * or transformation operations in the receiver is requested. When the receiver | |
3849 * is switched into advanced mode, the advanced graphics subsystem performs both | |
3850 * advanced and normal graphics operations. Because the two subsystems are | |
3851 * different, their output may differ. Switching to advanced graphics before | |
3852 * any graphics operations are performed ensures that the output is consistent. | |
3853 * </p><p> | |
3854 * Advanced graphics may not be installed for the operating system. In this | |
3855 * case, this operation does nothing. Some operating system have only one | |
3856 * graphics subsystem, so switching from normal to advanced graphics does | |
3857 * nothing. However, switching from advanced to normal graphics will always | |
3858 * clear the advanced graphics state, even for operating systems that have | |
3859 * only one graphics subsystem. | |
3860 * </p> | |
3861 * | |
3862 * @param advanced the new advanced graphics state | |
3863 * | |
3864 * @exception SWTException <ul> | |
3865 * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> | |
3866 * </ul> | |
3867 * | |
3868 * @see #setAlpha | |
3869 * @see #setAntialias | |
3870 * @see #setBackgroundPattern | |
3871 * @see #setClipping(Path) | |
3872 * @see #setForegroundPattern | |
3873 * @see #setLineAttributes | |
3874 * @see #setInterpolation | |
3875 * @see #setTextAntialias | |
3876 * @see #setTransform | |
3877 * @see #getAdvanced | |
3878 * | |
3879 * @since 3.1 | |
3880 */ | |
3881 public void setAdvanced(bool advanced) { | |
3882 if (handle is null) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); | |
3883 if (advanced && data.gdipGraphics !is null) return; | |
3884 if (advanced) { | |
3885 try { | |
3886 initGdip(); | |
3887 } catch (SWTException e) {} | |
3888 } else { | |
3889 disposeGdip(); | |
3890 data.alpha = 0xFF; | |
3891 data.backgroundPattern = data.foregroundPattern = null; | |
3892 data.state = 0; | |
3893 setClipping( cast(HRGN) null); | |
3894 if ((data.style & SWT.MIRRORED) !is 0) { | |
3895 OS.SetLayout(handle, OS.GetLayout(handle) | OS.LAYOUT_RTL); | |
3896 } | |
3897 } | |
3898 } | |
3899 | |
3900 /** | |
3901 * Sets the receiver's anti-aliasing value to the parameter, | |
3902 * which must be one of <code>SWT.DEFAULT</code>, <code>SWT.OFF</code> | |
3903 * or <code>SWT.ON</code>. Note that this controls anti-aliasing for all | |
3904 * <em>non-text drawing</em> operations. | |
3905 * <p> | |
3906 * This operation requires the operating system's advanced | |
3907 * graphics subsystem which may not be available on some | |
3908 * platforms. | |
3909 * </p> | |
3910 * | |
3911 * @param antialias the anti-aliasing setting | |
3912 * | |
3913 * @exception IllegalArgumentException <ul> | |
3914 * <li>ERROR_INVALID_ARGUMENT - if the parameter is not one of <code>SWT.DEFAULT</code>, | |
3915 * <code>SWT.OFF</code> or <code>SWT.ON</code></li> | |
3916 * </ul> | |
3917 * @exception SWTException <ul> | |
3918 * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> | |
3919 * <li>ERROR_NO_GRAPHICS_LIBRARY - if advanced graphics are not available</li> | |
3920 * </ul> | |
3921 * | |
3922 * @see #getAdvanced | |
3923 * @see #setAdvanced | |
3924 * @see #setTextAntialias | |
3925 * | |
3926 * @since 3.1 | |
3927 */ | |
3928 public void setAntialias(int antialias) { | |
3929 if (handle is null) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); | |
3930 if (data.gdipGraphics is null && antialias is SWT.DEFAULT) return; | |
3931 int mode = 0; | |
3932 switch (antialias) { | |
3933 case SWT.DEFAULT: | |
3934 mode = Gdip.SmoothingModeDefault; | |
3935 break; | |
3936 case SWT.OFF: | |
3937 mode = Gdip.SmoothingModeNone; | |
3938 break; | |
3939 case SWT.ON: | |
3940 mode = Gdip.SmoothingModeAntiAlias; | |
3941 break; | |
3942 default: | |
3943 SWT.error(SWT.ERROR_INVALID_ARGUMENT); | |
3944 } | |
3945 initGdip(); | |
3946 Gdip.Graphics_SetSmoothingMode(data.gdipGraphics, mode); | |
3947 } | |
3948 | |
3949 /** | |
3950 * Sets the receiver's alpha value which must be | |
3951 * between 0 (transparent) and 255 (opaque). | |
3952 * <p> | |
3953 * This operation requires the operating system's advanced | |
3954 * graphics subsystem which may not be available on some | |
3955 * platforms. | |
3956 * </p> | |
3957 * @param alpha the alpha value | |
3958 * | |
3959 * @exception SWTException <ul> | |
3960 * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> | |
3961 * <li>ERROR_NO_GRAPHICS_LIBRARY - if advanced graphics are not available</li> | |
3962 * </ul> | |
3963 * | |
3964 * @see #getAdvanced | |
3965 * @see #setAdvanced | |
3966 * | |
3967 * @since 3.1 | |
3968 */ | |
3969 public void setAlpha(int alpha) { | |
3970 if (handle is null) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); | |
3971 if (data.gdipGraphics is null && (alpha & 0xFF) is 0xFF) return; | |
3972 initGdip(); | |
3973 data.alpha = alpha & 0xFF; | |
3974 data.state &= ~(BACKGROUND | FOREGROUND); | |
3975 } | |
3976 | |
3977 /** | |
3978 * Sets the background color. The background color is used | |
3979 * for fill operations and as the background color when text | |
3980 * is drawn. | |
3981 * | |
3982 * @param color the new background color for the receiver | |
3983 * | |
3984 * @exception IllegalArgumentException <ul> | |
3985 * <li>ERROR_NULL_ARGUMENT - if the color is null</li> | |
3986 * <li>ERROR_INVALID_ARGUMENT - if the color has been disposed</li> | |
3987 * </ul> | |
3988 * @exception SWTException <ul> | |
3989 * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> | |
3990 * </ul> | |
3991 */ | |
3992 public void setBackground (Color color) { | |
3993 if (handle is null) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); | |
3994 if (color is null) SWT.error(SWT.ERROR_NULL_ARGUMENT); | |
3995 if (color.isDisposed()) SWT.error(SWT.ERROR_INVALID_ARGUMENT); | |
3996 if (data.backgroundPattern is null && data.background is color.handle) return; | |
3997 data.backgroundPattern = null; | |
3998 data.background = color.handle; | |
3999 data.state &= ~(BACKGROUND | BACKGROUND_TEXT); | |
4000 } | |
4001 | |
4002 /** | |
4003 * Sets the background pattern. The default value is <code>null</code>. | |
4004 * <p> | |
4005 * This operation requires the operating system's advanced | |
4006 * graphics subsystem which may not be available on some | |
4007 * platforms. | |
4008 * </p> | |
4009 * | |
4010 * @param pattern the new background pattern | |
4011 * | |
4012 * @exception IllegalArgumentException <ul> | |
4013 * <li>ERROR_INVALID_ARGUMENT - if the parameter has been disposed</li> | |
4014 * </ul> | |
4015 * @exception SWTException <ul> | |
4016 * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> | |
4017 * <li>ERROR_NO_GRAPHICS_LIBRARY - if advanced graphics are not available</li> | |
4018 * </ul> | |
4019 * | |
4020 * @see Pattern | |
4021 * @see #getAdvanced | |
4022 * @see #setAdvanced | |
4023 * | |
4024 * @since 3.1 | |
4025 */ | |
4026 public void setBackgroundPattern (Pattern pattern) { | |
4027 if (handle is null) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); | |
4028 if (pattern !is null && pattern.isDisposed()) SWT.error(SWT.ERROR_INVALID_ARGUMENT); | |
4029 if (data.gdipGraphics is null && pattern is null) return; | |
4030 initGdip(); | |
4031 if (data.backgroundPattern is pattern) return; | |
4032 data.backgroundPattern = pattern; | |
4033 data.state &= ~BACKGROUND; | |
4034 } | |
4035 | |
4036 void setClipping(HRGN clipRgn) { | |
4037 auto hRgn = clipRgn; | |
4038 auto gdipGraphics = data.gdipGraphics; | |
4039 if (gdipGraphics !is null) { | |
4040 if (hRgn !is null) { | |
4041 auto region = Gdip.Region_new(hRgn); | |
4042 Gdip.Graphics_SetClip(gdipGraphics, region, Gdip.CombineModeReplace); | |
4043 Gdip.Region_delete(region); | |
4044 } else { | |
4045 Gdip.Graphics_ResetClip(gdipGraphics); | |
4046 } | |
4047 } else { | |
4048 POINT pt; | |
4049 if (hRgn !is null && !OS.IsWinCE) { | |
4050 OS.GetWindowOrgEx(handle, &pt); | |
4051 OS.OffsetRgn(hRgn, -pt.x, -pt.y); | |
4052 } | |
4053 OS.SelectClipRgn(handle, hRgn); | |
4054 if (hRgn !is null && !OS.IsWinCE) { | |
4055 OS.OffsetRgn(hRgn, pt.x, pt.y); | |
4056 } | |
4057 } | |
4058 if (hRgn !is null && hRgn !is clipRgn) { | |
4059 OS.DeleteObject(hRgn); | |
4060 } | |
4061 } | |
4062 | |
4063 /** | |
4064 * Sets the area of the receiver which can be changed | |
4065 * by drawing operations to the rectangular area specified | |
4066 * by the arguments. | |
4067 * | |
4068 * @param x the x coordinate of the clipping rectangle | |
4069 * @param y the y coordinate of the clipping rectangle | |
4070 * @param width the width of the clipping rectangle | |
4071 * @param height the height of the clipping rectangle | |
4072 * | |
4073 * @exception SWTException <ul> | |
4074 * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> | |
4075 * </ul> | |
4076 */ | |
4077 public void setClipping (int x, int y, int width, int height) { | |
4078 if (handle is null) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); | |
4079 auto hRgn = OS.CreateRectRgn(x, y, x + width, y + height); | |
4080 setClipping(hRgn); | |
4081 OS.DeleteObject(hRgn); | |
4082 } | |
4083 | |
4084 /** | |
4085 * Sets the area of the receiver which can be changed | |
4086 * by drawing operations to the path specified | |
4087 * by the argument. | |
4088 * <p> | |
4089 * This operation requires the operating system's advanced | |
4090 * graphics subsystem which may not be available on some | |
4091 * platforms. | |
4092 * </p> | |
4093 * | |
4094 * @param path the clipping path. | |
4095 * | |
4096 * @exception IllegalArgumentException <ul> | |
4097 * <li>ERROR_INVALID_ARGUMENT - if the path has been disposed</li> | |
4098 * </ul> | |
4099 * @exception SWTException <ul> | |
4100 * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> | |
4101 * <li>ERROR_NO_GRAPHICS_LIBRARY - if advanced graphics are not available</li> | |
4102 * </ul> | |
4103 * | |
4104 * @see Path | |
4105 * @see #getAdvanced | |
4106 * @see #setAdvanced | |
4107 * | |
4108 * @since 3.1 | |
4109 */ | |
4110 public void setClipping (Path path) { | |
4111 if (handle is null) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); | |
4112 if (path !is null && path.isDisposed()) SWT.error(SWT.ERROR_INVALID_ARGUMENT); | |
4113 setClipping(cast(HRGN)null); | |
4114 if (path !is null) { | |
4115 initGdip(); | |
4116 int mode = OS.GetPolyFillMode(handle) is OS.WINDING ? Gdip.FillModeWinding : Gdip.FillModeAlternate; | |
4117 Gdip.GraphicsPath_SetFillMode(path.handle, mode); | |
4118 Gdip.Graphics_SetClipPath(data.gdipGraphics, path.handle); | |
4119 } | |
4120 } | |
4121 | |
4122 /** | |
4123 * Sets the area of the receiver which can be changed | |
4124 * by drawing operations to the rectangular area specified | |
4125 * by the argument. Specifying <code>null</code> for the | |
4126 * rectangle reverts the receiver's clipping area to its | |
4127 * original value. | |
4128 * | |
4129 * @param rect the clipping rectangle or <code>null</code> | |
4130 * | |
4131 * @exception SWTException <ul> | |
4132 * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> | |
4133 * </ul> | |
4134 */ | |
4135 public void setClipping (Rectangle rect) { | |
4136 if (handle is null) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); | |
4137 if (rect is null) { | |
4138 setClipping(cast(HRGN)null); | |
4139 } else { | |
4140 setClipping(rect.x, rect.y, rect.width, rect.height); | |
4141 } | |
4142 } | |
4143 | |
4144 /** | |
4145 * Sets the area of the receiver which can be changed | |
4146 * by drawing operations to the region specified | |
4147 * by the argument. Specifying <code>null</code> for the | |
4148 * region reverts the receiver's clipping area to its | |
4149 * original value. | |
4150 * | |
4151 * @param region the clipping region or <code>null</code> | |
4152 * | |
4153 * @exception IllegalArgumentException <ul> | |
4154 * <li>ERROR_INVALID_ARGUMENT - if the region has been disposed</li> | |
4155 * </ul> | |
4156 * @exception SWTException <ul> | |
4157 * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> | |
4158 * </ul> | |
4159 */ | |
4160 public void setClipping (Region region) { | |
4161 if (handle is null) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); | |
4162 if (region !is null && region.isDisposed()) SWT.error(SWT.ERROR_INVALID_ARGUMENT); | |
4163 setClipping(region !is null ? region.handle : cast(HRGN)null); | |
4164 } | |
4165 | |
4166 /** | |
4167 * Sets the receiver's fill rule to the parameter, which must be one of | |
4168 * <code>SWT.FILL_EVEN_ODD</code> or <code>SWT.FILL_WINDING</code>. | |
4169 * | |
4170 * @param rule the new fill rule | |
4171 * | |
4172 * @exception IllegalArgumentException <ul> | |
4173 * <li>ERROR_INVALID_ARGUMENT - if the rule is not one of <code>SWT.FILL_EVEN_ODD</code> | |
4174 * or <code>SWT.FILL_WINDING</code></li> | |
4175 * </ul> | |
4176 * @exception SWTException <ul> | |
4177 * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> | |
4178 * </ul> | |
4179 * | |
4180 * @since 3.1 | |
4181 */ | |
4182 public void setFillRule(int rule) { | |
4183 if (handle is null) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); | |
4184 static if (OS.IsWinCE) return; | |
4185 int mode = OS.ALTERNATE; | |
4186 switch (rule) { | |
4187 case SWT.FILL_WINDING: mode = OS.WINDING; break; | |
4188 case SWT.FILL_EVEN_ODD: mode = OS.ALTERNATE; break; | |
4189 default: | |
4190 SWT.error(SWT.ERROR_INVALID_ARGUMENT); | |
4191 } | |
4192 OS.SetPolyFillMode(handle, mode); | |
4193 } | |
4194 | |
4195 /** | |
4196 * Sets the font which will be used by the receiver | |
4197 * to draw and measure text to the argument. If the | |
4198 * argument is null, then a default font appropriate | |
4199 * for the platform will be used instead. | |
4200 * | |
4201 * @param font the new font for the receiver, or null to indicate a default font | |
4202 * | |
4203 * @exception IllegalArgumentException <ul> | |
4204 * <li>ERROR_INVALID_ARGUMENT - if the font has been disposed</li> | |
4205 * </ul> | |
4206 * @exception SWTException <ul> | |
4207 * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> | |
4208 * </ul> | |
4209 */ | |
4210 public void setFont (Font font) { | |
4211 if (handle is null) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); | |
4212 if (font !is null && font.isDisposed()) SWT.error(SWT.ERROR_INVALID_ARGUMENT); | |
4213 data.font = font !is null ? font : data.device.systemFont; | |
4214 data.state &= ~FONT; | |
4215 } | |
4216 | |
4217 /** | |
4218 * Sets the foreground color. The foreground color is used | |
4219 * for drawing operations including when text is drawn. | |
4220 * | |
4221 * @param color the new foreground color for the receiver | |
4222 * | |
4223 * @exception IllegalArgumentException <ul> | |
4224 * <li>ERROR_NULL_ARGUMENT - if the color is null</li> | |
4225 * <li>ERROR_INVALID_ARGUMENT - if the color has been disposed</li> | |
4226 * </ul> | |
4227 * @exception SWTException <ul> | |
4228 * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> | |
4229 * </ul> | |
4230 */ | |
4231 public void setForeground (Color color) { | |
4232 if (handle is null) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); | |
4233 if (color is null) SWT.error(SWT.ERROR_NULL_ARGUMENT); | |
4234 if (color.isDisposed()) SWT.error(SWT.ERROR_INVALID_ARGUMENT); | |
4235 if (data.foregroundPattern is null && color.handle is data.foreground) return; | |
4236 data.foregroundPattern = null; | |
4237 data.foreground = color.handle; | |
4238 data.state &= ~(FOREGROUND | FOREGROUND_TEXT); | |
4239 } | |
4240 | |
4241 /** | |
4242 * Sets the foreground pattern. The default value is <code>null</code>. | |
4243 * <p> | |
4244 * This operation requires the operating system's advanced | |
4245 * graphics subsystem which may not be available on some | |
4246 * platforms. | |
4247 * </p> | |
4248 * @param pattern the new foreground pattern | |
4249 * | |
4250 * @exception IllegalArgumentException <ul> | |
4251 * <li>ERROR_INVALID_ARGUMENT - if the parameter has been disposed</li> | |
4252 * </ul> | |
4253 * @exception SWTException <ul> | |
4254 * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> | |
4255 * <li>ERROR_NO_GRAPHICS_LIBRARY - if advanced graphics are not available</li> | |
4256 * </ul> | |
4257 * | |
4258 * @see Pattern | |
4259 * @see #getAdvanced | |
4260 * @see #setAdvanced | |
4261 * | |
4262 * @since 3.1 | |
4263 */ | |
4264 public void setForegroundPattern (Pattern pattern) { | |
4265 if (handle is null) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); | |
4266 if (pattern !is null && pattern.isDisposed()) SWT.error(SWT.ERROR_INVALID_ARGUMENT); | |
4267 if (data.gdipGraphics is null && pattern is null) return; | |
4268 initGdip(); | |
4269 if (data.foregroundPattern is pattern) return; | |
4270 data.foregroundPattern = pattern; | |
4271 data.state &= ~FOREGROUND; | |
4272 } | |
4273 | |
4274 /** | |
4275 * Sets the receiver's interpolation setting to the parameter, which | |
4276 * must be one of <code>SWT.DEFAULT</code>, <code>SWT.NONE</code>, | |
4277 * <code>SWT.LOW</code> or <code>SWT.HIGH</code>. | |
4278 * <p> | |
4279 * This operation requires the operating system's advanced | |
4280 * graphics subsystem which may not be available on some | |
4281 * platforms. | |
4282 * </p> | |
4283 * | |
4284 * @param interpolation the new interpolation setting | |
4285 * | |
4286 * @exception IllegalArgumentException <ul> | |
4287 * <li>ERROR_INVALID_ARGUMENT - if the rule is not one of <code>SWT.DEFAULT</code>, | |
4288 * <code>SWT.NONE</code>, <code>SWT.LOW</code> or <code>SWT.HIGH</code> | |
4289 * </ul> | |
4290 * @exception SWTException <ul> | |
4291 * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> | |
4292 * <li>ERROR_NO_GRAPHICS_LIBRARY - if advanced graphics are not available</li> | |
4293 * </ul> | |
4294 * | |
4295 * @see #getAdvanced | |
4296 * @see #setAdvanced | |
4297 * | |
4298 * @since 3.1 | |
4299 */ | |
4300 public void setInterpolation(int interpolation) { | |
4301 if (handle is null) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); | |
4302 if (data.gdipGraphics is null && interpolation is SWT.DEFAULT) return; | |
4303 int mode = 0; | |
4304 switch (interpolation) { | |
4305 case SWT.DEFAULT: mode = Gdip.InterpolationModeDefault; break; | |
4306 case SWT.NONE: mode = Gdip.InterpolationModeNearestNeighbor; break; | |
4307 case SWT.LOW: mode = Gdip.InterpolationModeLowQuality; break; | |
4308 case SWT.HIGH: mode = Gdip.InterpolationModeHighQuality; break; | |
4309 default: | |
4310 SWT.error(SWT.ERROR_INVALID_ARGUMENT); | |
4311 } | |
4312 initGdip(); | |
4313 Gdip.Graphics_SetInterpolationMode(data.gdipGraphics, mode); | |
4314 } | |
4315 | |
4316 /** | |
4317 * Sets the receiver's line attributes. | |
4318 * <p> | |
4319 * This operation requires the operating system's advanced | |
4320 * graphics subsystem which may not be available on some | |
4321 * platforms. | |
4322 * </p> | |
4323 * @param attributes the line attributes | |
4324 * | |
4325 * @exception IllegalArgumentException <ul> | |
4326 * <li>ERROR_NULL_ARGUMENT - if the attributes is null</li> | |
4327 * <li>ERROR_INVALID_ARGUMENT - if any of the line attributes is not valid</li> | |
4328 * </ul> | |
4329 * @exception SWTException <ul> | |
4330 * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> | |
4331 * <li>ERROR_NO_GRAPHICS_LIBRARY - if advanced graphics are not available</li> | |
4332 * </ul> | |
4333 * | |
4334 * @see LineAttributes | |
4335 * @see #getAdvanced | |
4336 * @see #setAdvanced | |
4337 * | |
4338 * @since 3.3 | |
4339 */ | |
4340 public void setLineAttributes(LineAttributes attributes) { | |
4341 if (handle is null) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); | |
4342 if (attributes is null) SWT.error(SWT.ERROR_NULL_ARGUMENT); | |
4343 int mask = 0; | |
4344 float lineWidth = attributes.width; | |
4345 if (lineWidth !is data.lineWidth) { | |
4346 mask |= LINE_WIDTH | DRAW_OFFSET; | |
4347 } | |
4348 int lineStyle = attributes.style; | |
4349 if (lineStyle !is data.lineStyle) { | |
4350 mask |= LINE_STYLE; | |
4351 switch (lineStyle) { | |
4352 case SWT.LINE_SOLID: | |
4353 case SWT.LINE_DASH: | |
4354 case SWT.LINE_DOT: | |
4355 case SWT.LINE_DASHDOT: | |
4356 case SWT.LINE_DASHDOTDOT: | |
4357 break; | |
4358 case SWT.LINE_CUSTOM: | |
4359 if (attributes.dash is null) lineStyle = SWT.LINE_SOLID; | |
4360 break; | |
4361 default: | |
4362 SWT.error(SWT.ERROR_INVALID_ARGUMENT); | |
4363 } | |
4364 } | |
4365 int join = attributes.join; | |
4366 if (join !is data.lineJoin) { | |
4367 mask |= LINE_JOIN; | |
4368 switch (join) { | |
4369 case SWT.CAP_ROUND: | |
4370 case SWT.CAP_FLAT: | |
4371 case SWT.CAP_SQUARE: | |
4372 break; | |
4373 default: | |
4374 SWT.error(SWT.ERROR_INVALID_ARGUMENT); | |
4375 } | |
4376 } | |
4377 int cap = attributes.cap; | |
4378 if (cap !is data.lineCap) { | |
4379 mask |= LINE_CAP; | |
4380 switch (cap) { | |
4381 case SWT.JOIN_MITER: | |
4382 case SWT.JOIN_ROUND: | |
4383 case SWT.JOIN_BEVEL: | |
4384 break; | |
4385 default: | |
4386 SWT.error(SWT.ERROR_INVALID_ARGUMENT); | |
4387 } | |
4388 } | |
4389 float[] dashes = attributes.dash; | |
4390 float[] lineDashes = data.lineDashes; | |
4391 if (dashes !is null && dashes.length > 0) { | |
4392 bool changed = lineDashes is null || lineDashes.length !is dashes.length; | |
4393 for (int i = 0; i < dashes.length; i++) { | |
4394 float dash = dashes[i]; | |
4395 if (dash <= 0) SWT.error(SWT.ERROR_INVALID_ARGUMENT); | |
4396 if (!changed && lineDashes[i] !is dash) changed = true; | |
4397 } | |
4398 if (changed) { | |
4399 float[] newDashes = new float[dashes.length]; | |
4400 System.arraycopy(dashes, 0, newDashes, 0, dashes.length); | |
4401 dashes = newDashes; | |
4402 mask |= LINE_STYLE; | |
4403 } else { | |
4404 dashes = lineDashes; | |
4405 } | |
4406 } else { | |
4407 if (lineDashes !is null && lineDashes.length > 0) { | |
4408 mask |= LINE_STYLE; | |
4409 } else { | |
4410 dashes = lineDashes; | |
4411 } | |
4412 } | |
4413 float dashOffset = attributes.dashOffset; | |
4414 if (dashOffset !is data.lineDashesOffset) { | |
4415 mask |= LINE_STYLE; | |
4416 } | |
4417 float miterLimit = attributes.miterLimit; | |
4418 if (miterLimit !is data.lineMiterLimit) { | |
4419 mask |= LINE_MITERLIMIT; | |
4420 } | |
4421 initGdip(); | |
4422 if (mask is 0) return; | |
4423 data.lineWidth = lineWidth; | |
4424 data.lineStyle = lineStyle; | |
4425 data.lineCap = cap; | |
4426 data.lineJoin = join; | |
4427 data.lineDashes = dashes; | |
4428 data.lineDashesOffset = dashOffset; | |
4429 data.lineMiterLimit = miterLimit; | |
4430 data.state &= ~mask; | |
4431 } | |
4432 | |
4433 /** | |
4434 * Sets the receiver's line cap style to the argument, which must be one | |
4435 * of the constants <code>SWT.CAP_FLAT</code>, <code>SWT.CAP_ROUND</code>, | |
4436 * or <code>SWT.CAP_SQUARE</code>. | |
4437 * | |
4438 * @param cap the cap style to be used for drawing lines | |
4439 * | |
4440 * @exception IllegalArgumentException <ul> | |
4441 * <li>ERROR_INVALID_ARGUMENT - if the style is not valid</li> | |
4442 * </ul> | |
4443 * @exception SWTException <ul> | |
4444 * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> | |
4445 * </ul> | |
4446 * | |
4447 * @since 3.1 | |
4448 */ | |
4449 public void setLineCap(int cap) { | |
4450 if (handle is null) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); | |
4451 if (data.lineCap is cap) return; | |
4452 switch (cap) { | |
4453 case SWT.CAP_ROUND: | |
4454 case SWT.CAP_FLAT: | |
4455 case SWT.CAP_SQUARE: | |
4456 break; | |
4457 default: | |
4458 SWT.error(SWT.ERROR_INVALID_ARGUMENT); | |
4459 } | |
4460 data.lineCap = cap; | |
4461 data.state &= ~LINE_CAP; | |
4462 } | |
4463 | |
4464 /** | |
4465 * Sets the receiver's line dash style to the argument. The default | |
4466 * value is <code>null</code>. If the argument is not <code>null</code>, | |
4467 * the receiver's line style is set to <code>SWT.LINE_CUSTOM</code>, otherwise | |
4468 * it is set to <code>SWT.LINE_SOLID</code>. | |
4469 * | |
4470 * @param dashes the dash style to be used for drawing lines | |
4471 * | |
4472 * @exception IllegalArgumentException <ul> | |
4473 * <li>ERROR_INVALID_ARGUMENT - if any of the values in the array is less than or equal 0</li> | |
4474 * </ul> | |
4475 * @exception SWTException <ul> | |
4476 * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> | |
4477 * </ul> | |
4478 * | |
4479 * @since 3.1 | |
4480 */ | |
4481 public void setLineDash(int[] dashes) { | |
4482 if (handle is null) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); | |
4483 float[] lineDashes = data.lineDashes; | |
4484 if (dashes !is null && dashes.length > 0) { | |
4485 bool changed = data.lineStyle !is SWT.LINE_CUSTOM || lineDashes is null || lineDashes.length !is dashes.length; | |
4486 for (int i = 0; i < dashes.length; i++) { | |
4487 int dash = dashes[i]; | |
4488 if (dash <= 0) SWT.error(SWT.ERROR_INVALID_ARGUMENT); | |
4489 if (!changed && lineDashes[i] !is dash) changed = true; | |
4490 } | |
4491 if (!changed) return; | |
4492 data.lineDashes = new float[dashes.length]; | |
4493 for (int i = 0; i < dashes.length; i++) { | |
4494 data.lineDashes[i] = dashes[i]; | |
4495 } | |
4496 data.lineStyle = SWT.LINE_CUSTOM; | |
4497 } else { | |
4498 if (data.lineStyle is SWT.LINE_SOLID && (lineDashes is null || lineDashes.length is 0)) return; | |
4499 data.lineDashes = null; | |
4500 data.lineStyle = SWT.LINE_SOLID; | |
4501 } | |
4502 data.state &= ~LINE_STYLE; | |
4503 } | |
4504 | |
4505 /** | |
4506 * Sets the receiver's line join style to the argument, which must be one | |
4507 * of the constants <code>SWT.JOIN_MITER</code>, <code>SWT.JOIN_ROUND</code>, | |
4508 * or <code>SWT.JOIN_BEVEL</code>. | |
4509 * | |
4510 * @param join the join style to be used for drawing lines | |
4511 * | |
4512 * @exception IllegalArgumentException <ul> | |
4513 * <li>ERROR_INVALID_ARGUMENT - if the style is not valid</li> | |
4514 * </ul> | |
4515 * @exception SWTException <ul> | |
4516 * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> | |
4517 * </ul> | |
4518 * | |
4519 * @since 3.1 | |
4520 */ | |
4521 public void setLineJoin(int join) { | |
4522 if (handle is null) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); | |
4523 if (data.lineJoin is join) return; | |
4524 switch (join) { | |
4525 case SWT.JOIN_MITER: | |
4526 case SWT.JOIN_ROUND: | |
4527 case SWT.JOIN_BEVEL: | |
4528 break; | |
4529 default: | |
4530 SWT.error(SWT.ERROR_INVALID_ARGUMENT); | |
4531 } | |
4532 data.lineJoin = join; | |
4533 data.state &= ~LINE_JOIN; | |
4534 } | |
4535 | |
4536 /** | |
4537 * Sets the receiver's line style to the argument, which must be one | |
4538 * of the constants <code>SWT.LINE_SOLID</code>, <code>SWT.LINE_DASH</code>, | |
4539 * <code>SWT.LINE_DOT</code>, <code>SWT.LINE_DASHDOT</code> or | |
4540 * <code>SWT.LINE_DASHDOTDOT</code>. | |
4541 * | |
4542 * @param lineStyle the style to be used for drawing lines | |
4543 * | |
4544 * @exception IllegalArgumentException <ul> | |
4545 * <li>ERROR_INVALID_ARGUMENT - if the style is not valid</li> | |
4546 * </ul> | |
4547 * @exception SWTException <ul> | |
4548 * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> | |
4549 * </ul> | |
4550 */ | |
4551 public void setLineStyle(int lineStyle) { | |
4552 if (handle is null) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); | |
4553 if (data.lineStyle is lineStyle) return; | |
4554 switch (lineStyle) { | |
4555 case SWT.LINE_SOLID: | |
4556 case SWT.LINE_DASH: | |
4557 case SWT.LINE_DOT: | |
4558 case SWT.LINE_DASHDOT: | |
4559 case SWT.LINE_DASHDOTDOT: | |
4560 break; | |
4561 case SWT.LINE_CUSTOM: | |
4562 if (data.lineDashes is null) lineStyle = SWT.LINE_SOLID; | |
4563 break; | |
4564 default: | |
4565 SWT.error(SWT.ERROR_INVALID_ARGUMENT); | |
4566 } | |
4567 data.lineStyle = lineStyle; | |
4568 data.state &= ~LINE_STYLE; | |
4569 } | |
4570 | |
4571 /** | |
4572 * Sets the width that will be used when drawing lines | |
4573 * for all of the figure drawing operations (that is, | |
4574 * <code>drawLine</code>, <code>drawRectangle</code>, | |
4575 * <code>drawPolyline</code>, and so forth. | |
4576 * <p> | |
4577 * Note that line width of zero is used as a hint to | |
4578 * indicate that the fastest possible line drawing | |
4579 * algorithms should be used. This means that the | |
4580 * output may be different from line width one. | |
4581 * </p> | |
4582 * | |
4583 * @param lineWidth the width of a line | |
4584 * | |
4585 * @exception SWTException <ul> | |
4586 * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> | |
4587 * </ul> | |
4588 */ | |
4589 public void setLineWidth(int lineWidth) { | |
4590 if (handle is null) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); | |
4591 if (data.lineWidth is lineWidth) return; | |
4592 data.lineWidth = lineWidth; | |
4593 data.state &= ~(LINE_WIDTH | DRAW_OFFSET); | |
4594 } | |
4595 | |
4596 /** | |
4597 * If the argument is <code>true</code>, puts the receiver | |
4598 * in a drawing mode where the resulting color in the destination | |
4599 * is the <em>exclusive or</em> of the color values in the source | |
4600 * and the destination, and if the argument is <code>false</code>, | |
4601 * puts the receiver in a drawing mode where the destination color | |
4602 * is replaced with the source color value. | |
4603 * <p> | |
4604 * Note that this mode in fundamentally unsupportable on certain | |
4605 * platforms, notably Carbon (Mac OS X). Clients that want their | |
4606 * code to run on all platforms need to avoid this method. | |
4607 * </p> | |
4608 * | |
4609 * @param xor if <code>true</code>, then <em>xor</em> mode is used, otherwise <em>source copy</em> mode is used | |
4610 * | |
4611 * @exception SWTException <ul> | |
4612 * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> | |
4613 * </ul> | |
4614 * | |
4615 * @deprecated this functionality is not supported on some platforms | |
4616 */ | |
4617 public void setXORMode(bool xor) { | |
4618 if (handle is null) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); | |
4619 OS.SetROP2(handle, xor ? OS.R2_XORPEN : OS.R2_COPYPEN); | |
4620 } | |
4621 | |
4622 /** | |
4623 * Sets the receiver's text anti-aliasing value to the parameter, | |
4624 * which must be one of <code>SWT.DEFAULT</code>, <code>SWT.OFF</code> | |
4625 * or <code>SWT.ON</code>. Note that this controls anti-aliasing only | |
4626 * for all <em>text drawing</em> operations. | |
4627 * <p> | |
4628 * This operation requires the operating system's advanced | |
4629 * graphics subsystem which may not be available on some | |
4630 * platforms. | |
4631 * </p> | |
4632 * | |
4633 * @param antialias the anti-aliasing setting | |
4634 * | |
4635 * @exception IllegalArgumentException <ul> | |
4636 * <li>ERROR_INVALID_ARGUMENT - if the parameter is not one of <code>SWT.DEFAULT</code>, | |
4637 * <code>SWT.OFF</code> or <code>SWT.ON</code></li> | |
4638 * </ul> | |
4639 * @exception SWTException <ul> | |
4640 * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> | |
4641 * <li>ERROR_NO_GRAPHICS_LIBRARY - if advanced graphics are not available</li> | |
4642 * </ul> | |
4643 * | |
4644 * @see #getAdvanced | |
4645 * @see #setAdvanced | |
4646 * @see #setAntialias | |
4647 * | |
4648 * @since 3.1 | |
4649 */ | |
4650 public void setTextAntialias(int antialias) { | |
4651 if (handle is null) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); | |
4652 if (data.gdipGraphics is null && antialias is SWT.DEFAULT) return; | |
4653 int textMode = 0; | |
4654 switch (antialias) { | |
4655 case SWT.DEFAULT: | |
4656 textMode = Gdip.TextRenderingHintSystemDefault; | |
4657 break; | |
4658 case SWT.OFF: | |
4659 textMode = Gdip.TextRenderingHintSingleBitPerPixelGridFit; | |
4660 break; | |
4661 case SWT.ON: | |
4662 int type; | |
4663 OS.SystemParametersInfo(OS.SPI_GETFONTSMOOTHINGTYPE, 0, &type, 0); | |
4664 if (type is OS.FE_FONTSMOOTHINGCLEARTYPE) { | |
4665 textMode = Gdip.TextRenderingHintClearTypeGridFit; | |
4666 } else { | |
4667 textMode = Gdip.TextRenderingHintAntiAliasGridFit; | |
4668 } | |
4669 break; | |
4670 default: | |
4671 SWT.error(SWT.ERROR_INVALID_ARGUMENT); | |
4672 } | |
4673 initGdip(); | |
4674 Gdip.Graphics_SetTextRenderingHint(data.gdipGraphics, textMode); | |
4675 } | |
4676 | |
4677 /** | |
4678 * Sets the transform that is currently being used by the receiver. If | |
4679 * the argument is <code>null</code>, the current transform is set to | |
4680 * the identity transform. | |
4681 * <p> | |
4682 * This operation requires the operating system's advanced | |
4683 * graphics subsystem which may not be available on some | |
4684 * platforms. | |
4685 * </p> | |
4686 * | |
4687 * @param transform the transform to set | |
4688 * | |
4689 * @exception IllegalArgumentException <ul> | |
4690 * <li>ERROR_INVALID_ARGUMENT - if the parameter has been disposed</li> | |
4691 * </ul> | |
4692 * @exception SWTException <ul> | |
4693 * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> | |
4694 * <li>ERROR_NO_GRAPHICS_LIBRARY - if advanced graphics are not available</li> | |
4695 * </ul> | |
4696 * | |
4697 * @see Transform | |
4698 * @see #getAdvanced | |
4699 * @see #setAdvanced | |
4700 * | |
4701 * @since 3.1 | |
4702 */ | |
4703 public void setTransform(Transform transform) { | |
4704 if (handle is null) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); | |
4705 if (transform !is null && transform.isDisposed()) SWT.error(SWT.ERROR_INVALID_ARGUMENT); | |
4706 if (data.gdipGraphics is null && transform is null) return; | |
4707 initGdip(); | |
4708 auto identity_ = identity(); | |
4709 if (transform !is null) { | |
4710 Gdip.Matrix_Multiply(identity_, transform.handle, Gdip.MatrixOrderPrepend); | |
4711 } | |
4712 Gdip.Graphics_SetTransform(data.gdipGraphics, identity_); | |
4713 Gdip.Matrix_delete(identity_); | |
4714 data.state &= ~DRAW_OFFSET; | |
4715 } | |
4716 | |
4717 /** | |
4718 * Returns the extent of the given string. No tab | |
4719 * expansion or carriage return processing will be performed. | |
4720 * <p> | |
4721 * The <em>extent</em> of a string is the width and height of | |
4722 * the rectangular area it would cover if drawn in a particular | |
4723 * font (in this case, the current font in the receiver). | |
4724 * </p> | |
4725 * | |
4726 * @param string the string to measure | |
4727 * @return a point containing the extent of the string | |
4728 * | |
4729 * @exception SWTException <ul> | |
4730 * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> | |
4731 * </ul> | |
4732 */ | |
4733 public Point stringExtent(String string) { | |
4734 if (handle is null) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); | |
4735 // SWT externsion: allow null string | |
4736 //if (string is null) SWT.error (SWT.ERROR_NULL_ARGUMENT); | |
4737 checkGC(FONT); | |
4738 int length_ = string.length; | |
4739 if (data.gdipGraphics !is null) { | |
4740 Gdip.PointF pt; | |
4741 Gdip.RectF bounds; | |
4742 wchar* buffer; | |
4743 if (length_ !is 0) { | |
4744 wchar[] wstr = StrToWCHARs( string ); | |
4745 buffer = wstr.ptr; | |
4746 length_ = wstr.length; | |
4747 } else { | |
4748 buffer = (" "w).ptr; | |
4749 } | |
4750 auto format = Gdip.StringFormat_Clone(Gdip.StringFormat_GenericTypographic()); | |
4751 int formatFlags = Gdip.StringFormat_GetFormatFlags(format) | Gdip.StringFormatFlagsMeasureTrailingSpaces; | |
4752 if ((data.style & SWT.MIRRORED) !is 0) formatFlags |= Gdip.StringFormatFlagsDirectionRightToLeft; | |
4753 Gdip.StringFormat_SetFormatFlags(format, formatFlags); | |
4754 Gdip.Graphics_MeasureString(data.gdipGraphics, buffer, length_, data.gdipFont, pt, format, bounds); | |
4755 Gdip.StringFormat_delete(format); | |
4756 return new Point(length_ is 0 ? 0 : Math.rndint(bounds.Width), Math.rndint(bounds.Height)); | |
4757 } | |
4758 SIZE size; | |
4759 if (length_ is 0) { | |
4760 // OS.GetTextExtentPoint32(handle, SPACE, SPACE.length(), size); | |
4761 OS.GetTextExtentPoint32W(handle, (" "w).ptr, 1, &size); | |
4762 return new Point(0, size.cy); | |
4763 } else { | |
4764 // TCHAR buffer = new TCHAR (getCodePage(), string, false); | |
4765 wchar[] wstr = StrToWCHARs( string ); | |
4766 wchar* buffer = wstr.ptr; | |
4767 length_ = wstr.length; | |
4768 OS.GetTextExtentPoint32W(handle, buffer, length_, &size); | |
4769 return new Point(size.cx, size.cy); | |
4770 } | |
4771 } | |
4772 | |
4773 /** | |
4774 * Returns the extent of the given string. Tab expansion and | |
4775 * carriage return processing are performed. | |
4776 * <p> | |
4777 * The <em>extent</em> of a string is the width and height of | |
4778 * the rectangular area it would cover if drawn in a particular | |
4779 * font (in this case, the current font in the receiver). | |
4780 * </p> | |
4781 * | |
4782 * @param string the string to measure | |
4783 * @return a point containing the extent of the string | |
4784 * | |
4785 * @exception SWTException <ul> | |
4786 * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> | |
4787 * </ul> | |
4788 */ | |
4789 public Point textExtent(String string) { | |
4790 return textExtent(string, SWT.DRAW_DELIMITER | SWT.DRAW_TAB); | |
4791 } | |
4792 | |
4793 /** | |
4794 * Returns the extent of the given string. Tab expansion, line | |
4795 * delimiter and mnemonic processing are performed according to | |
4796 * the specified flags, which can be a combination of: | |
4797 * <dl> | |
4798 * <dt><b>DRAW_DELIMITER</b></dt> | |
4799 * <dd>draw multiple lines</dd> | |
4800 * <dt><b>DRAW_TAB</b></dt> | |
4801 * <dd>expand tabs</dd> | |
4802 * <dt><b>DRAW_MNEMONIC</b></dt> | |
4803 * <dd>underline the mnemonic character</dd> | |
4804 * <dt><b>DRAW_TRANSPARENT</b></dt> | |
4805 * <dd>transparent background</dd> | |
4806 * </dl> | |
4807 * <p> | |
4808 * The <em>extent</em> of a string is the width and height of | |
4809 * the rectangular area it would cover if drawn in a particular | |
4810 * font (in this case, the current font in the receiver). | |
4811 * </p> | |
4812 * | |
4813 * @param string the string to measure | |
4814 * @param flags the flags specifying how to process the text | |
4815 * @return a point containing the extent of the string | |
4816 * | |
4817 * @exception SWTException <ul> | |
4818 * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> | |
4819 * </ul> | |
4820 */ | |
4821 public Point textExtent(String string, int flags) { | |
4822 if (handle is null) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); | |
4823 //DWT_CHANGE: allow null string | |
4824 //if (string is null) SWT.error (SWT.ERROR_NULL_ARGUMENT); | |
4825 checkGC(FONT); | |
4826 if (data.gdipGraphics !is null) { | |
4827 Gdip.PointF pt; | |
4828 Gdip.RectF bounds; | |
4829 wchar* buffer; | |
4830 int length_ = string.length; | |
4831 if (length_ !is 0) { | |
4832 wchar[] wstr = StrToWCHARs( string ); | |
4833 buffer = wstr.ptr; | |
4834 length_ = wstr.length; | |
4835 } else { | |
4836 buffer = (" "w).ptr; | |
4837 } | |
4838 auto format = Gdip.StringFormat_Clone(Gdip.StringFormat_GenericTypographic()); | |
4839 int formatFlags = Gdip.StringFormat_GetFormatFlags(format) | Gdip.StringFormatFlagsMeasureTrailingSpaces; | |
4840 if ((data.style & SWT.MIRRORED) !is 0) formatFlags |= Gdip.StringFormatFlagsDirectionRightToLeft; | |
4841 Gdip.StringFormat_SetFormatFlags(format, formatFlags); | |
4842 float[] tabs = (flags & SWT.DRAW_TAB) !is 0 ? [measureSpace(data.gdipFont, format) * 8] : new float[1]; | |
4843 Gdip.StringFormat_SetTabStops(format, 0, tabs.length, tabs.ptr); | |
4844 Gdip.StringFormat_SetHotkeyPrefix(format, (flags & SWT.DRAW_MNEMONIC) !is 0 ? Gdip.HotkeyPrefixShow : Gdip.HotkeyPrefixNone); | |
4845 Gdip.Graphics_MeasureString(data.gdipGraphics, buffer, length_, data.gdipFont, pt, format, bounds); | |
4846 Gdip.StringFormat_delete(format); | |
4847 return new Point(length_ is 0 ? 0 : Math.rndint(bounds.Width), Math.rndint(bounds.Height)); | |
4848 } | |
4849 if (string.length is 0) { | |
4850 SIZE size; | |
4851 // OS.GetTextExtentPoint32(handle, SPACE, SPACE.length(), size); | |
4852 OS.GetTextExtentPoint32W(handle, (" "w).ptr, 1, &size); | |
4853 return new Point(0, size.cy); | |
4854 } | |
4855 RECT rect; | |
4856 auto wstr = StrToTCHARs( string ); | |
4857 TCHAR* buffer = wstr.ptr; | |
4858 int length_ = wstr.length; | |
4859 int uFormat = OS.DT_LEFT | OS.DT_CALCRECT; | |
4860 if ((flags & SWT.DRAW_DELIMITER) is 0) uFormat |= OS.DT_SINGLELINE; | |
4861 if ((flags & SWT.DRAW_TAB) !is 0) uFormat |= OS.DT_EXPANDTABS; | |
4862 if ((flags & SWT.DRAW_MNEMONIC) is 0) uFormat |= OS.DT_NOPREFIX; | |
4863 OS.DrawText(handle, buffer, length_, &rect, uFormat); | |
4864 return new Point(rect.right, rect.bottom); | |
4865 } | |
4866 | |
4867 /** | |
4868 * Returns a string containing a concise, human-readable | |
4869 * description of the receiver. | |
4870 * | |
4871 * @return a string representation of the receiver | |
4872 */ | |
4873 override public String toString () { | |
4874 if (isDisposed()) return "GC {*DISPOSED*}"; | |
4875 return Format( "GC {{{}}", handle ); | |
4876 } | |
4877 | |
4878 /** | |
4879 * Invokes platform specific functionality to allocate a new graphics context. | |
4880 * <p> | |
4881 * <b>IMPORTANT:</b> This method is <em>not</em> part of the public | |
4882 * API for <code>GC</code>. It is marked public only so that it | |
4883 * can be shared within the packages provided by SWT. It is not | |
4884 * available on all platforms, and should never be called from | |
4885 * application code. | |
4886 * </p> | |
4887 * | |
4888 * @param drawable the Drawable for the receiver. | |
4889 * @param data the data for the receiver. | |
4890 * | |
4891 * @return a new <code>GC</code> | |
4892 */ | |
4893 public static GC win32_new(Drawable drawable, GCData data) { | |
4894 GC gc = new GC(); | |
4895 auto hDC = drawable.internal_new_GC(data); | |
4896 gc.disposeChecking = false; | |
4897 gc.device = data.device; | |
4898 gc.init_(drawable, data, hDC); | |
4899 return gc; | |
4900 } | |
4901 | |
4902 /** | |
4903 * Invokes platform specific functionality to wrap a graphics context. | |
4904 * <p> | |
4905 * <b>IMPORTANT:</b> This method is <em>not</em> part of the public | |
4906 * API for <code>GC</code>. It is marked public only so that it | |
4907 * can be shared within the packages provided by SWT. It is not | |
4908 * available on all platforms, and should never be called from | |
4909 * application code. | |
4910 * </p> | |
4911 * | |
4912 * @param hDC the Windows HDC. | |
4913 * @param data the data for the receiver. | |
4914 * | |
4915 * @return a new <code>GC</code> | |
4916 */ | |
4917 public static GC win32_new(HDC hDC, GCData data) { | |
4918 GC gc = new GC(); | |
4919 gc.disposeChecking = false; | |
4920 gc.device = data.device; | |
4921 data.style |= SWT.LEFT_TO_RIGHT; | |
4922 if (OS.WIN32_VERSION >= OS.VERSION (4, 10)) { | |
4923 int flags = OS.GetLayout (hDC); | |
4924 if ((flags & OS.LAYOUT_RTL) !is 0) { | |
4925 data.style |= SWT.RIGHT_TO_LEFT | SWT.MIRRORED; | |
4926 } | |
4927 } | |
4928 gc.init_(null, data, hDC); | |
4929 return gc; | |
4930 } | |
4931 | |
4932 } |