1 /*
2  * PROJECT:     PAINT for ReactOS
3  * LICENSE:     LGPL
4  * FILE:        base/applications/mspaint/drawing.cpp
5  * PURPOSE:     The drawing functions used by the tools
6  * PROGRAMMERS: Benedikt Freisen
7  */
8 
9 /* INCLUDES *********************************************************/
10 
11 #include "precomp.h"
12 
13 /* FUNCTIONS ********************************************************/
14 
15 void
16 Line(HDC hdc, LONG x1, LONG y1, LONG x2, LONG y2, COLORREF color, int thickness)
17 {
18     HPEN oldPen = (HPEN) SelectObject(hdc, CreatePen(PS_SOLID, thickness, color));
19     MoveToEx(hdc, x1, y1, NULL);
20     LineTo(hdc, x2, y2);
21     DeleteObject(SelectObject(hdc, oldPen));
22 }
23 
24 void
25 Rect(HDC hdc, LONG x1, LONG y1, LONG x2, LONG y2, COLORREF fg,  COLORREF bg, int thickness, int style)
26 {
27     HBRUSH oldBrush;
28     LOGBRUSH logbrush;
29     HPEN oldPen = (HPEN) SelectObject(hdc, CreatePen(PS_SOLID, thickness, fg));
30     logbrush.lbStyle = (style == 0) ? BS_HOLLOW : BS_SOLID;
31     logbrush.lbColor = (style == 2) ? fg : bg;
32     logbrush.lbHatch = 0;
33     oldBrush = (HBRUSH) SelectObject(hdc, CreateBrushIndirect(&logbrush));
34     Rectangle(hdc, x1, y1, x2, y2);
35     DeleteObject(SelectObject(hdc, oldBrush));
36     DeleteObject(SelectObject(hdc, oldPen));
37 }
38 
39 void
40 Ellp(HDC hdc, LONG x1, LONG y1, LONG x2, LONG y2, COLORREF fg,  COLORREF bg, int thickness, int style)
41 {
42     HBRUSH oldBrush;
43     LOGBRUSH logbrush;
44     HPEN oldPen = (HPEN) SelectObject(hdc, CreatePen(PS_SOLID, thickness, fg));
45     logbrush.lbStyle = (style == 0) ? BS_HOLLOW : BS_SOLID;
46     logbrush.lbColor = (style == 2) ? fg : bg;
47     logbrush.lbHatch = 0;
48     oldBrush = (HBRUSH) SelectObject(hdc, CreateBrushIndirect(&logbrush));
49     Ellipse(hdc, x1, y1, x2, y2);
50     DeleteObject(SelectObject(hdc, oldBrush));
51     DeleteObject(SelectObject(hdc, oldPen));
52 }
53 
54 void
55 RRect(HDC hdc, LONG x1, LONG y1, LONG x2, LONG y2, COLORREF fg,  COLORREF bg, int thickness, int style)
56 {
57     LOGBRUSH logbrush;
58     HBRUSH oldBrush;
59     HPEN oldPen = (HPEN) SelectObject(hdc, CreatePen(PS_SOLID, thickness, fg));
60     logbrush.lbStyle = (style == 0) ? BS_HOLLOW : BS_SOLID;
61     logbrush.lbColor = (style == 2) ? fg : bg;
62     logbrush.lbHatch = 0;
63     oldBrush = (HBRUSH) SelectObject(hdc, CreateBrushIndirect(&logbrush));
64     RoundRect(hdc, x1, y1, x2, y2, 16, 16);
65     DeleteObject(SelectObject(hdc, oldBrush));
66     DeleteObject(SelectObject(hdc, oldPen));
67 }
68 
69 void
70 Poly(HDC hdc, POINT * lpPoints, int nCount,  COLORREF fg,  COLORREF bg, int thickness, int style, BOOL closed, BOOL inverted)
71 {
72     LOGBRUSH logbrush;
73     HBRUSH oldBrush;
74     HPEN oldPen = (HPEN) SelectObject(hdc, CreatePen(PS_SOLID, thickness, fg));
75     UINT oldRop = GetROP2(hdc);
76 
77     if (inverted)
78       SetROP2(hdc, R2_NOTXORPEN);
79 
80     logbrush.lbStyle = (style == 0) ? BS_HOLLOW : BS_SOLID;
81     logbrush.lbColor = (style == 2) ? fg : bg;
82     logbrush.lbHatch = 0;
83     oldBrush = (HBRUSH) SelectObject(hdc, CreateBrushIndirect(&logbrush));
84     if (closed)
85         Polygon(hdc, lpPoints, nCount);
86     else
87         Polyline(hdc, lpPoints, nCount);
88     DeleteObject(SelectObject(hdc, oldBrush));
89     DeleteObject(SelectObject(hdc, oldPen));
90 
91     SetROP2(hdc, oldRop);
92 }
93 
94 void
95 Bezier(HDC hdc, POINT p1, POINT p2, POINT p3, POINT p4, COLORREF color, int thickness)
96 {
97     HPEN oldPen;
98     POINT fourPoints[4];
99     fourPoints[0] = p1;
100     fourPoints[1] = p2;
101     fourPoints[2] = p3;
102     fourPoints[3] = p4;
103     oldPen = (HPEN) SelectObject(hdc, CreatePen(PS_SOLID, thickness, color));
104     PolyBezier(hdc, fourPoints, 4);
105     DeleteObject(SelectObject(hdc, oldPen));
106 }
107 
108 void
109 Fill(HDC hdc, LONG x, LONG y, COLORREF color)
110 {
111     HBRUSH oldBrush = (HBRUSH) SelectObject(hdc, CreateSolidBrush(color));
112     ExtFloodFill(hdc, x, y, GetPixel(hdc, x, y), FLOODFILLSURFACE);
113     DeleteObject(SelectObject(hdc, oldBrush));
114 }
115 
116 void
117 Erase(HDC hdc, LONG x1, LONG y1, LONG x2, LONG y2, COLORREF color, LONG radius)
118 {
119     LONG a, b;
120     HPEN oldPen;
121     HBRUSH oldBrush = (HBRUSH) SelectObject(hdc, CreateSolidBrush(color));
122 
123     b = max(1, max(abs(x2 - x1), abs(y2 - y1)));
124     oldPen = (HPEN) SelectObject(hdc, CreatePen(PS_SOLID, 1, color));
125     for(a = 0; a <= b; a++)
126         Rectangle(hdc, (x1 * (b - a) + x2 * a) / b - radius + 1,
127                   (y1 * (b - a) + y2 * a) / b - radius + 1, (x1 * (b - a) + x2 * a) / b + radius + 1,
128                   (y1 * (b - a) + y2 * a) / b + radius + 1);
129     DeleteObject(SelectObject(hdc, oldBrush));
130     DeleteObject(SelectObject(hdc, oldPen));
131 }
132 
133 void
134 Replace(HDC hdc, LONG x1, LONG y1, LONG x2, LONG y2, COLORREF fg, COLORREF bg, LONG radius)
135 {
136     LONG a, b, x, y;
137     b = max(1, max(abs(x2 - x1), abs(y2 - y1)));
138 
139     for(a = 0; a <= b; a++)
140         for(y = (y1 * (b - a) + y2 * a) / b - radius + 1;
141             y < (y1 * (b - a) + y2 * a) / b + radius + 1; y++)
142             for(x = (x1 * (b - a) + x2 * a) / b - radius + 1;
143                 x < (x1 * (b - a) + x2 * a) / b + radius + 1; x++)
144                 if (GetPixel(hdc, x, y) == fg)
145                     SetPixel(hdc, x, y, bg);
146 }
147 
148 void
149 Airbrush(HDC hdc, LONG x, LONG y, COLORREF color, LONG r)
150 {
151     LONG a, b;
152 
153     for(b = -r; b <= r; b++)
154         for(a = -r; a <= r; a++)
155             if ((a * a + b * b <= r * r) && (rand() % 4 == 0))
156                 SetPixel(hdc, x + a, y + b, color);
157 }
158 
159 void
160 Brush(HDC hdc, LONG x1, LONG y1, LONG x2, LONG y2, COLORREF color, LONG style)
161 {
162     HPEN oldPen = (HPEN) SelectObject(hdc, CreatePen(PS_SOLID, 1, color));
163     HBRUSH oldBrush = (HBRUSH) SelectObject(hdc, CreateSolidBrush(color));
164     LONG a, b;
165     b = max(1, max(abs(x2 - x1), abs(y2 - y1)));
166     switch (style)
167     {
168         case 0:
169             for(a = 0; a <= b; a++)
170                 Ellipse(hdc, (x1 * (b - a) + x2 * a) / b - 3, (y1 * (b - a) + y2 * a) / b - 3,
171                         (x1 * (b - a) + x2 * a) / b + 4, (y1 * (b - a) + y2 * a) / b + 4);
172             break;
173         case 1:
174             for(a = 0; a <= b; a++)
175                 Ellipse(hdc, (x1 * (b - a) + x2 * a) / b - 1, (y1 * (b - a) + y2 * a) / b - 1,
176                         (x1 * (b - a) + x2 * a) / b + 3, (y1 * (b - a) + y2 * a) / b + 3);
177             break;
178         case 2:
179             MoveToEx(hdc, x1, y1, NULL);
180             LineTo(hdc, x2, y2);
181             SetPixel(hdc, x2, y2, color);
182             break;
183         case 3:
184             for(a = 0; a <= b; a++)
185                 Rectangle(hdc, (x1 * (b - a) + x2 * a) / b - 3, (y1 * (b - a) + y2 * a) / b - 3,
186                           (x1 * (b - a) + x2 * a) / b + 5, (y1 * (b - a) + y2 * a) / b + 5);
187             break;
188         case 4:
189             for(a = 0; a <= b; a++)
190                 Rectangle(hdc, (x1 * (b - a) + x2 * a) / b - 2, (y1 * (b - a) + y2 * a) / b - 2,
191                           (x1 * (b - a) + x2 * a) / b + 3, (y1 * (b - a) + y2 * a) / b + 3);
192             break;
193         case 5:
194             for(a = 0; a <= b; a++)
195                 Rectangle(hdc, (x1 * (b - a) + x2 * a) / b - 1, (y1 * (b - a) + y2 * a) / b - 1,
196                           (x1 * (b - a) + x2 * a) / b + 1, (y1 * (b - a) + y2 * a) / b + 1);
197             break;
198         case 6:
199         case 7:
200         case 8:
201         case 9:
202         case 10:
203         case 11:
204         {
205             POINT offsTop[] = {{4, -3}, {2, -2}, {0, 0},
206                                {-3, -3}, {-2, -2}, {-1, 0}};
207             POINT offsBtm[] = {{-3, 4}, {-2, 2}, {-1, 1},
208                                {4, 4}, {2, 2}, {0, 1}};
209             LONG idx = style - 6;
210             POINT pts[4];
211             pts[0].x = x1 + offsTop[idx].x;
212             pts[0].y = y1 + offsTop[idx].y;
213             pts[1].x = x1 + offsBtm[idx].x;
214             pts[1].y = y1 + offsBtm[idx].y;
215             pts[2].x = x2 + offsBtm[idx].x;
216             pts[2].y = y2 + offsBtm[idx].y;
217             pts[3].x = x2 + offsTop[idx].x;
218             pts[3].y = y2 + offsTop[idx].y;
219             Polygon(hdc, pts, 4);
220             break;
221         }
222     }
223     DeleteObject(SelectObject(hdc, oldBrush));
224     DeleteObject(SelectObject(hdc, oldPen));
225 }
226 
227 void
228 RectSel(HDC hdc, LONG x1, LONG y1, LONG x2, LONG y2)
229 {
230     HBRUSH oldBrush;
231     LOGBRUSH logbrush;
232     HPEN oldPen = (HPEN) SelectObject(hdc, CreatePen(PS_DOT, 1, GetSysColor(COLOR_HIGHLIGHT)));
233     UINT oldRop = GetROP2(hdc);
234 
235     SetROP2(hdc, R2_NOTXORPEN);
236 
237     logbrush.lbStyle = BS_HOLLOW;
238     logbrush.lbColor = 0;
239     logbrush.lbHatch = 0;
240     oldBrush = (HBRUSH) SelectObject(hdc, CreateBrushIndirect(&logbrush));
241     Rectangle(hdc, x1, y1, x2, y2);
242     DeleteObject(SelectObject(hdc, oldBrush));
243     DeleteObject(SelectObject(hdc, oldPen));
244 
245     SetROP2(hdc, oldRop);
246 }
247 
248 void
249 SelectionFrame(HDC hdc, LONG x1, LONG y1, LONG x2, LONG y2, COLORREF system_selection_color)
250 {
251     HBRUSH oldBrush;
252     LOGBRUSH logbrush;
253     HPEN oldPen = (HPEN) SelectObject(hdc, CreatePen(PS_DOT, 1, system_selection_color));
254 
255     logbrush.lbStyle = BS_HOLLOW;
256     logbrush.lbColor = 0;
257     logbrush.lbHatch = 0;
258     oldBrush = (HBRUSH) SelectObject(hdc, CreateBrushIndirect(&logbrush));
259     Rectangle(hdc, x1, y1, x2, y2); /* SEL BOX FRAME */
260     DeleteObject(SelectObject(hdc, oldBrush));
261     DeleteObject(SelectObject(hdc, oldPen));
262     oldPen = (HPEN) SelectObject(hdc, CreatePen(PS_SOLID, 1, system_selection_color));
263     oldBrush = (HBRUSH) SelectObject(hdc, CreateSolidBrush(system_selection_color));
264     Rectangle(hdc, x1 - 1, y1 - 1, x1 + 2, y1 + 2);
265     Rectangle(hdc, x2 - 2, y1 - 1, x2 + 2, y1 + 2);
266     Rectangle(hdc, x1 - 1, y2 - 2, x1 + 2, y2 + 1);
267     Rectangle(hdc, x2 - 2, y2 - 2, x2 + 2, y2 + 1);
268     Rectangle(hdc, (x1 + x2) / 2 - 1, y1 - 1, (x1 + x2) / 2 + 2, y1 + 2);
269     Rectangle(hdc, (x1 + x2) / 2 - 1, y2 - 2, (x1 + x2) / 2 + 2, y2 + 1);
270     Rectangle(hdc, x1 - 1, (y1 + y2) / 2 - 1, x1 + 2, (y1 + y2) / 2 + 2);
271     Rectangle(hdc, x2 - 2, (y1 + y2) / 2 - 1, x2 + 1, (y1 + y2) / 2 + 2);
272     DeleteObject(SelectObject(hdc, oldBrush));
273     DeleteObject(SelectObject(hdc, oldPen));
274 }
275 
276 void
277 Text(HDC hdc, LONG x1, LONG y1, LONG x2, LONG y2, COLORREF fg, COLORREF bg, LPCTSTR lpchText, HFONT font, LONG style)
278 {
279     INT iSaveDC = SaveDC(hdc); // We will modify the clipping region. Save now.
280 
281     RECT rc;
282     SetRect(&rc, x1, y1, x2, y2);
283 
284     if (style == 0) // Transparent
285     {
286         SetBkMode(hdc, TRANSPARENT);
287         GetBkColor(hdc);
288     }
289     else // Opaque
290     {
291         SetBkMode(hdc, OPAQUE);
292         SetBkColor(hdc, bg);
293 
294         HBRUSH hbr = CreateSolidBrush(bg);
295         FillRect(hdc, &rc, hbr); // Fill the background
296         DeleteObject(hbr);
297     }
298 
299     IntersectClipRect(hdc, rc.left, rc.top, rc.right, rc.bottom);
300 
301     HGDIOBJ hFontOld = SelectObject(hdc, font);
302     SetTextColor(hdc, fg);
303     const UINT uFormat = DT_LEFT | DT_TOP | DT_EDITCONTROL | DT_NOPREFIX | DT_NOCLIP |
304                          DT_EXPANDTABS | DT_WORDBREAK;
305     DrawText(hdc, lpchText, -1, &rc, uFormat);
306     SelectObject(hdc, hFontOld);
307 
308     RestoreDC(hdc, iSaveDC); // Restore
309 }
310 
311 BOOL
312 ColorKeyedMaskBlt(HDC hdcDest, int nXDest, int nYDest, int nWidth, int nHeight,
313                   HDC hdcSrc, int nXSrc, int nYSrc, HBITMAP hbmMask, int xMask, int yMask,
314                   DWORD dwRop, COLORREF keyColor)
315 {
316     HDC hTempDC;
317     HDC hTempDC2;
318     HBITMAP hTempBm;
319     HBRUSH hTempBrush;
320     HBITMAP hTempMask;
321 
322     hTempDC = CreateCompatibleDC(hdcSrc);
323     hTempDC2 = CreateCompatibleDC(hdcSrc);
324     hTempBm = CreateCompatibleBitmap(hTempDC, nWidth, nHeight);
325     SelectObject(hTempDC, hTempBm);
326     hTempBrush = CreateSolidBrush(keyColor);
327     SelectObject(hTempDC, hTempBrush);
328     BitBlt(hTempDC, 0, 0, nWidth, nHeight, hdcSrc, nXSrc, nYSrc, SRCCOPY);
329     PatBlt(hTempDC, 0, 0, nWidth, nHeight, PATINVERT);
330     hTempMask = CreateBitmap(nWidth, nHeight, 1, 1, NULL);
331     SelectObject(hTempDC2, hTempMask);
332     BitBlt(hTempDC2, 0, 0, nWidth, nHeight, hTempDC, 0, 0, SRCCOPY);
333     SelectObject(hTempDC, hbmMask);
334     BitBlt(hTempDC2, 0, 0, nWidth, nHeight, hTempDC, xMask, yMask, SRCAND);
335     MaskBlt(hdcDest, nXDest, nYDest, nWidth, nHeight, hdcSrc, nXSrc, nYSrc, hTempMask, xMask, yMask, dwRop);
336     DeleteDC(hTempDC);
337     DeleteDC(hTempDC2);
338     DeleteObject(hTempBm);
339     DeleteObject(hTempBrush);
340     DeleteObject(hTempMask);
341     return TRUE;
342 }
343