1 /** DGui project file.
2 
3 Copyright: Trogu Antonio Davide 2011-2013
4 
5 License: $(HTTP boost.org/LICENSE_1_0.txt, Boost License 1.0).
6 
7 Authors: Trogu Antonio Davide
8 */
9 module dguihub.canvas;
10 
11 import std.conv : to;
12 import std.path;
13 import std..string;
14 import core.memory;
15 import dguihub.core.interfaces.idisposable;
16 import dguihub.core.charset;
17 import dguihub.core.winapi;
18 import dguihub.core.exception;
19 import dguihub.core.handle;
20 import dguihub.core.utils;
21 public import dguihub.core.geometry;
22 
23 /**
24   Enum that contain the font style of a Font Object.
25   */
26 enum FontStyle : ubyte {
27    normal = 0, /// Normal Font Style
28    bold = 1, /// Bold Font Style
29    italic = 2, /// Italic Font Style
30    underline = 4, /// Underline Font Style
31    strikeout = 8, /// Strikeout Font Style
32 }
33 
34 /**
35   Enum that contain the image type (useful in order to identify a Image object).
36   */
37 
38 enum ImageType {
39    bitmap = 0, /// Bitmap Image
40    iconOrCursor = 1, /// Icon or Cursor
41 }
42 
43 /**
44   Enum that specify the fill mode of a gradient.
45   */
46 enum GradientFillRectMode {
47    horizontal = 0, /// Horizontal Fill
48    vertical = 1, /// Vertical Fill
49 }
50 
51 /**
52   Enum that specify the border type (used in a Canvas.drawEdge() call).
53   */
54 enum EdgeType : uint {
55    raisedOuter = BDR_RAISEDOUTER, /// Raised Outer Edge
56    raisedInner = BDR_RAISEDINNER, /// Raised Innter Edge
57 
58    sunkenOuter = BDR_SUNKENOUTER, /// Sunken Outer Edge
59    sunkenInner = BDR_SUNKENINNER, /// Sunken Inner Edge
60 
61    bump = EDGE_BUMP, /// Bump Edge
62    etched = EDGE_ETCHED, /// Etched Edge
63    raised = EDGE_RAISED, /// Edge Raised Edge
64    sunken = EDGE_SUNKEN, /// Sunken Edge
65 }
66 
67 enum FrameType : uint {
68    button = DFC_BUTTON,
69    caption = DFC_CAPTION,
70    menu = DFC_MENU,
71    popupMenu = DFC_POPUPMENU,
72    scroll = DFC_SCROLL,
73 }
74 
75 enum FrameMode : uint {
76    button3state = DFCS_BUTTON3STATE,
77    buttonCheck = DFCS_BUTTONCHECK,
78    buttonPush = DFCS_BUTTONPUSH,
79    buttonRadio = DFCS_BUTTONRADIO,
80    buttonRadioImage = DFCS_BUTTONRADIOIMAGE,
81    buttonRadioMask = DFCS_BUTTONRADIOMASK,
82 
83    captionClose = DFCS_CAPTIONCLOSE,
84    captionHelp = DFCS_CAPTIONHELP,
85    captionMax = DFCS_CAPTIONMAX,
86    captionMin = DFCS_CAPTIONMIN,
87    captionRestore = DFCS_CAPTIONRESTORE,
88 
89    menuArrow = DFCS_MENUARROW,
90    menuArrowRight = DFCS_MENUARROWRIGHT,
91    menuBullet = DFCS_MENUBULLET,
92    menuCheck = DFCS_MENUCHECK,
93 
94    scrollComboBox = DFCS_SCROLLCOMBOBOX,
95    scrollDown = DFCS_SCROLLDOWN,
96    scrollLeft = DFCS_SCROLLLEFT,
97    scrollRight = DFCS_SCROLLRIGHT,
98    scrollSizeGrip = DFCS_SCROLLSIZEGRIP,
99    scrollSizeGripRight = DFCS_SCROLLSIZEGRIPRIGHT,
100    scrollUp = DFCS_SCROLLUP,
101 
102    checked = DFCS_CHECKED,
103    flat = DFCS_FLAT,
104    hot = DFCS_HOT,
105    inactive = DFCS_INACTIVE,
106    mono = DFCS_MONO,
107    pushed = DFCS_PUSHED,
108    transparent = DFCS_TRANSPARENT,
109 }
110 
111 /**
112   Enum that specify the draw border mode  (used in a Canvas.drawEdge() call).
113   */
114 enum EdgeMode : uint {
115    adjust = BF_ADJUST, /// Shrink the rectangle in order to exlude the edges that were drawn.
116    diagonal = BF_DIAGONAL, /// Diagonal Border.
117    flat = BF_FLAT, /// Flat Border.
118    left = BF_LEFT, /// Left Border Only.
119    top = BF_TOP, /// Top Border Only.
120    right = BF_RIGHT, /// Right Border Only.
121    bottom = BF_BOTTOM, /// Bottom Border Only.
122    internal = BF_MIDDLE, /// Internal Border will be filled.
123    mono = BF_MONO, /// One Dimensional Border.
124    rect = BF_RECT, /// Fills the entire border of the rectangle.
125    //SOFT 	 = BF_SOFT,
126 }
127 
128 /**
129   Enum that specify the style of a Hatch Brush object
130   */
131 enum HatchStyle : int {
132    horizontal = HS_HORIZONTAL, /// The brush has horizontal stripes.
133    vertical = HS_VERTICAL, /// The brush has vertical stripes.
134    degree45Upward = HS_BDIAGONAL, /// The brush has 45° degree rising stripes.
135    degree45Downward = HS_FDIAGONAL, /// The brush has 45° degree falling stripes.
136    cross = HS_CROSS, /// The brush has crossed stripes.
137    diagonalCross = HS_DIAGCROSS, /// The brush has diagonal crossed stripes.
138 }
139 
140 /**
141   Enum that specify the style of a Pen object.
142   */
143 enum PenStyle : uint {
144    solid = PS_SOLID, /// Solid Pen (Standard).
145    dash = PS_DASH, /// Dashed Pen.
146    dot = PS_DOT, /// Dotted Pen.
147    dashDot = PS_DASHDOT, /// Dash-Dotted Pen.
148    dashDotDot = PS_DASHDOTDOT, /// Dashed-Dotted-Dotted Pen.
149    null_ = PS_NULL, /// Invisible Pen.
150    insideFrame = PS_INSIDEFRAME, /// Solid Pen (line are drown inside the border of a closed shape).
151 }
152 
153 /**
154   Enum that specify the style of a text in a drawText() call
155   */
156 enum TextFormatFlags : uint {
157    noPrefix = DT_NOPREFIX, /// Turn of processing of prefix characters (like '&', character that it will be not displayed underline).
158    wordBreak = DT_WORDBREAK, /// Break the line if a carriage return is found or the selected rectangle is too small.
159    singleLine = DT_SINGLELINE, /// The text is draw in one single line.
160    lineLimit = DT_EDITCONTROL, /// Duplicate the text displaying of a multiline control.
161    noClip = DT_NOCLIP, /// The text is not clipped.
162    //DIRECTION_RIGHT_TO_LEFT = DT_RTLREADING,
163 }
164 
165 /**
166   Enum that specify the style of a text alignment in a drawText() call
167   */
168 enum TextAlignment : uint {
169    left = DT_LEFT, /// Text is left aligned.
170    right = DT_RIGHT, /// Text is right aligned.
171    center = DT_CENTER, /// Text is centred horizontally.
172 
173    top = DT_TOP, /// Text is top aligned.
174    bottom = DT_BOTTOM, /// Text is bottom aligned.
175    middle = DT_VCENTER, /// Text is centred vertically.
176 }
177 
178 /**
179   Enum that specify the trimming of a text alignment in a drawText() call
180   */
181 enum TextTrimming : uint {
182    none = 0, /// No Trimming.
183    ellipsis = DT_END_ELLIPSIS, /// If the text is too long, it will be replaced with end ellipsis (like: ellips...).
184    ellipsisPath = DT_PATH_ELLIPSIS, /// If the text is too long, it will be replaces with middle ellipsis (like: texttr...ing).
185 }
186 
187 /**
188   Specify the copy mode of a Bitmap
189   */
190 enum BitmapCopyMode {
191    normal = SRCCOPY, /// Standard Copy.
192    invert = SRCINVERT, /// Copy Inverted.
193    and = SRCAND, /// Copy using _AND operator (Source _AND Destination).
194    or = SRCPAINT, /// Copy using _OR operator (Source _OR Destination).
195 }
196 
197 /**
198   It rappresentes a color of a bitmap.
199   */
200 struct BitmapBit {
201    union {
202       ubyte rgbBlue;
203       ubyte blue; /// Blue color.
204    }
205 
206    union {
207       ubyte rgbGreen;
208       ubyte green; /// Green color.
209    }
210 
211    union {
212       ubyte rgbRed;
213       ubyte red; /// Red color.
214    }
215 
216    union {
217       ubyte rgbReserved;
218       ubyte alpha; /// Alpha channel (if available).
219    }
220 }
221 
222 /**
223   This structure allows direct modification of a bitmap
224   */
225 struct BitmapData {
226    BITMAPINFO* info; /// BITMAPINFO structure (usually, it is used internally).
227    uint imageSize; /// The size of the _Bitmap.
228    uint bitsCount; /// Number of BitmapBits structure of the _Bitmap (is the _Bits field length).
229    BitmapBit* bits; /// Pointer to the _Bitmap's bits (it allows direct modification of the colors)
230 }
231 
232 /**
233   A _Color in ARGB format (compatible with COLORREF win32 type)
234   */
235 struct Color {
236    private bool _valid = false; // Check if it was assigned a value
237 
238    public union {
239       align(1) struct {
240          ubyte red = 0x00;
241          ubyte green = 0x00;
242          ubyte blue = 0x00;
243          ubyte alpha = 0x00; //0x00: Transparent (or Don't Care), 0xFF: Opaque
244       }
245 
246       COLORREF colorref; /// Compatibility with COLORREF type
247    }
248 
249    /// Checks if the color information is _valid.
250    @property public final bool valid() {
251       return this._valid;
252    }
253 
254    public static Color opCall(ubyte r, ubyte g, ubyte b) {
255       return Color(0x00, r, g, b);
256    }
257 
258    public static Color opCall(ubyte a, ubyte r, ubyte g, ubyte b) {
259       Color color = void; //Inializzata sotto;
260 
261       color._valid = true;
262 
263       color.alpha = a;
264       color.red = r;
265       color.green = g;
266       color.blue = b;
267 
268       return color;
269    }
270 
271    /// Returns an invalid color
272    public static Color invalid() {
273       static Color color;
274       //color._valid = false; //Set valid to false (false = default value)
275       return color;
276    }
277 
278    /// Given a COLORREF, it returns a _Color object
279    public static Color fromCOLORREF(COLORREF cref) {
280       Color color = void;
281 
282       color._valid = true;
283       color.colorref = cref;
284       return color;
285    }
286 }
287 
288 struct FontMetrics {
289    int height;
290    int ascent;
291    int descent;
292    int internalLeading;
293    int externalLeading;
294    int averageCharWidth;
295    int maxCharWidth;
296 }
297 
298 /**
299  The _Canvas object is the DGui's rappresentation of a Device Context (Screen DC, Memory DC and Printer DC)
300  $(DDOC_BLANKLINE)
301  $(B Note): Printer DC is not implemented
302  */
303 class Canvas : Handle!(HDC), IDisposable {
304    private alias extern (Windows) BOOL function(HDC, int, int, int, int, HDC,
305          int, int, int, int, UINT) GdiTransparentBltProc;
306    private alias extern (Windows) BOOL function(HDC, int, int, int, int, HDC,
307          int, int, int, int, BLENDFUNCTION) GdiAlphaBlendProc;
308    private alias extern (Windows) BOOL function(HDC, TRIVERTEX*, ULONG, void*, ULONG, ULONG) GdiGradientFillProc;
309 
310    private static GdiTransparentBltProc _gdiTransparentBlt = null;
311    private static GdiAlphaBlendProc _gdiAlphaBlend = null;
312    private static GdiGradientFillProc _gdiGradientFill = null;
313 
314    private enum CanvasType : ubyte {
315       normal = 0,
316       fromControl = 1,
317       inMemory = 2,
318    }
319 
320    private CanvasType _canvasType = CanvasType.normal;
321    private HBITMAP _hBitmap;
322    private bool _owned;
323 
324    protected this(HDC hdc, bool owned, CanvasType type) {
325       this._handle = hdc;
326       this._owned = owned;
327       this._canvasType = type;
328    }
329 
330    public ~this() {
331       this.dispose();
332    }
333 
334    public void copyTo(Canvas c, BitmapCopyMode bcm, Rect destRect, Point posSrc) {
335       BITMAP bmp;
336 
337       if (!destRect.width && destRect.height) {
338          GetObjectW(GetCurrentObject(this._handle, OBJ_BITMAP), BITMAP.sizeof, &bmp);
339       }
340 
341       BitBlt(c.handle, destRect.x, destRect.y, destRect.width ? destRect.width
342             : bmp.bmWidth, destRect.height ? destRect.height : bmp.bmHeight,
343             this._handle, posSrc.x, posSrc.y, bcm);
344    }
345 
346    public void copyTo(Canvas c, Rect destRect, Point posSrc) {
347       this.copyTo(c, BitmapCopyMode.normal, destRect, posSrc);
348    }
349 
350    public void copyTo(Canvas c, BitmapCopyMode bcm, Rect destRect) {
351       this.copyTo(c, bcm, destRect, nullPoint);
352    }
353 
354    public void copyTo(Canvas c, BitmapCopyMode bcm) {
355       this.copyTo(c, bcm, nullRect, nullPoint);
356    }
357 
358    public void copyTo(Canvas c) {
359       this.copyTo(c, BitmapCopyMode.normal);
360    }
361 
362    public void copyTransparent(Canvas c, Color transpColor) {
363       this.copyTransparent(c, transpColor, nullRect);
364    }
365 
366    public void copyTransparent(Canvas c, Color transpColor, Rect r) {
367       if (!_gdiTransparentBlt) {
368          _gdiTransparentBlt = cast(GdiTransparentBltProc)GetProcAddress(
369                getModuleHandle("gdi32.dll"), toStringz("GdiTransparentBlt"));
370       }
371 
372       BITMAP bmp;
373       HBITMAP hBitmap = GetCurrentObject(this._handle, OBJ_BITMAP);
374       GetObjectW(hBitmap, BITMAP.sizeof, &bmp);
375 
376       if (r.empty) {
377          r = Rect(0, 0, bmp.bmWidth, bmp.bmHeight);
378       }
379 
380       _gdiTransparentBlt(c.handle, r.x, r.y, r.width, r.height, this._handle,
381             0, 0, bmp.bmWidth, bmp.bmHeight, transpColor.colorref);
382    }
383 
384    public void dispose() {
385       if (this._handle && this._owned) {
386          switch (this._canvasType) {
387          case CanvasType.fromControl:
388             ReleaseDC(WindowFromDC(this._handle), this._handle);
389             break;
390 
391          case CanvasType.inMemory:
392             DeleteObject(this._hBitmap);
393             DeleteDC(this._handle);
394             break;
395 
396          default:
397             break;
398          }
399 
400          this._handle = null;
401       }
402    }
403 
404    public static Size measureString(string s, Canvas c, Font f) {
405       Size sz;
406 
407       HFONT hOldFont = f ? SelectObject(c.handle, f.handle) : null;
408       GetTextExtentPoint32W(c.handle, toUTFz!(wchar*)(s), s.length, &sz.size);
409 
410       if (f) {
411          SelectObject(c.handle, hOldFont);
412       }
413 
414       return sz;
415    }
416 
417    public static Size measureString(string s, Canvas c) {
418       return Canvas.measureString(s, c, null);
419    }
420 
421    public static Size measureString(string s, Font f) {
422       scope Canvas c = Screen.canvas;
423       return Canvas.measureString(s, c, f);
424    }
425 
426    public static Size measureString(string s) {
427       scope Canvas c = Screen.canvas;
428       return Canvas.measureString(s, c, SystemFonts.windowsFont);
429    }
430 
431    public final void fillRectGradient(Rect r, Color startColor, Color endColor,
432          GradientFillRectMode gfrm) {
433       if (!_gdiGradientFill) {
434          _gdiGradientFill = cast(GdiGradientFillProc)GetProcAddress(getModuleHandle("gdi32.dll"),
435                toStringz("GdiGradientFill"));
436       }
437 
438       TRIVERTEX[2] tv;
439       static GRADIENT_RECT gr = {UpperLeft:
440       0, LowerRight : 1};
441 
442       tv[0].x = r.left;
443       tv[0].y = r.top;
444       tv[0].Red = startColor.red << 8;
445       tv[0].Green = startColor.green << 8;
446       tv[0].Blue = startColor.blue << 8;
447       tv[0].Alpha = startColor.alpha << 8;
448 
449       tv[1].x = r.right;
450       tv[1].y = r.bottom;
451       tv[1].Red = endColor.red << 8;
452       tv[1].Green = endColor.green << 8;
453       tv[1].Blue = endColor.blue << 8;
454       tv[1].Alpha = endColor.alpha << 8;
455 
456       _gdiGradientFill(this._handle, tv.ptr, 2, &gr, 1, gfrm);
457    }
458 
459    public final void fillTriangleGradient(int x1, int y1, int x2, int y2, int x3,
460          int y3, Color color1, Color color2, Color color3) {
461       this.fillTriangleGradient(Point(x1, y1), Point(x2, y2), Point(x3, y3),
462             color1, color2, color3);
463    }
464 
465    public final void fillTriangleGradient(Point pt1, Point pt2, Point pt3,
466          Color color1, Color color2, Color color3) {
467       if (!_gdiGradientFill) {
468          _gdiGradientFill = cast(GdiGradientFillProc)GetProcAddress(getModuleHandle("gdi32.dll"),
469                toStringz("GdiGradientFill"));
470       }
471 
472       TRIVERTEX[3] tv;
473       static GRADIENT_TRIANGLE gt = {Vertex1:
474       0, Vertex2 : 1, Vertex3 : 2};
475 
476       tv[0].x = pt1.x;
477       tv[0].y = pt1.y;
478       tv[0].Red = color1.red << 8;
479       tv[0].Green = color1.green << 8;
480       tv[0].Blue = color1.blue << 8;
481       tv[0].Alpha = color1.alpha << 8;
482 
483       tv[1].x = pt2.x;
484       tv[1].y = pt2.y;
485       tv[1].Red = color2.red << 8;
486       tv[1].Green = color2.green << 8;
487       tv[1].Blue = color2.blue << 8;
488       tv[1].Alpha = color2.alpha << 8;
489 
490       tv[2].x = pt3.x;
491       tv[2].y = pt3.y;
492       tv[2].Red = color3.red << 8;
493       tv[2].Green = color3.green << 8;
494       tv[2].Blue = color3.blue << 8;
495       tv[2].Alpha = color3.alpha << 8;
496 
497       _gdiGradientFill(this._handle, tv.ptr, 3, &gt, 1, 2 /* GRADIENT_FILL_TRIANGLE */ );
498    }
499 
500    public final void drawImage(Image img, Point upLeft, Point upRight, Point lowLeft) {
501       this.drawImage(img, 0, 0, upLeft, upRight, lowLeft);
502    }
503 
504    public final void drawImage(Image img, int x, int y, Point upLeft, Point upRight, Point lowLeft) {
505       POINT[3] pts;
506 
507       pts[0] = upLeft.point;
508       pts[1] = upRight.point;
509       pts[2] = lowLeft.point;
510 
511       Size sz = img.size;
512       HDC hdc = CreateCompatibleDC(this._handle);
513       HBITMAP hOldBitmap = SelectObject(hdc, img.handle);
514 
515       PlgBlt(this._handle, pts.ptr, hdc, x, y, sz.width, sz.height, null, 0, 0);
516 
517       SelectObject(hdc, hOldBitmap);
518       DeleteDC(hdc);
519    }
520 
521    public final void drawImage(Image img, int x, int y) {
522       Size sz = img.size;
523 
524       switch (img.type) {
525       case ImageType.bitmap:
526          HDC hdc = CreateCompatibleDC(this._handle);
527          HBITMAP hOldBitmap = SelectObject(hdc, img.handle);
528          BitBlt(this._handle, x, y, sz.width, sz.height, hdc, 0, 0, SRCCOPY);
529          SelectObject(hdc, hOldBitmap);
530          DeleteDC(hdc);
531          break;
532 
533       case ImageType.iconOrCursor:
534          DrawIconEx(this._handle, x, y, img.handle,
535                sz.width, sz.height, 0, null, DI_NORMAL);
536          break;
537 
538       default:
539          break;
540       }
541    }
542 
543    public final void drawImage(Image img, Rect r) {
544       Size sz = img.size;
545 
546       switch (img.type) {
547       case ImageType.bitmap:
548          HDC hdc = CreateCompatibleDC(this._handle);
549          HBITMAP hOldBitmap = SelectObject(hdc, img.handle);
550          StretchBlt(this._handle, r.x, r.y, r.width, r.height, hdc, 0, 0,
551                sz.width, sz.height, SRCCOPY);
552          SelectObject(hdc, hOldBitmap);
553          DeleteDC(hdc);
554          break;
555 
556       case ImageType.iconOrCursor:
557          DrawIconEx(this._handle, r.x, r.y,
558                img.handle, r.width, r.height, 0, null, DI_NORMAL);
559          break;
560 
561       default:
562          break;
563       }
564    }
565 
566    public final void drawFrameControl(Rect r, FrameType frameType, FrameMode frameMode) {
567       DrawFrameControl(this._handle, &r.rect, frameType, frameMode);
568    }
569 
570    public final void drawEdge(Rect r, EdgeType edgeType, EdgeMode edgeMode) {
571       DrawEdge(this._handle, &r.rect, edgeType, edgeMode);
572    }
573 
574    public final void drawText(string text, Rect r, Color foreColor, Font font,
575          TextFormat textFormat) {
576       DRAWTEXTPARAMS dtp;
577 
578       dtp.cbSize = DRAWTEXTPARAMS.sizeof;
579       dtp.iLeftMargin = textFormat.leftMargin;
580       dtp.iRightMargin = textFormat.rightMargin;
581       dtp.iTabLength = textFormat.tabLength;
582 
583       HFONT hOldFont = SelectObject(this._handle, font.handle);
584       COLORREF oldColorRef = SetTextColor(this._handle, foreColor.colorref);
585       int oldBkMode = SetBkMode(this._handle, TRANSPARENT);
586 
587       drawTextEx(this._handle, text, &r.rect,
588             DT_EXPANDTABS | DT_TABSTOP | textFormat.formatFlags | textFormat.alignment | textFormat.trimming,
589             &dtp);
590 
591       SetBkMode(this._handle, oldBkMode);
592       SetTextColor(this._handle, oldColorRef);
593       SelectObject(this._handle, hOldFont);
594    }
595 
596    public final void drawText(string text, Rect r, Color foreColor, Font font) {
597       scope TextFormat tf = new TextFormat(
598             TextFormatFlags.noPrefix | TextFormatFlags.wordBreak
599             | TextFormatFlags.noClip | TextFormatFlags.lineLimit);
600 
601       tf.trimming = TextTrimming.none;
602 
603       this.drawText(text, r, foreColor, font, tf);
604    }
605 
606    public final void drawText(string text, Rect r, Color foreColor) {
607       scope Font f = Font.fromHFONT(GetCurrentObject(this._handle, OBJ_FONT), false);
608       this.drawText(text, r, foreColor, f);
609    }
610 
611    public final void drawText(string text, Rect r, Font f, TextFormat tf) {
612       this.drawText(text, r, Color.fromCOLORREF(GetTextColor(this._handle)), f, tf);
613    }
614 
615    public final void drawText(string text, Rect r, TextFormat tf) {
616       scope Font f = Font.fromHFONT(GetCurrentObject(this._handle, OBJ_FONT), false);
617       this.drawText(text, r, Color.fromCOLORREF(GetTextColor(this._handle)), f, tf);
618    }
619 
620    public final void drawText(string text, Rect r, Font f) {
621       this.drawText(text, r, Color.fromCOLORREF(GetTextColor(this._handle)), f);
622    }
623 
624    public final void drawText(string text, Rect r) {
625       scope Font f = Font.fromHFONT(GetCurrentObject(this._handle, OBJ_FONT), false);
626       this.drawText(text, r, Color.fromCOLORREF(GetTextColor(this._handle)), f);
627    }
628 
629    public final void drawLine(Pen p, int x1, int y1, int x2, int y2) {
630       HPEN hOldPen = SelectObject(this._handle, p.handle);
631 
632       MoveToEx(this._handle, x1, y1, null);
633       LineTo(this._handle, x2, y2);
634 
635       SelectObject(this._handle, hOldPen);
636    }
637 
638    public final void drawEllipse(Pen pen, Brush fill, Rect r) {
639       HPEN hOldPen;
640       HBRUSH hOldBrush;
641 
642       if (pen) {
643          hOldPen = SelectObject(this._handle, pen.handle);
644       }
645 
646       if (fill) {
647          hOldBrush = SelectObject(this._handle, fill.handle);
648       }
649 
650       Ellipse(this._handle, r.left, r.top, r.right, r.bottom);
651 
652       if (hOldBrush) {
653          SelectObject(this._handle, hOldBrush);
654       }
655 
656       if (hOldPen) {
657          SelectObject(this._handle, hOldPen);
658       }
659    }
660 
661    public final void drawEllipse(Pen pen, Rect r) {
662       this.drawEllipse(pen, SystemBrushes.nullBrush, r);
663    }
664 
665    public final void drawRectangle(Pen pen, Brush fill, Rect r) {
666       HPEN hOldPen;
667       HBRUSH hOldBrush;
668 
669       if (pen) {
670          hOldPen = SelectObject(this._handle, pen.handle);
671       }
672 
673       if (fill) {
674          hOldBrush = SelectObject(this._handle, fill.handle);
675       }
676 
677       Rectangle(this._handle, r.left, r.top, r.right, r.bottom);
678 
679       if (hOldBrush) {
680          SelectObject(this._handle, hOldBrush);
681       }
682 
683       if (hOldPen) {
684          SelectObject(this._handle, hOldPen);
685       }
686    }
687 
688    public final void drawRectangle(Pen pen, Rect r) {
689       this.drawRectangle(pen, SystemBrushes.nullBrush, r);
690    }
691 
692    public final void fillRectangle(Brush b, Rect r) {
693       FillRect(this._handle, &r.rect, b.handle);
694    }
695 
696    public final void fillEllipse(Brush b, Rect r) {
697       this.drawEllipse(SystemPens.nullPen, b, r);
698    }
699 
700    public final Canvas createInMemory(Bitmap b) {
701       HDC hdc = CreateCompatibleDC(this._handle);
702       Canvas c = new Canvas(hdc, true, CanvasType.inMemory);
703 
704       if (!b) {
705          Rect r;
706          HWND hWnd = WindowFromDC(this._handle);
707 
708          if (hWnd) {
709             GetClientRect(hWnd, &r.rect);
710          } else // Try with bitmap's size
711          {
712             BITMAP bmp;
713             HBITMAP hOrgBitmap = GetCurrentObject(this._handle, OBJ_BITMAP);
714             GetObjectW(hOrgBitmap, BITMAP.sizeof, &bmp);
715 
716             assert(bmp.bmWidth > 0 && bmp.bmHeight > 0, "Bitmap zero size");
717             r = Rect(0, 0, bmp.bmWidth, bmp.bmHeight);
718          }
719 
720          HBITMAP hBitmap = CreateCompatibleBitmap(this._handle, r.width, r.height);
721          c._hBitmap = hBitmap;
722          SelectObject(hdc, hBitmap); // Destroyed by Mem Canvas Object
723       } else {
724          SelectObject(hdc, b.handle); // This bitmap is not destroyed because the Bitmap object own his HBITMAP
725       }
726 
727       return c;
728    }
729 
730    public final Canvas createInMemory() {
731       return this.createInMemory(null);
732    }
733 
734    public static Canvas fromHDC(HDC hdc, bool owned = true) {
735       return new Canvas(hdc, owned, CanvasType.fromControl);
736    }
737 }
738 
739 abstract class GraphicObject : Handle!(HGDIOBJ), IDisposable {
740    protected bool _owned;
741 
742    protected this() {
743 
744    }
745 
746    protected this(HGDIOBJ hGdiObj, bool owned) {
747       this._handle = hGdiObj;
748       this._owned = owned;
749    }
750 
751    public ~this() {
752       this.dispose();
753    }
754 
755    protected static int getInfo(T)(HGDIOBJ hGdiObj, ref T t) {
756       return GetObjectW(hGdiObj, T.sizeof, &t);
757    }
758 
759    public void dispose() {
760       if (this._handle && this._owned) {
761          DeleteObject(this._handle);
762          this._handle = null;
763       }
764    }
765 }
766 
767 abstract class Image : GraphicObject {
768    protected this() {
769 
770    }
771 
772    @property public abstract Size size();
773    @property public abstract ImageType type();
774 
775    protected this(HGDIOBJ hGdiObj, bool owned) {
776       super(hGdiObj, owned);
777    }
778 }
779 
780 class Bitmap : Image {
781    public this(Size sz) {
782       HBITMAP hBitmap = this.createBitmap(sz.width, sz.height, RGB(0xFF, 0xFF, 0xFF));
783       super(hBitmap, true);
784    }
785 
786    public this(Size sz, Color bc) {
787       HBITMAP hBitmap = this.createBitmap(sz.width, sz.height, bc.colorref);
788       super(hBitmap, true);
789    }
790 
791    public this(int w, int h) {
792       HBITMAP hBitmap = this.createBitmap(w, h, RGB(0xFF, 0xFF, 0xFF));
793       super(hBitmap, true);
794    }
795 
796    public this(int w, int h, Color bc) {
797       HBITMAP hBitmap = this.createBitmap(w, h, bc.colorref);
798       super(hBitmap, true);
799    }
800 
801    protected this(HBITMAP hBitmap, bool owned) {
802       super(hBitmap, owned);
803    }
804 
805    protected this(string fileName) {
806       HBITMAP hBitmap = loadImage(null, fileName, IMAGE_BITMAP, 0, 0,
807             LR_DEFAULTCOLOR | LR_DEFAULTSIZE | LR_LOADFROMFILE);
808 
809       if (!hBitmap) {
810          throwException!(Win32Exception)("Cannot load Bitmap From File: '%s'", fileName);
811       }
812 
813       super(hBitmap, true);
814    }
815 
816    private static HBITMAP createBitmap(int w, int h, COLORREF backColor) {
817       Rect r = Rect(0, 0, w, h);
818 
819       HDC hdc = GetWindowDC(null);
820       HDC hcdc = CreateCompatibleDC(hdc);
821       HBITMAP hBitmap = CreateCompatibleBitmap(hdc, w, h);
822       HBITMAP hOldBitmap = SelectObject(hcdc, hBitmap);
823 
824       HBRUSH hBrush = CreateSolidBrush(backColor);
825       FillRect(hcdc, &r.rect, hBrush);
826       DeleteObject(hBrush);
827 
828       SelectObject(hcdc, hOldBitmap);
829       DeleteDC(hcdc);
830       ReleaseDC(null, hdc);
831 
832       return hBitmap;
833    }
834 
835    /*
836 	 *  !!! Is this procedure useful? !!!
837 	 *
838 	public Bitmap alphaBlend(ubyte alpha)
839 	{
840 		if(!_gdiAlphaBlend)
841 		{
842 			_gdiAlphaBlend = cast(GdiAlphaBlendProc)GetProcAddress(getModuleHandle("gdi32.dll"), toStringz("GdiAlphaBlend"));
843 		}
844 
845 		BITMAP b;
846 		getInfo!(BITMAP)(this._handle, b);
847 
848 		HDC hdc = GetWindowDC(null);
849 		HDC hdc1 = CreateCompatibleDC(hdc);
850 		HDC hdc2 = CreateCompatibleDC(hdc);
851 		HBITMAP hBitmap = CreateCompatibleBitmap(hdc, b.bmWidth, b.bmHeight);
852 		HBITMAP hOldBitmap1 = SelectObject(hdc1, hBitmap);
853 		HBITMAP hOldBitmap2 = SelectObject(hdc2, this._handle);
854 
855 		BLENDFUNCTION bf;
856 		bf.BlendOp = 0; // AC_SRC_OVER
857 		bf.SourceConstantAlpha = alpha;
858 
859 		if(b.bmBitsPixel == 32) // Premultiply bits if Bitmap's bpp = 32bpp
860 		{
861 			BitmapData bd;
862 			Bitmap.getData(hBitmap, bd);
863 
864 			for(int i = 0; i < bd.bitsCount; i++)
865 			{
866 				bd.bits[i].red = cast(ubyte)(bd.bits[i].red * (alpha / 0xFF));
867 				bd.bits[i].green = cast(ubyte)(bd.bits[i].green * (alpha / 0xFF));
868 				bd.bits[i].blue = cast(ubyte)(bd.bits[i].blue * (alpha / 0xFF));
869 			}
870 
871 			Bitmap.setData(hBitmap, bd);
872 
873 			bf.AlphaFormat = 1; // AC_SRC_ALPHA
874 		}
875 
876 		_gdiAlphaBlend(hdc1, 0, 0, b.bmWidth, b.bmHeight, hdc2, 0, 0, b.bmWidth, b.bmHeight, bf);
877 
878 		SelectObject(hdc2, hOldBitmap2);
879 		SelectObject(hdc1, hOldBitmap1);
880 		DeleteDC(hdc2);
881 		DeleteDC(hdc1);
882 		ReleaseDC(null, hdc);
883 
884 		return Bitmap.fromHBITMAP(hBitmap);
885 	}
886 	*/
887 
888    public Bitmap clone() {
889       BITMAP b;
890       getInfo!(BITMAP)(this._handle, b);
891 
892       HDC hdc = GetDC(null);
893       HDC hcdc1 = CreateCompatibleDC(hdc); // Contains this bitmap
894       HDC hcdc2 = CreateCompatibleDC(hdc); // The Bitmap will be copied here
895       HBITMAP hBitmap = CreateCompatibleBitmap(hdc, b.bmWidth, b.bmHeight); //Don't delete it, it will be deleted by the class Bitmap
896 
897       HBITMAP hOldBitmap1 = SelectObject(hcdc1, this._handle);
898       HBITMAP hOldBitmap2 = SelectObject(hcdc2, hBitmap);
899 
900       BitBlt(hcdc2, 0, 0, b.bmWidth, b.bmHeight, hcdc1, 0, 0, SRCCOPY);
901       SelectObject(hcdc2, hOldBitmap2);
902       SelectObject(hcdc1, hOldBitmap1);
903 
904       DeleteDC(hcdc2);
905       DeleteDC(hcdc1);
906       ReleaseDC(null, hdc);
907 
908       Bitmap bmp = new Bitmap(hBitmap, true);
909       return bmp;
910    }
911 
912    public static void getData(HBITMAP hBitmap, ref BitmapData bd) {
913       BITMAPINFO bi;
914       bi.bmiHeader.biSize = BITMAPINFOHEADER.sizeof;
915       bi.bmiHeader.biBitCount = 0;
916 
917       HDC hdc = GetWindowDC(null);
918       GetDIBits(hdc, hBitmap, 0, 0, null, &bi, DIB_RGB_COLORS); // Get Bitmap Info
919 
920       bd.imageSize = bi.bmiHeader.biSizeImage;
921       bd.bitsCount = bi.bmiHeader.biSizeImage / RGBQUAD.sizeof;
922       bd.bits = cast(BitmapBit*)GC.malloc(bi.bmiHeader.biSizeImage);
923 
924       switch (bi.bmiHeader.biBitCount) // Calculate color table size (if needed)
925       {
926       case 24:
927          bd.info = cast(BITMAPINFO*)GC.malloc(bi.bmiHeader.biSize);
928          break;
929 
930       case 16, 32:
931          bd.info = cast(BITMAPINFO*)GC.malloc(bi.bmiHeader.biSize + uint.sizeof * 3); // Needs Investigation
932          break;
933 
934       default:
935          bd.info = cast(BITMAPINFO*)GC.malloc(
936                bi.bmiHeader.biSize + RGBQUAD.sizeof * (1 << bi.bmiHeader.biBitCount));
937          break;
938       }
939 
940       bd.info.bmiHeader = bi.bmiHeader;
941       GetDIBits(hdc, hBitmap, 0, bd.info.bmiHeader.biHeight,
942             cast(RGBQUAD*)bd.bits, bd.info, DIB_RGB_COLORS);
943       ReleaseDC(null, hdc);
944    }
945 
946    public void getData(ref BitmapData bd) {
947       return Bitmap.getData(this._handle, bd);
948    }
949 
950    private static void setData(HBITMAP hBitmap, ref BitmapData bd) {
951       HDC hdc = GetWindowDC(null);
952       SetDIBits(hdc, hBitmap, 0, bd.info.bmiHeader.biHeight,
953             cast(RGBQUAD*)bd.bits, bd.info, DIB_RGB_COLORS);
954 
955       ReleaseDC(null, hdc);
956       Bitmap.freeData(bd);
957    }
958 
959    public void setData(ref BitmapData bd) {
960       Bitmap.setData(this._handle, bd);
961    }
962 
963    public static void freeData(ref BitmapData bd) {
964       GC.free(bd.bits);
965       GC.free(bd.info);
966    }
967 
968    @property public override Size size() {
969       BITMAP bmp = void; //Inizializzata da getInfo()
970 
971       getInfo!(BITMAP)(this._handle, bmp);
972       return Size(bmp.bmWidth, bmp.bmHeight);
973    }
974 
975    @property public override ImageType type() {
976       return ImageType.bitmap;
977    }
978 
979    public static Bitmap fromHBITMAP(HBITMAP hBitmap, bool owned = true) {
980       return new Bitmap(hBitmap, owned);
981    }
982 
983    public static Bitmap fromFile(string fileName) {
984       return new Bitmap(fileName);
985    }
986 }
987 
988 class Icon : Image {
989    protected this(HICON hIcon, bool owned) {
990       super(hIcon, owned);
991    }
992 
993    protected this(string fileName) {
994       HICON hIcon;
995 
996       if (!icmp(std.path.extension(fileName), ".ico")) {
997          hIcon = loadImage(null, fileName, IMAGE_ICON, 0, 0,
998                LR_DEFAULTCOLOR | LR_DEFAULTSIZE | LR_LOADFROMFILE);
999       } else {
1000          ushort dummy = 0;
1001          hIcon = extractAssociatedIcon(fileName, &dummy);
1002       }
1003 
1004       if (!hIcon) {
1005          throwException!(Win32Exception)("Cannot load Icon From File: '%s'", fileName);
1006       }
1007 
1008       super(hIcon, true);
1009    }
1010 
1011    public override void dispose() {
1012       if (this._handle && this._owned) {
1013          DestroyIcon(this._handle); // Use DestroyIcon() not DestroyObject()
1014       }
1015    }
1016 
1017    @property public override Size size() {
1018       ICONINFO ii = void; //Inizializzata da GetIconInfo()
1019       BITMAP bmp = void; //Inizializzata da getInfo()
1020       Size sz = void; //Inizializzata sotto.
1021 
1022       if (!GetIconInfo(this._handle, &ii)) {
1023          throwException!(Win32Exception)("Unable to get information from Icon");
1024       }
1025 
1026       if (ii.hbmColor) //Exists: Icon Color Bitmap
1027       {
1028          if (!getInfo!(BITMAP)(ii.hbmColor, bmp)) {
1029             throwException!(Win32Exception)("Unable to get Icon Color Bitmap");
1030          }
1031 
1032          sz.width = bmp.bmWidth;
1033          sz.height = bmp.bmHeight;
1034          DeleteObject(ii.hbmColor);
1035       } else {
1036          if (!getInfo!(BITMAP)(ii.hbmMask, bmp)) {
1037             throwException!(Win32Exception)("Unable to get Icon Mask");
1038          }
1039 
1040          sz.width = bmp.bmWidth;
1041          sz.height = bmp.bmHeight / 2;
1042       }
1043 
1044       DeleteObject(ii.hbmMask);
1045       return sz;
1046    }
1047 
1048    @property public override ImageType type() {
1049       return ImageType.iconOrCursor;
1050    }
1051 
1052    public Bitmap toBitmap(Size sz) {
1053       HDC hwdc = GetWindowDC(null);
1054       HDC hdc1 = CreateCompatibleDC(hwdc);
1055 
1056       HBITMAP hBitmap = CreateCompatibleBitmap(hwdc, sz.width, sz.height);
1057       HBITMAP hOldBitmap = SelectObject(hdc1, hBitmap);
1058 
1059       Rect r = Rect(nullPoint, sz);
1060       HBRUSH hBrush = CreateSolidBrush(RGB(255, 255, 255));
1061       FillRect(hdc1, &r.rect, hBrush);
1062       DeleteObject(hBrush);
1063 
1064       DrawIconEx(hdc1, 0, 0, this._handle, sz.width, sz.height, 0, null, DI_NORMAL);
1065       SelectObject(hdc1, hOldBitmap);
1066       DeleteDC(hdc1);
1067       ReleaseDC(null, hwdc);
1068 
1069       return Bitmap.fromHBITMAP(hBitmap);
1070    }
1071 
1072    public Bitmap toBitmap() {
1073       Size sz = this.size;
1074       return this.toBitmap(sz);
1075    }
1076 
1077    public static Icon fromHICON(HICON hIcon, bool owned = true) {
1078       return new Icon(hIcon, owned);
1079    }
1080 
1081    public static Icon fromFile(string fileName) {
1082       return new Icon(fileName);
1083    }
1084 }
1085 
1086 final class Cursor : Icon {
1087    protected this(HCURSOR hCursor, bool owned) {
1088       super(hCursor, owned);
1089    }
1090 
1091    public override void dispose() {
1092       if (this._handle && this._owned) {
1093          DestroyCursor(this._handle); // Use DestroyCursor() not DestroyObject()
1094       }
1095    }
1096 
1097    @property public static Point position() {
1098       Point pt;
1099 
1100       GetCursorPos(&pt.point);
1101       return pt;
1102    }
1103 
1104    public static Cursor fromHCURSOR(HCURSOR hCursor, bool owned = true) {
1105       return new Cursor(hCursor, owned);
1106    }
1107 }
1108 
1109 final class Font : GraphicObject {
1110    private static int _logPixelSY = 0;
1111 
1112    private bool _metricsDone = false;
1113    private FontMetrics _metrics;
1114 
1115    private this(HFONT hFont, bool owned) {
1116       super(hFont, owned);
1117    }
1118 
1119    private static void initLogPixelSY() {
1120       if (!_logPixelSY) {
1121          HDC hdc = GetWindowDC(null);
1122          _logPixelSY = GetDeviceCaps(hdc, LOGPIXELSY);
1123          ReleaseDC(null, hdc);
1124       }
1125    }
1126 
1127    public this(string name, int h, FontStyle style = FontStyle.normal) {
1128       Font.initLogPixelSY();
1129 
1130       LOGFONTW lf;
1131       lf.lfHeight = -MulDiv(h, _logPixelSY, 72);
1132 
1133       doStyle(style, lf);
1134       this._handle = createFontIndirect(name, &lf);
1135    }
1136 
1137    public this(Font f, FontStyle fs) {
1138       LOGFONTW lf;
1139 
1140       getInfo!(LOGFONTW)(f.handle, lf);
1141       doStyle(fs, lf);
1142       this._handle = createFontIndirect(&lf);
1143    }
1144 
1145    @property public string name() {
1146       LOGFONTW lf;
1147 
1148       getInfo!(LOGFONTW)(this._handle, lf);
1149       int idx = indexOf(lf.lfFaceName, '\0');
1150       return to!(string)(lf.lfFaceName[0 .. idx]);
1151    }
1152 
1153    @property public int height() {
1154       LOGFONTW lf;
1155 
1156       Font.initLogPixelSY();
1157 
1158       getInfo!(LOGFONTW)(this._handle, lf);
1159       return -MulDiv(72, lf.lfHeight, _logPixelSY);
1160    }
1161 
1162    @property public FontMetrics metrics() {
1163       if (!this._metricsDone) {
1164          TEXTMETRICW tm;
1165 
1166          HDC hdc = CreateCompatibleDC(null);
1167          HFONT hOldFont = SelectObject(hdc, this._handle);
1168          GetTextMetricsW(hdc, &tm);
1169          SelectObject(hdc, hOldFont);
1170          DeleteDC(hdc);
1171 
1172          this._metrics.height = tm.tmHeight;
1173          this._metrics.ascent = tm.tmAscent;
1174          this._metrics.descent = tm.tmDescent;
1175          this._metrics.internalLeading = tm.tmInternalLeading;
1176          this._metrics.externalLeading = tm.tmExternalLeading;
1177          this._metrics.averageCharWidth = tm.tmAveCharWidth;
1178          this._metrics.maxCharWidth = tm.tmMaxCharWidth;
1179 
1180          this._metricsDone = true;
1181       }
1182 
1183       return this._metrics;
1184    }
1185 
1186    private static void doStyle(FontStyle style, ref LOGFONTW lf) {
1187       lf.lfCharSet = DEFAULT_CHARSET;
1188       lf.lfWeight = FW_NORMAL;
1189       //lf.lfItalic = FALSE;    Inizializzata dal compilatore
1190       //lf.lfStrikeOut = FALSE; Inizializzata dal compilatore
1191       //lf.lfUnderline = FALSE; Inizializzata dal compilatore
1192 
1193       if (style & FontStyle.bold) {
1194          lf.lfWeight = FW_BOLD;
1195       }
1196 
1197       if (style & FontStyle.italic) {
1198          lf.lfItalic = 1;
1199       }
1200 
1201       if (style & FontStyle.strikeout) {
1202          lf.lfStrikeOut = 1;
1203       }
1204 
1205       if (style & FontStyle.underline) {
1206          lf.lfUnderline = 1;
1207       }
1208    }
1209 
1210    public static Font fromHFONT(HFONT hFont, bool owned = true) {
1211       return new Font(hFont, owned);
1212    }
1213 }
1214 
1215 abstract class Brush : GraphicObject {
1216    protected this(HBRUSH hBrush, bool owned) {
1217       super(hBrush, owned);
1218    }
1219 }
1220 
1221 class SolidBrush : Brush {
1222    private Color _color;
1223 
1224    protected this(HBRUSH hBrush, bool owned) {
1225       super(hBrush, owned);
1226    }
1227 
1228    public this(Color color) {
1229       this._color = color;
1230       super(CreateSolidBrush(color.colorref), true);
1231    }
1232 
1233    @property public final Color color() {
1234       return this._color;
1235    }
1236 
1237    public static SolidBrush fromHBRUSH(HBRUSH hBrush, bool owned = true) {
1238       return new SolidBrush(hBrush, owned);
1239    }
1240 }
1241 
1242 class HatchBrush : Brush {
1243    private Color _color;
1244    private HatchStyle _style;
1245 
1246    protected this(HBRUSH hBrush, bool owned) {
1247       super(hBrush, owned);
1248    }
1249 
1250    public this(Color color, HatchStyle style) {
1251       this._color = color;
1252       this._style = style;
1253 
1254       super(CreateHatchBrush(style, color.colorref), true);
1255    }
1256 
1257    @property public final Color color() {
1258       return this._color;
1259    }
1260 
1261    @property public final HatchStyle style() {
1262       return this._style;
1263    }
1264 
1265    public static HatchBrush fromHBRUSH(HBRUSH hBrush, bool owned = true) {
1266       return new HatchBrush(hBrush, owned);
1267    }
1268 }
1269 
1270 class PatternBrush : Brush {
1271    private Bitmap _bmp;
1272 
1273    protected this(HBRUSH hBrush, bool owned) {
1274       super(hBrush, owned);
1275    }
1276 
1277    public this(Bitmap bmp) {
1278       this._bmp = bmp;
1279       super(CreatePatternBrush(bmp.handle), true);
1280    }
1281 
1282    @property public final Bitmap bitmap() {
1283       return this._bmp;
1284    }
1285 
1286    public static PatternBrush fromHBRUSH(HBRUSH hBrush, bool owned = true) {
1287       return new PatternBrush(hBrush, owned);
1288    }
1289 }
1290 
1291 final class Pen : GraphicObject {
1292    private PenStyle _style;
1293    private Color _color;
1294    private int _width;
1295 
1296    protected this(HPEN hPen, bool owned) {
1297       super(hPen, owned);
1298    }
1299 
1300    public this(Color color, int width = 1, PenStyle style = PenStyle.solid) {
1301       this._color = color;
1302       this._width = width;
1303       this._style = style;
1304 
1305       this._handle = CreatePen(style, width, color.colorref);
1306 
1307       super(this._handle, true);
1308    }
1309 
1310    @property public PenStyle style() {
1311       return this._style;
1312    }
1313 
1314    @property public int width() {
1315       return this._width;
1316    }
1317 
1318    @property public Color color() {
1319       return this._color;
1320    }
1321 
1322    public static Pen fromHPEN(HPEN hPen, bool owned = true) {
1323       return new Pen(hPen, owned);
1324    }
1325 }
1326 
1327 final class SystemPens {
1328    @property public static Pen nullPen() {
1329       return Pen.fromHPEN(GetStockObject(NULL_PEN), false);
1330    }
1331 
1332    @property public static Pen blackPen() {
1333       return Pen.fromHPEN(GetStockObject(BLACK_PEN), false);
1334    }
1335 
1336    @property public static Pen whitePen() {
1337       return Pen.fromHPEN(GetStockObject(WHITE_PEN), false);
1338    }
1339 }
1340 
1341 final class SystemIcons {
1342    @property public static Icon application() {
1343       static Icon ico;
1344 
1345       if (!ico) {
1346          HICON hIco = loadImage(null, cast(wchar*)IDI_APPLICATION, IMAGE_ICON,
1347                0, 0, LR_SHARED | LR_DEFAULTCOLOR | LR_DEFAULTSIZE);
1348          ico = Icon.fromHICON(hIco);
1349       }
1350 
1351       return ico;
1352    }
1353 
1354    @property public static Icon asterisk() {
1355       static Icon ico;
1356 
1357       if (!ico) {
1358          HICON hIco = loadImage(null, IDI_ASTERISK, IMAGE_ICON, 0, 0,
1359                LR_SHARED | LR_DEFAULTCOLOR | LR_DEFAULTSIZE);
1360          ico = Icon.fromHICON(hIco);
1361       }
1362 
1363       return ico;
1364    }
1365 
1366    @property public static Icon error() {
1367       static Icon ico;
1368 
1369       if (!ico) {
1370          HICON hIco = loadImage(null, IDI_ERROR, IMAGE_ICON, 0, 0,
1371                LR_SHARED | LR_DEFAULTCOLOR | LR_DEFAULTSIZE);
1372          ico = Icon.fromHICON(hIco);
1373       }
1374 
1375       return ico;
1376    }
1377 
1378    @property public static Icon question() {
1379       static Icon ico;
1380 
1381       if (!ico) {
1382          HICON hIco = loadImage(null, IDI_QUESTION, IMAGE_ICON, 0, 0,
1383                LR_SHARED | LR_DEFAULTCOLOR | LR_DEFAULTSIZE);
1384          ico = Icon.fromHICON(hIco);
1385       }
1386 
1387       return ico;
1388    }
1389 
1390    @property public static Icon warning() {
1391       static Icon ico;
1392 
1393       if (!ico) {
1394          HICON hIco = loadImage(null, IDI_WARNING, IMAGE_ICON, 0, 0,
1395                LR_SHARED | LR_DEFAULTCOLOR | LR_DEFAULTSIZE);
1396          ico = Icon.fromHICON(hIco);
1397       }
1398 
1399       return ico;
1400    }
1401 }
1402 
1403 final class SystemBrushes {
1404    @property public static SolidBrush blackBrush() {
1405       return SolidBrush.fromHBRUSH(GetStockObject(BLACK_BRUSH), false);
1406    }
1407 
1408    @property public static SolidBrush darkGrayBrush() {
1409       return SolidBrush.fromHBRUSH(GetStockObject(DKGRAY_BRUSH), false);
1410    }
1411 
1412    @property public static SolidBrush grayBrush() {
1413       return SolidBrush.fromHBRUSH(GetStockObject(GRAY_BRUSH), false);
1414    }
1415 
1416    @property public static SolidBrush lightGrayBrush() {
1417       return SolidBrush.fromHBRUSH(GetStockObject(LTGRAY_BRUSH), false);
1418    }
1419 
1420    @property public static SolidBrush nullBrush() {
1421       return SolidBrush.fromHBRUSH(GetStockObject(NULL_BRUSH), false);
1422    }
1423 
1424    @property public static SolidBrush whiteBrush() {
1425       return SolidBrush.fromHBRUSH(GetStockObject(WHITE_BRUSH), false);
1426    }
1427 
1428    @property public static SolidBrush brush3DDarkShadow() {
1429       return SolidBrush.fromHBRUSH(GetSysColorBrush(COLOR_3DDKSHADOW), false);
1430    }
1431 
1432    @property public static SolidBrush brush3DFace() {
1433       return SolidBrush.fromHBRUSH(GetSysColorBrush(COLOR_3DFACE), false);
1434    }
1435 
1436    @property public static SolidBrush brushButtonFace() {
1437       return SolidBrush.fromHBRUSH(GetSysColorBrush(COLOR_BTNFACE), false);
1438    }
1439 
1440    @property public static SolidBrush brush3DLight() {
1441       return SolidBrush.fromHBRUSH(GetSysColorBrush(COLOR_3DLIGHT), false);
1442    }
1443 
1444    @property public static SolidBrush brush3DShadow() {
1445       return SolidBrush.fromHBRUSH(GetSysColorBrush(COLOR_3DSHADOW), false);
1446    }
1447 
1448    @property public static SolidBrush brushActiveBorder() {
1449       return SolidBrush.fromHBRUSH(GetSysColorBrush(COLOR_ACTIVEBORDER), false);
1450    }
1451 
1452    @property public static SolidBrush brushActiveCaption() {
1453       return SolidBrush.fromHBRUSH(GetSysColorBrush(COLOR_3DLIGHT), false);
1454    }
1455 
1456    @property public static SolidBrush brushAppWorkspace() {
1457       return SolidBrush.fromHBRUSH(GetSysColorBrush(COLOR_APPWORKSPACE), false);
1458    }
1459 
1460    @property public static SolidBrush brushBackground() {
1461       return SolidBrush.fromHBRUSH(GetSysColorBrush(COLOR_BACKGROUND), false);
1462    }
1463 
1464    @property public static SolidBrush brushButtonText() {
1465       return SolidBrush.fromHBRUSH(GetSysColorBrush(COLOR_BTNTEXT), false);
1466    }
1467 
1468    @property public static SolidBrush brushCaptionText() {
1469       return SolidBrush.fromHBRUSH(GetSysColorBrush(COLOR_CAPTIONTEXT), false);
1470    }
1471 
1472    @property public static SolidBrush brushGrayText() {
1473       return SolidBrush.fromHBRUSH(GetSysColorBrush(COLOR_GRAYTEXT), false);
1474    }
1475 
1476    @property public static SolidBrush brushHighlight() {
1477       return SolidBrush.fromHBRUSH(GetSysColorBrush(COLOR_HIGHLIGHT), false);
1478    }
1479 
1480    @property public static SolidBrush brushHighlightText() {
1481       return SolidBrush.fromHBRUSH(GetSysColorBrush(COLOR_HIGHLIGHTTEXT), false);
1482    }
1483 
1484    @property public static SolidBrush brushInactiveBorder() {
1485       return SolidBrush.fromHBRUSH(GetSysColorBrush(COLOR_INACTIVEBORDER), false);
1486    }
1487 
1488    @property public static SolidBrush brushInactiveCaption() {
1489       return SolidBrush.fromHBRUSH(GetSysColorBrush(COLOR_INACTIVECAPTION), false);
1490    }
1491 
1492    @property public static SolidBrush brushInactiveCaptionText() {
1493       return SolidBrush.fromHBRUSH(GetSysColorBrush(COLOR_INACTIVECAPTIONTEXT), false);
1494    }
1495 
1496    @property public static SolidBrush brushInfo() {
1497       return SolidBrush.fromHBRUSH(GetSysColorBrush(COLOR_INFOBK), false);
1498    }
1499 
1500    @property public static SolidBrush brushInfoText() {
1501       return SolidBrush.fromHBRUSH(GetSysColorBrush(COLOR_INFOTEXT), false);
1502    }
1503 
1504    @property public static SolidBrush brushMenu() {
1505       return SolidBrush.fromHBRUSH(GetSysColorBrush(COLOR_MENU), false);
1506    }
1507 
1508    @property public static SolidBrush brushMenuText() {
1509       return SolidBrush.fromHBRUSH(GetSysColorBrush(COLOR_MENUTEXT), false);
1510    }
1511 
1512    @property public static SolidBrush brushScrollBar() {
1513       return SolidBrush.fromHBRUSH(GetSysColorBrush(COLOR_SCROLLBAR), false);
1514    }
1515 
1516    @property public static SolidBrush brushWindow() {
1517       return SolidBrush.fromHBRUSH(GetSysColorBrush(COLOR_WINDOW), false);
1518    }
1519 
1520    @property public static SolidBrush brushWindowFrame() {
1521       return SolidBrush.fromHBRUSH(GetSysColorBrush(COLOR_WINDOW), false);
1522    }
1523 
1524    @property public static SolidBrush brushWindowText() {
1525       return SolidBrush.fromHBRUSH(GetSysColorBrush(COLOR_WINDOWTEXT), false);
1526    }
1527 }
1528 
1529 final class SystemFonts {
1530    @property public static Font windowsFont() {
1531       static Font f;
1532 
1533       if (!f) {
1534          NONCLIENTMETRICSW ncm = void; //La inizializza sotto.
1535          ncm.cbSize = NONCLIENTMETRICSW.sizeof;
1536 
1537          if (SystemParametersInfoW(SPI_GETNONCLIENTMETRICS, NONCLIENTMETRICSW.sizeof, &ncm, 0)) {
1538             f = Font.fromHFONT(createFontIndirect(&ncm.lfMessageFont), false);
1539          } else {
1540             f = SystemFonts.ansiVarFont;
1541          }
1542       }
1543 
1544       return f;
1545    }
1546 
1547    @property public static Font ansiFixedFont() {
1548       static Font f;
1549 
1550       if (!f) {
1551          f = Font.fromHFONT(GetStockObject(ANSI_FIXED_FONT), false);
1552       }
1553 
1554       return f;
1555    }
1556 
1557    @property public static Font ansiVarFont() {
1558       static Font f;
1559 
1560       if (!f) {
1561          f = Font.fromHFONT(GetStockObject(ANSI_VAR_FONT), false);
1562       }
1563 
1564       return f;
1565    }
1566 
1567    @property public static Font deviceDefaultFont() {
1568       static Font f;
1569 
1570       if (!f) {
1571          f = Font.fromHFONT(GetStockObject(DEVICE_DEFAULT_FONT), false);
1572       }
1573 
1574       return f;
1575    }
1576 
1577    @property public static Font oemFixedFont() {
1578       static Font f;
1579 
1580       if (!f) {
1581          f = Font.fromHFONT(GetStockObject(OEM_FIXED_FONT), false);
1582       }
1583 
1584       return f;
1585    }
1586 
1587    @property public static Font systemFont() {
1588       static Font f;
1589 
1590       if (!f) {
1591          f = Font.fromHFONT(GetStockObject(SYSTEM_FONT), false);
1592       }
1593 
1594       return f;
1595    }
1596 
1597    @property public static Font systemFixedFont() {
1598       static Font f;
1599 
1600       if (!f) {
1601          f = Font.fromHFONT(GetStockObject(SYSTEM_FIXED_FONT), false);
1602       }
1603 
1604       return f;
1605    }
1606 }
1607 
1608 final class SystemCursors {
1609    @property public static Cursor appStarting() {
1610       static Cursor c;
1611 
1612       if (!c) {
1613          c = Cursor.fromHCURSOR(loadImage(getHInstance(), IDC_APPSTARTING,
1614                IMAGE_CURSOR, 0, 0, LR_DEFAULTSIZE | LR_DEFAULTCOLOR | LR_SHARED), false);
1615       }
1616 
1617       return c;
1618    }
1619 
1620    @property public static Cursor arrow() {
1621       static Cursor c;
1622 
1623       if (!c) {
1624          c = Cursor.fromHCURSOR(loadImage(null, IDC_ARROW, IMAGE_CURSOR, 0, 0,
1625                LR_DEFAULTSIZE | LR_DEFAULTCOLOR | LR_SHARED), false);
1626       }
1627 
1628       return c;
1629    }
1630 
1631    @property public static Cursor cross() {
1632       static Cursor c;
1633 
1634       if (!c) {
1635          c = Cursor.fromHCURSOR(loadImage(null, cast(wchar*)IDC_CROSS,
1636                IMAGE_CURSOR, 0, 0, LR_DEFAULTSIZE | LR_DEFAULTCOLOR | LR_SHARED), false);
1637       }
1638 
1639       return c;
1640    }
1641 
1642    @property public static Cursor iBeam() {
1643       static Cursor c;
1644 
1645       if (!c) {
1646          c = Cursor.fromHCURSOR(loadImage(null, IDC_IBEAM, IMAGE_CURSOR, 0, 0,
1647                LR_DEFAULTSIZE | LR_DEFAULTCOLOR | LR_SHARED), false);
1648       }
1649 
1650       return c;
1651    }
1652 
1653    @property public static Cursor icon() {
1654       static Cursor c;
1655 
1656       if (!c) {
1657          c = Cursor.fromHCURSOR(loadImage(null, IDC_ICON, IMAGE_CURSOR, 0, 0,
1658                LR_DEFAULTSIZE | LR_DEFAULTCOLOR | LR_SHARED), false);
1659       }
1660 
1661       return c;
1662    }
1663 
1664    @property public static Cursor no() {
1665       static Cursor c;
1666 
1667       if (!c) {
1668          c = Cursor.fromHCURSOR(loadImage(null, IDC_NO, IMAGE_CURSOR, 0, 0,
1669                LR_DEFAULTSIZE | LR_DEFAULTCOLOR | LR_SHARED), false);
1670       }
1671 
1672       return c;
1673    }
1674 
1675    @property public static Cursor sizeAll() {
1676       static Cursor c;
1677 
1678       if (!c) {
1679          c = Cursor.fromHCURSOR(loadImage(null, IDC_SIZEALL, IMAGE_CURSOR, 0,
1680                0, LR_DEFAULTSIZE | LR_DEFAULTCOLOR | LR_SHARED), false);
1681       }
1682 
1683       return c;
1684    }
1685 
1686    @property public static Cursor sizeNESW() {
1687       static Cursor c;
1688 
1689       if (!c) {
1690          c = Cursor.fromHCURSOR(loadImage(null, IDC_SIZENESW, IMAGE_CURSOR, 0,
1691                0, LR_DEFAULTSIZE | LR_DEFAULTCOLOR | LR_SHARED), false);
1692       }
1693 
1694       return c;
1695    }
1696 
1697    @property public static Cursor sizeNS() {
1698       static Cursor c;
1699 
1700       if (!c) {
1701          c = Cursor.fromHCURSOR(loadImage(null, IDC_SIZENS, IMAGE_CURSOR, 0, 0,
1702                LR_DEFAULTSIZE | LR_DEFAULTCOLOR | LR_SHARED), false);
1703       }
1704 
1705       return c;
1706    }
1707 
1708    @property public static Cursor sizeNWSE() {
1709       static Cursor c;
1710 
1711       if (!c) {
1712          c = Cursor.fromHCURSOR(loadImage(null, IDC_SIZENWSE, IMAGE_CURSOR, 0,
1713                0, LR_DEFAULTSIZE | LR_DEFAULTCOLOR | LR_SHARED), false);
1714       }
1715 
1716       return c;
1717    }
1718 
1719    @property public static Cursor sizeWE() {
1720       static Cursor c;
1721 
1722       if (!c) {
1723          c = Cursor.fromHCURSOR(loadImage(null, IDC_SIZEWE, IMAGE_CURSOR, 0, 0,
1724                LR_DEFAULTSIZE | LR_DEFAULTCOLOR | LR_SHARED), false);
1725       }
1726 
1727       return c;
1728    }
1729 
1730    @property public static Cursor upArrow() {
1731       static Cursor c;
1732 
1733       if (!c) {
1734          c = Cursor.fromHCURSOR(loadImage(null, IDC_UPARROW, IMAGE_CURSOR, 0,
1735                0, LR_DEFAULTSIZE | LR_DEFAULTCOLOR | LR_SHARED), false);
1736       }
1737 
1738       return c;
1739    }
1740 
1741    @property public static Cursor wait() {
1742       static Cursor c;
1743 
1744       if (!c) {
1745          c = Cursor.fromHCURSOR(loadImage(null, IDC_WAIT, IMAGE_CURSOR, 0, 0,
1746                LR_DEFAULTSIZE | LR_DEFAULTCOLOR | LR_SHARED), false);
1747       }
1748 
1749       return c;
1750    }
1751 }
1752 
1753 final class SystemColors {
1754    @property public static Color red() {
1755       return Color(0xFF, 0x00, 0x00);
1756    }
1757 
1758    @property public static Color green() {
1759       return Color(0x00, 0xFF, 0x00);
1760    }
1761 
1762    @property public static Color blue() {
1763       return Color(0x00, 0x00, 0xFF);
1764    }
1765 
1766    @property public static Color black() {
1767       return Color(0x00, 0x00, 0x00);
1768    }
1769 
1770    @property public static Color white() {
1771       return Color(0xFF, 0xFF, 0xFF);
1772    }
1773 
1774    @property public static Color yellow() {
1775       return Color(0xFF, 0xFF, 0x00);
1776    }
1777 
1778    @property public static Color magenta() {
1779       return Color(0xFF, 0x00, 0xFF);
1780    }
1781 
1782    @property public static Color magicPink() {
1783       return SystemColors.magenta; //Is 'Magic Pink'
1784    }
1785 
1786    @property public static Color cyan() {
1787       return Color(0x00, 0xFF, 0xFF);
1788    }
1789 
1790    @property public static Color darkGray() {
1791       return Color(0xA9, 0xA9, 0xA9);
1792    }
1793 
1794    @property public static Color lightGray() {
1795       return Color(0xD3, 0xD3, 0xD3);
1796    }
1797 
1798    @property public static Color darkRed() {
1799       return Color(0x8B, 0x00, 0x00);
1800    }
1801 
1802    @property public static Color darkGreen() {
1803       return Color(0x00, 0x64, 0x00);
1804    }
1805 
1806    @property public static Color darkBlue() {
1807       return Color(0x00, 0x00, 0x8B);
1808    }
1809 
1810    @property public static Color darkYellow() {
1811       return Color(0x00, 0x80, 0x80);
1812    }
1813 
1814    @property public static Color darkMagenta() {
1815       return Color(0x80, 0x00, 0x80);
1816    }
1817 
1818    @property public static Color darkCyan() {
1819       return Color(0x80, 0x80, 0x00);
1820    }
1821 
1822    @property public static Color transparent() {
1823       return Color(0x00, 0x00, 0x00, 0x00);
1824    }
1825 
1826    @property public static Color color3DDarkShadow() {
1827       return Color.fromCOLORREF(GetSysColor(COLOR_3DDKSHADOW));
1828    }
1829 
1830    @property public static Color color3DFace() {
1831       return Color.fromCOLORREF(GetSysColor(COLOR_3DFACE));
1832    }
1833 
1834    @property public static Color colorButtonFace() {
1835       return Color.fromCOLORREF(GetSysColor(COLOR_BTNFACE));
1836    }
1837 
1838    @property public static Color color3DLight() {
1839       return Color.fromCOLORREF(GetSysColor(COLOR_3DLIGHT));
1840    }
1841 
1842    @property public static Color color3DShadow() {
1843       return Color.fromCOLORREF(GetSysColor(COLOR_3DSHADOW));
1844    }
1845 
1846    @property public static Color colorActiveBorder() {
1847       return Color.fromCOLORREF(GetSysColor(COLOR_ACTIVEBORDER));
1848    }
1849 
1850    @property public static Color colorActiveCaption() {
1851       return Color.fromCOLORREF(GetSysColor(COLOR_3DLIGHT));
1852    }
1853 
1854    @property public static Color colorAppWorkspace() {
1855       return Color.fromCOLORREF(GetSysColor(COLOR_APPWORKSPACE));
1856    }
1857 
1858    @property public static Color colorBackground() {
1859       return Color.fromCOLORREF(GetSysColor(COLOR_BACKGROUND));
1860    }
1861 
1862    @property public static Color colorButtonText() {
1863       return Color.fromCOLORREF(GetSysColor(COLOR_BTNTEXT));
1864    }
1865 
1866    @property public static Color colorCaptionText() {
1867       return Color.fromCOLORREF(GetSysColor(COLOR_CAPTIONTEXT));
1868    }
1869 
1870    @property public static Color colorGrayText() {
1871       return Color.fromCOLORREF(GetSysColor(COLOR_GRAYTEXT));
1872    }
1873 
1874    @property public static Color colorHighlight() {
1875       return Color.fromCOLORREF(GetSysColor(COLOR_HIGHLIGHT));
1876    }
1877 
1878    @property public static Color colorHighlightText() {
1879       return Color.fromCOLORREF(GetSysColor(COLOR_HIGHLIGHTTEXT));
1880    }
1881 
1882    @property public static Color colorInactiveBorder() {
1883       return Color.fromCOLORREF(GetSysColor(COLOR_INACTIVEBORDER));
1884    }
1885 
1886    @property public static Color colorInactiveCaption() {
1887       return Color.fromCOLORREF(GetSysColor(COLOR_INACTIVECAPTION));
1888    }
1889 
1890    @property public static Color colorInactiveCaptionText() {
1891       return Color.fromCOLORREF(GetSysColor(COLOR_INACTIVECAPTIONTEXT));
1892    }
1893 
1894    @property public static Color colorInfo() {
1895       return Color.fromCOLORREF(GetSysColor(COLOR_INFOBK));
1896    }
1897 
1898    @property public static Color colorInfoText() {
1899       return Color.fromCOLORREF(GetSysColor(COLOR_INFOTEXT));
1900    }
1901 
1902    @property public static Color colorMenu() {
1903       return Color.fromCOLORREF(GetSysColor(COLOR_MENU));
1904    }
1905 
1906    @property public static Color colorMenuText() {
1907       return Color.fromCOLORREF(GetSysColor(COLOR_MENUTEXT));
1908    }
1909 
1910    @property public static Color colorScrollBar() {
1911       return Color.fromCOLORREF(GetSysColor(COLOR_SCROLLBAR));
1912    }
1913 
1914    @property public static Color colorWindow() {
1915       return Color.fromCOLORREF(GetSysColor(COLOR_WINDOW));
1916    }
1917 
1918    @property public static Color colorWindowFrame() {
1919       return Color.fromCOLORREF(GetSysColor(COLOR_WINDOW));
1920    }
1921 
1922    @property public static Color colorWindowText() {
1923       return Color.fromCOLORREF(GetSysColor(COLOR_WINDOWTEXT));
1924    }
1925 }
1926 
1927 final class TextFormat {
1928    private TextTrimming _trim = TextTrimming.none; // TextTrimming.CHARACTER.
1929    private TextFormatFlags _flags = TextFormatFlags.noPrefix | TextFormatFlags.wordBreak;
1930    private TextAlignment _align = TextAlignment.left;
1931    private DRAWTEXTPARAMS _params = {DRAWTEXTPARAMS.sizeof, 8, 0, 0};
1932 
1933    public this() {
1934 
1935    }
1936 
1937    public this(TextFormat tf) {
1938       this._trim = tf._trim;
1939       this._flags = tf._flags;
1940       this._align = tf._align;
1941       this._params = tf._params;
1942    }
1943 
1944    public this(TextFormatFlags tff) {
1945       this._flags = tff;
1946    }
1947 
1948    @property public TextAlignment alignment() {
1949       return this._align;
1950    }
1951 
1952    @property public void alignment(TextAlignment ta) {
1953       this._align = ta;
1954    }
1955 
1956    @property public void formatFlags(TextFormatFlags tff) {
1957       this._flags = tff;
1958    }
1959 
1960    @property public TextFormatFlags formatFlags() {
1961       return this._flags;
1962    }
1963 
1964    @property public void trimming(TextTrimming tt) {
1965       this._trim = tt;
1966    }
1967 
1968    @property public TextTrimming trimming() {
1969       return this._trim;
1970    }
1971 
1972    @property public int tabLength() {
1973       return _params.iTabLength;
1974    }
1975 
1976    @property public void tabLength(int tablen) {
1977       this._params.iTabLength = tablen;
1978    }
1979 
1980    @property public int leftMargin() {
1981       return this._params.iLeftMargin;
1982    }
1983 
1984    @property public void leftMargin(int sz) {
1985       this._params.iLeftMargin = sz;
1986    }
1987 
1988    @property public int rightMargin() {
1989       return this._params.iRightMargin;
1990    }
1991 
1992    @property public void rightMargin(int sz) {
1993       this._params.iRightMargin = sz;
1994    }
1995 }
1996 
1997 final class Screen {
1998    @property public static Size size() {
1999       Size sz = void; //Inizializzata sotto
2000 
2001       sz.width = GetSystemMetrics(SM_CXSCREEN);
2002       sz.height = GetSystemMetrics(SM_CYSCREEN);
2003 
2004       return sz;
2005    }
2006 
2007    @property public static Rect workArea() {
2008       Rect r = void; //Inizializzata sotto
2009 
2010       SystemParametersInfoW(SPI_GETWORKAREA, 0, &r.rect, 0);
2011       return r;
2012    }
2013 
2014    @property public static Canvas canvas() {
2015       return Canvas.fromHDC(GetWindowDC(null));
2016    }
2017 }