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