1 module simple;
2 
3 /+
4  + This tutorial is derived from: http://cairographics.org/cookbook/win32quickstart/
5  + Translated to D2 by Andrej Mitrovic, 2011.
6  +/
7 
8 import core.runtime;
9 import std.utf;
10 
11 pragma(lib, "gdi32.lib");
12 import windows.windef;
13 import windows.winuser;
14 import windows.wingdi;
15 
16 string appName     = "CairoWindow";
17 string description = "A simple win32 window with Cairo drawing";
18 HINSTANCE hinst;
19 
20 import cairo.c.cairo;
21 import cairo.cairo;
22 import cairo.win32;
23 
24 alias cairo.cairo.RGB RGB;  // conflicts with win32.wingdi.RGB
25 
26 extern (Windows)
27 int WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int iCmdShow)
28 {
29     int result;
30 
31 
32     try
33     {
34         Runtime.initialize();
35         result = myWinMain(hInstance, hPrevInstance, lpCmdLine, iCmdShow);
36         Runtime.terminate();
37     }
38     catch (Throwable o)
39     {
40         MessageBox(null, o.toString().toUTF16z, "Error", MB_OK | MB_ICONEXCLAMATION);
41         result = 0;
42     }
43 
44     return result;
45 }
46 
47 int myWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int iCmdShow)
48 {
49     hinst = hInstance;
50     HACCEL hAccel;
51     HWND hwnd;
52     MSG  msg;
53     WNDCLASS wndclass;
54 
55     wndclass.style         = CS_HREDRAW | CS_VREDRAW;
56     wndclass.lpfnWndProc   = &WndProc;
57     wndclass.cbClsExtra    = 0;
58     wndclass.cbWndExtra    = 0;
59     wndclass.hInstance     = hInstance;
60     wndclass.hIcon         = LoadIcon(null, IDI_APPLICATION);
61     wndclass.hCursor       = LoadCursor(null, IDC_ARROW);
62     wndclass.hbrBackground = cast(HBRUSH) GetStockObject(WHITE_BRUSH);
63     wndclass.lpszMenuName  = appName.toUTF16z;
64     wndclass.lpszClassName = appName.toUTF16z;
65 
66     if (!RegisterClass(&wndclass))
67     {
68         MessageBox(null, "This program requires Windows NT!", appName.toUTF16z, MB_ICONERROR);
69         return 0;
70     }
71 
72     hwnd = CreateWindow(appName.toUTF16z,              // window class name
73                         description.toUTF16z,          // window caption
74                         WS_OVERLAPPEDWINDOW,           // window style
75                         400,                 // initial x position
76                         400,                 // initial y position
77                         400,                 // initial x size
78                         400,                 // initial y size
79                         null,                          // parent window handle
80                         null,                          // window menu handle
81                         hInstance,                     // program instance handle
82                         null);                         // creation parameters
83 
84     ShowWindow(hwnd, iCmdShow);
85     UpdateWindow(hwnd);
86 
87     while (GetMessage(&msg, null, 0, 0))
88     {
89         TranslateMessage(&msg);
90         DispatchMessage(&msg);
91     }
92 
93     return msg.wParam;
94 }
95 
96 void roundedRectangle(Context ctx, int x, int y, int w, int h, int radius_x = 5, int radius_y = 5)
97 {
98     enum ARC_TO_BEZIER = 0.55228475;
99 
100     if (radius_x > w - radius_x)
101         radius_x = w / 2;
102 
103     if (radius_y > h - radius_y)
104         radius_y = h / 2;
105 
106     // approximate (quite close) the arc using a bezier curve
107     auto c1 = ARC_TO_BEZIER * radius_x;
108     auto c2 = ARC_TO_BEZIER * radius_y;
109 
110     ctx.newPath();
111     ctx.moveTo(x + radius_x, y);
112     ctx.relLineTo(w - 2 * radius_x, 0.0);
113     ctx.relCurveTo(c1, 0.0, radius_x, c2, radius_x, radius_y);
114     ctx.relLineTo(0, h - 2 * radius_y);
115     ctx.relCurveTo(0.0, c2, c1 - radius_x, radius_y, -radius_x, radius_y);
116     ctx.relLineTo(-w + 2 * radius_x, 0);
117     ctx.relCurveTo(-c1, 0, -radius_x, -c2, -radius_x, -radius_y);
118     ctx.relLineTo(0, -h + 2 * radius_y);
119     ctx.relCurveTo(0.0, -c2, radius_x - c1, -radius_y, radius_x, -radius_y);
120     ctx.closePath();
121 }
122 
123 extern (Windows)
124 LRESULT WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
125 {
126     switch (message)
127     {
128         case WM_CREATE:
129         {
130             window = new Window(hwnd);
131             return 0;
132         }
133 
134         default:
135     }
136 
137     if (window)
138         return window.process(hwnd, message, wParam, lParam);
139     else
140         return DefWindowProc(hwnd, message, wParam, lParam);
141 }
142 
143 Window window;
144 
145 class Window
146 {
147     int  x, y;
148     HWND hwnd;
149     HDC hdc;
150     PAINTSTRUCT ps;
151     RECT rc;
152     HDC _buffer;
153     HBITMAP hBitmap;
154     HBITMAP hOldBitmap;
155 
156     this(HWND hwnd)
157     {
158         this.hwnd = hwnd;
159     }
160 
161     LRESULT process(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
162     {
163         switch (message)
164         {
165             case WM_DESTROY:
166                 return OnDestroy(hwnd, message, wParam, lParam);
167 
168             case WM_PAINT:
169                 return OnPaint(hwnd, message, wParam, lParam);
170 
171             case WM_ERASEBKGND:
172                 return 0;
173 
174             default:
175         }
176 
177         return DefWindowProc(hwnd, message, wParam, lParam);
178     }
179 
180     auto OnPaint(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
181     {
182         hdc = BeginPaint(hwnd, &ps);
183         GetClientRect(hwnd, &rc);
184 
185         auto left = rc.left;
186         auto top = rc.top;
187         auto right = rc.right;
188         auto bottom = rc.bottom;
189 
190         auto width  = right - left;
191         auto height = bottom - top;
192         x = left;
193         y = top;
194 
195         _buffer    = CreateCompatibleDC(hdc);
196         hBitmap    = CreateCompatibleBitmap(hdc, width, height);
197         hOldBitmap = SelectObject(_buffer, hBitmap);
198 
199         auto surf = new Win32Surface(_buffer);
200         auto ctx = Context(surf);
201 
202         ctx.setSourceRGB(1, 1, 1);
203         ctx.paint();
204 
205         roundedRectangle(ctx, 50, 50, 250, 250, 10, 10);
206 
207         auto clr = RGB(0.9411764705882353, 0.996078431372549, 0.9137254901960784);
208         ctx.setSourceRGB(clr);
209         ctx.fillPreserve();
210 
211         clr = RGB(0.7019607843137254, 1.0, 0.5529411764705883);
212         ctx.setSourceRGB(clr);
213         ctx.stroke();
214 
215         ctx.setSourceRGB(0, 0, 0);
216         ctx.selectFontFace("Arial", FontSlant.CAIRO_FONT_SLANT_NORMAL, FontWeight.CAIRO_FONT_WEIGHT_NORMAL);
217         ctx.setFontSize(10.0);
218         auto txt = "Cairo is the greatest thing!";
219         ctx.moveTo(5.0, 10.0);
220         ctx.showText(txt);
221 
222         surf.finish();
223         BitBlt(hdc, 0, 0, width, height, _buffer, x, y, SRCCOPY);
224 
225         SelectObject(_buffer, hOldBitmap);
226         DeleteObject(hBitmap);
227         DeleteDC(_buffer);
228 
229         EndPaint(hwnd, &ps);
230         return 0;
231     }
232 
233     auto OnDestroy(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
234     {
235         PostQuitMessage(0);
236         return 0;
237     }
238 }