1 /* 2 * PROJECT: PAINT for ReactOS 3 * LICENSE: LGPL-2.0-or-later (https://spdx.org/licenses/LGPL-2.0-or-later) 4 * PURPOSE: Things which should not be in the mouse event handler itself 5 * COPYRIGHT: Copyright 2015 Benedikt Freisen <b.freisen@gmx.net> 6 * Copyright 2021 Katayama Hirofumi MZ <katayama.hirofumi.mz@gmail.com> 7 */ 8 9 /* INCLUDES *********************************************************/ 10 11 #include "precomp.h" 12 13 INT ToolBase::s_pointSP = 0; 14 POINT ToolBase::s_pointStack[256] = { { 0 } }; 15 16 /* FUNCTIONS ********************************************************/ 17 18 void 19 regularize(LONG x0, LONG y0, LONG& x1, LONG& y1) 20 { 21 if (abs(x1 - x0) >= abs(y1 - y0)) 22 y1 = y0 + (y1 > y0 ? abs(x1 - x0) : -abs(x1 - x0)); 23 else 24 x1 = x0 + (x1 > x0 ? abs(y1 - y0) : -abs(y1 - y0)); 25 } 26 27 void 28 roundTo8Directions(LONG x0, LONG y0, LONG& x1, LONG& y1) 29 { 30 if (abs(x1 - x0) >= abs(y1 - y0)) 31 { 32 if (abs(y1 - y0) * 5 < abs(x1 - x0) * 2) 33 y1 = y0; 34 else 35 y1 = y0 + (y1 > y0 ? abs(x1 - x0) : -abs(x1 - x0)); 36 } 37 else 38 { 39 if (abs(x1 - x0) * 5 < abs(y1 - y0) * 2) 40 x1 = x0; 41 else 42 x1 = x0 + (x1 > x0 ? abs(y1 - y0) : -abs(y1 - y0)); 43 } 44 } 45 46 BOOL nearlyEqualPoints(INT x0, INT y0, INT x1, INT y1) 47 { 48 INT cxThreshold = toolsModel.GetLineWidth() + UnZoomed(GetSystemMetrics(SM_CXDRAG)); 49 INT cyThreshold = toolsModel.GetLineWidth() + UnZoomed(GetSystemMetrics(SM_CYDRAG)); 50 return (abs(x1 - x0) <= cxThreshold) && (abs(y1 - y0) <= cyThreshold); 51 } 52 53 void updateStartAndLast(LONG x, LONG y) 54 { 55 g_ptStart.x = g_ptEnd.x = x; 56 g_ptStart.y = g_ptEnd.y = y; 57 } 58 59 void updateLast(LONG x, LONG y) 60 { 61 g_ptEnd.x = x; 62 g_ptEnd.y = y; 63 } 64 65 void ToolBase::reset() 66 { 67 s_pointSP = 0; 68 g_ptStart.x = g_ptStart.y = g_ptEnd.x = g_ptEnd.y = -1; 69 selectionModel.ResetPtStack(); 70 if (selectionModel.m_bShow) 71 { 72 selectionModel.Landing(); 73 selectionModel.HideSelection(); 74 } 75 } 76 77 void ToolBase::OnCancelDraw() 78 { 79 reset(); 80 imageModel.NotifyImageChanged(); 81 } 82 83 void ToolBase::OnFinishDraw() 84 { 85 reset(); 86 imageModel.NotifyImageChanged(); 87 } 88 89 void ToolBase::beginEvent() 90 { 91 m_hdc = imageModel.GetDC(); 92 m_fg = paletteModel.GetFgColor(); 93 m_bg = paletteModel.GetBgColor(); 94 } 95 96 void ToolBase::endEvent() 97 { 98 m_hdc = NULL; 99 } 100 101 void ToolBase::OnDrawSelectionOnCanvas(HDC hdc) 102 { 103 if (!selectionModel.m_bShow) 104 return; 105 106 RECT rcSelection = selectionModel.m_rc; 107 canvasWindow.ImageToCanvas(rcSelection); 108 109 ::InflateRect(&rcSelection, GRIP_SIZE, GRIP_SIZE); 110 drawSizeBoxes(hdc, &rcSelection, TRUE); 111 } 112 113 /* TOOLS ********************************************************/ 114 115 // TOOL_FREESEL 116 struct FreeSelTool : ToolBase 117 { 118 BOOL m_bLeftButton = FALSE; 119 120 FreeSelTool() : ToolBase(TOOL_FREESEL) 121 { 122 } 123 124 void OnDrawOverlayOnImage(HDC hdc) override 125 { 126 if (!selectionModel.IsLanded()) 127 { 128 selectionModel.DrawBackgroundPoly(hdc, selectionModel.m_rgbBack); 129 selectionModel.DrawSelection(hdc, paletteModel.GetBgColor(), toolsModel.IsBackgroundTransparent()); 130 } 131 132 if (canvasWindow.m_drawing) 133 { 134 selectionModel.DrawFramePoly(hdc); 135 } 136 } 137 138 void OnDrawOverlayOnCanvas(HDC hdc) override 139 { 140 OnDrawSelectionOnCanvas(hdc); 141 } 142 143 void OnButtonDown(BOOL bLeftButton, LONG x, LONG y, BOOL bDoubleClick) override 144 { 145 selectionModel.Landing(); 146 if (bLeftButton) 147 { 148 selectionModel.HideSelection(); 149 selectionModel.ResetPtStack(); 150 POINT pt = { x, y }; 151 selectionModel.PushToPtStack(pt); 152 } 153 m_bLeftButton = bLeftButton; 154 } 155 156 void OnMouseMove(BOOL bLeftButton, LONG x, LONG y) override 157 { 158 if (bLeftButton) 159 { 160 POINT pt = { x, y }; 161 imageModel.Clamp(pt); 162 selectionModel.PushToPtStack(pt); 163 imageModel.NotifyImageChanged(); 164 } 165 } 166 167 void OnButtonUp(BOOL bLeftButton, LONG x, LONG y) override 168 { 169 if (bLeftButton) 170 { 171 if (selectionModel.PtStackSize() > 2) 172 { 173 selectionModel.BuildMaskFromPtStack(); 174 selectionModel.m_bShow = TRUE; 175 } 176 else 177 { 178 selectionModel.ResetPtStack(); 179 selectionModel.m_bShow = FALSE; 180 } 181 imageModel.NotifyImageChanged(); 182 } 183 else 184 { 185 POINT pt = { x, y }; 186 canvasWindow.ClientToScreen(&pt); 187 mainWindow.TrackPopupMenu(pt, 0); 188 } 189 } 190 191 void OnFinishDraw() override 192 { 193 selectionModel.Landing(); 194 ToolBase::OnFinishDraw(); 195 } 196 197 void OnCancelDraw() override 198 { 199 selectionModel.HideSelection(); 200 ToolBase::OnCancelDraw(); 201 } 202 }; 203 204 // TOOL_RECTSEL 205 struct RectSelTool : ToolBase 206 { 207 BOOL m_bLeftButton = FALSE; 208 209 RectSelTool() : ToolBase(TOOL_RECTSEL) 210 { 211 } 212 213 void OnDrawOverlayOnImage(HDC hdc) override 214 { 215 if (!selectionModel.IsLanded()) 216 { 217 selectionModel.DrawBackgroundRect(hdc, selectionModel.m_rgbBack); 218 selectionModel.DrawSelection(hdc, paletteModel.GetBgColor(), toolsModel.IsBackgroundTransparent()); 219 } 220 221 if (canvasWindow.m_drawing) 222 { 223 RECT rc = selectionModel.m_rc; 224 if (!::IsRectEmpty(&rc)) 225 RectSel(hdc, rc.left, rc.top, rc.right, rc.bottom); 226 } 227 } 228 229 void OnDrawOverlayOnCanvas(HDC hdc) override 230 { 231 OnDrawSelectionOnCanvas(hdc); 232 } 233 234 void OnButtonDown(BOOL bLeftButton, LONG x, LONG y, BOOL bDoubleClick) override 235 { 236 selectionModel.Landing(); 237 if (bLeftButton) 238 { 239 selectionModel.HideSelection(); 240 } 241 m_bLeftButton = bLeftButton; 242 } 243 244 void OnMouseMove(BOOL bLeftButton, LONG x, LONG y) override 245 { 246 if (bLeftButton) 247 { 248 POINT pt = { x, y }; 249 imageModel.Clamp(pt); 250 selectionModel.SetRectFromPoints(g_ptStart, pt); 251 imageModel.NotifyImageChanged(); 252 } 253 } 254 255 void OnButtonUp(BOOL bLeftButton, LONG x, LONG y) override 256 { 257 POINT pt = { x, y }; 258 if (bLeftButton) 259 { 260 imageModel.Clamp(pt); 261 selectionModel.SetRectFromPoints(g_ptStart, pt); 262 selectionModel.m_bShow = !selectionModel.m_rc.IsRectEmpty(); 263 imageModel.NotifyImageChanged(); 264 } 265 else 266 { 267 canvasWindow.ClientToScreen(&pt); 268 mainWindow.TrackPopupMenu(pt, 0); 269 } 270 } 271 272 void OnFinishDraw() override 273 { 274 selectionModel.Landing(); 275 ToolBase::OnFinishDraw(); 276 } 277 278 void OnCancelDraw() override 279 { 280 selectionModel.HideSelection(); 281 ToolBase::OnCancelDraw(); 282 } 283 }; 284 285 struct TwoPointDrawTool : ToolBase 286 { 287 BOOL m_bLeftButton = FALSE; 288 BOOL m_bDrawing = FALSE; 289 290 TwoPointDrawTool(TOOLTYPE type) : ToolBase(type) 291 { 292 } 293 294 void OnButtonDown(BOOL bLeftButton, LONG x, LONG y, BOOL bDoubleClick) override 295 { 296 m_bLeftButton = bLeftButton; 297 m_bDrawing = TRUE; 298 g_ptStart.x = g_ptEnd.x = x; 299 g_ptStart.y = g_ptEnd.y = y; 300 imageModel.NotifyImageChanged(); 301 } 302 303 void OnMouseMove(BOOL bLeftButton, LONG x, LONG y) override 304 { 305 g_ptEnd.x = x; 306 g_ptEnd.y = y; 307 imageModel.NotifyImageChanged(); 308 } 309 310 void OnButtonUp(BOOL bLeftButton, LONG x, LONG y) override 311 { 312 g_ptEnd.x = x; 313 g_ptEnd.y = y; 314 imageModel.PushImageForUndo(); 315 OnDrawOverlayOnImage(m_hdc); 316 m_bDrawing = FALSE; 317 imageModel.NotifyImageChanged(); 318 } 319 320 void OnFinishDraw() override 321 { 322 m_bDrawing = FALSE; 323 ToolBase::OnFinishDraw(); 324 } 325 326 void OnCancelDraw() override 327 { 328 m_bDrawing = FALSE; 329 ToolBase::OnCancelDraw(); 330 } 331 }; 332 333 struct SmoothDrawTool : ToolBase 334 { 335 SmoothDrawTool(TOOLTYPE type) : ToolBase(type) 336 { 337 } 338 339 virtual void draw(BOOL bLeftButton, LONG x, LONG y) = 0; 340 341 void OnButtonDown(BOOL bLeftButton, LONG x, LONG y, BOOL bDoubleClick) override 342 { 343 imageModel.PushImageForUndo(); 344 g_ptStart.x = g_ptEnd.x = x; 345 g_ptStart.y = g_ptEnd.y = y; 346 imageModel.NotifyImageChanged(); 347 } 348 349 void OnMouseMove(BOOL bLeftButton, LONG x, LONG y) override 350 { 351 draw(bLeftButton, x, y); 352 imageModel.NotifyImageChanged(); 353 } 354 355 void OnButtonUp(BOOL bLeftButton, LONG x, LONG y) override 356 { 357 draw(bLeftButton, x, y); 358 OnFinishDraw(); 359 } 360 361 void OnFinishDraw() override 362 { 363 ToolBase::OnFinishDraw(); 364 } 365 366 void OnCancelDraw() override 367 { 368 OnButtonUp(FALSE, 0, 0); 369 imageModel.Undo(TRUE); 370 ToolBase::OnCancelDraw(); 371 } 372 }; 373 374 // TOOL_RUBBER 375 struct RubberTool : SmoothDrawTool 376 { 377 RubberTool() : SmoothDrawTool(TOOL_RUBBER) 378 { 379 } 380 381 void draw(BOOL bLeftButton, LONG x, LONG y) override 382 { 383 if (bLeftButton) 384 Erase(m_hdc, g_ptEnd.x, g_ptEnd.y, x, y, m_bg, toolsModel.GetRubberRadius()); 385 else 386 Replace(m_hdc, g_ptEnd.x, g_ptEnd.y, x, y, m_fg, m_bg, toolsModel.GetRubberRadius()); 387 g_ptEnd.x = x; 388 g_ptEnd.y = y; 389 } 390 }; 391 392 // TOOL_FILL 393 struct FillTool : ToolBase 394 { 395 FillTool() : ToolBase(TOOL_FILL) 396 { 397 } 398 399 void OnButtonDown(BOOL bLeftButton, LONG x, LONG y, BOOL bDoubleClick) override 400 { 401 imageModel.PushImageForUndo(); 402 Fill(m_hdc, x, y, bLeftButton ? m_fg : m_bg); 403 } 404 }; 405 406 // TOOL_COLOR 407 struct ColorTool : ToolBase 408 { 409 ColorTool() : ToolBase(TOOL_COLOR) 410 { 411 } 412 413 void fetchColor(BOOL bLeftButton, LONG x, LONG y) 414 { 415 COLORREF rgbColor; 416 417 if (0 <= x && x < imageModel.GetWidth() && 0 <= y && y < imageModel.GetHeight()) 418 rgbColor = GetPixel(m_hdc, x, y); 419 else 420 rgbColor = RGB(255, 255, 255); // Outside is white 421 422 if (bLeftButton) 423 paletteModel.SetFgColor(rgbColor); 424 else 425 paletteModel.SetBgColor(rgbColor); 426 } 427 428 void OnMouseMove(BOOL bLeftButton, LONG x, LONG y) override 429 { 430 fetchColor(bLeftButton, x, y); 431 } 432 433 void OnButtonUp(BOOL bLeftButton, LONG x, LONG y) override 434 { 435 fetchColor(bLeftButton, x, y); 436 toolsModel.SetActiveTool(toolsModel.GetOldActiveTool()); 437 } 438 }; 439 440 // TOOL_ZOOM 441 struct ZoomTool : ToolBase 442 { 443 ZoomTool() : ToolBase(TOOL_ZOOM) 444 { 445 } 446 447 void OnButtonDown(BOOL bLeftButton, LONG x, LONG y, BOOL bDoubleClick) override 448 { 449 imageModel.PushImageForUndo(); 450 if (bLeftButton) 451 { 452 if (toolsModel.GetZoom() < MAX_ZOOM) 453 zoomTo(toolsModel.GetZoom() * 2, x, y); 454 } 455 else 456 { 457 if (toolsModel.GetZoom() > MIN_ZOOM) 458 zoomTo(toolsModel.GetZoom() / 2, x, y); 459 } 460 } 461 }; 462 463 // TOOL_PEN 464 struct PenTool : SmoothDrawTool 465 { 466 PenTool() : SmoothDrawTool(TOOL_PEN) 467 { 468 } 469 470 void draw(BOOL bLeftButton, LONG x, LONG y) override 471 { 472 COLORREF rgb = bLeftButton ? m_fg : m_bg; 473 Line(m_hdc, g_ptEnd.x, g_ptEnd.y, x, y, rgb, 1); 474 ::SetPixelV(m_hdc, x, y, rgb); 475 g_ptEnd.x = x; 476 g_ptEnd.y = y; 477 } 478 }; 479 480 // TOOL_BRUSH 481 struct BrushTool : SmoothDrawTool 482 { 483 BrushTool() : SmoothDrawTool(TOOL_BRUSH) 484 { 485 } 486 487 void draw(BOOL bLeftButton, LONG x, LONG y) override 488 { 489 COLORREF rgb = bLeftButton ? m_fg : m_bg; 490 Brush(m_hdc, g_ptEnd.x, g_ptEnd.y, x, y, rgb, toolsModel.GetBrushStyle()); 491 g_ptEnd.x = x; 492 g_ptEnd.y = y; 493 } 494 }; 495 496 // TOOL_AIRBRUSH 497 struct AirBrushTool : SmoothDrawTool 498 { 499 AirBrushTool() : SmoothDrawTool(TOOL_AIRBRUSH) 500 { 501 } 502 503 void draw(BOOL bLeftButton, LONG x, LONG y) override 504 { 505 COLORREF rgb = bLeftButton ? m_fg : m_bg; 506 Airbrush(m_hdc, x, y, rgb, toolsModel.GetAirBrushWidth()); 507 } 508 }; 509 510 // TOOL_TEXT 511 struct TextTool : ToolBase 512 { 513 TextTool() : ToolBase(TOOL_TEXT) 514 { 515 } 516 517 void OnDrawOverlayOnImage(HDC hdc) override 518 { 519 if (canvasWindow.m_drawing) 520 { 521 RECT rc = selectionModel.m_rc; 522 if (!::IsRectEmpty(&rc)) 523 RectSel(hdc, rc.left, rc.top, rc.right, rc.bottom); 524 } 525 } 526 527 void UpdatePoint(LONG x, LONG y) 528 { 529 POINT pt = { x, y }; 530 imageModel.Clamp(pt); 531 selectionModel.SetRectFromPoints(g_ptStart, pt); 532 imageModel.NotifyImageChanged(); 533 } 534 535 void OnButtonDown(BOOL bLeftButton, LONG x, LONG y, BOOL bDoubleClick) override 536 { 537 if (!textEditWindow.IsWindow()) 538 textEditWindow.Create(canvasWindow); 539 540 UpdatePoint(x, y); 541 } 542 543 void OnMouseMove(BOOL bLeftButton, LONG x, LONG y) override 544 { 545 UpdatePoint(x, y); 546 } 547 548 void draw(HDC hdc) 549 { 550 CString szText; 551 textEditWindow.GetWindowText(szText); 552 553 RECT rc; 554 textEditWindow.InvalidateEditRect(); 555 textEditWindow.GetEditRect(&rc); 556 ::InflateRect(&rc, -GRIP_SIZE / 2, -GRIP_SIZE / 2); 557 558 // Draw the text 559 INT style = (toolsModel.IsBackgroundTransparent() ? 0 : 1); 560 Text(hdc, rc.left, rc.top, rc.right, rc.bottom, m_fg, m_bg, szText, 561 textEditWindow.GetFont(), style); 562 } 563 564 void quit() 565 { 566 if (textEditWindow.IsWindow()) 567 textEditWindow.ShowWindow(SW_HIDE); 568 selectionModel.HideSelection(); 569 } 570 571 void OnButtonUp(BOOL bLeftButton, LONG x, LONG y) override 572 { 573 POINT pt = { x, y }; 574 imageModel.Clamp(pt); 575 selectionModel.SetRectFromPoints(g_ptStart, pt); 576 577 BOOL bTextBoxShown = ::IsWindowVisible(textEditWindow); 578 if (bTextBoxShown) 579 { 580 if (textEditWindow.GetWindowTextLength() > 0) 581 { 582 imageModel.PushImageForUndo(); 583 draw(m_hdc); 584 } 585 if (::IsRectEmpty(&selectionModel.m_rc)) 586 { 587 quit(); 588 return; 589 } 590 } 591 592 if (registrySettings.ShowTextTool) 593 { 594 if (!fontsDialog.IsWindow()) 595 fontsDialog.Create(mainWindow); 596 597 fontsDialog.ShowWindow(SW_SHOWNOACTIVATE); 598 } 599 600 RECT rc = selectionModel.m_rc; 601 602 // Enlarge if tool small 603 INT cxMin = CX_MINTEXTEDIT, cyMin = CY_MINTEXTEDIT; 604 if (selectionModel.m_rc.IsRectEmpty()) 605 { 606 SetRect(&rc, x, y, x + cxMin, y + cyMin); 607 } 608 else 609 { 610 if (rc.right - rc.left < cxMin) 611 rc.right = rc.left + cxMin; 612 if (rc.bottom - rc.top < cyMin) 613 rc.bottom = rc.top + cyMin; 614 } 615 616 if (!textEditWindow.IsWindow()) 617 textEditWindow.Create(canvasWindow); 618 619 textEditWindow.SetWindowText(NULL); 620 textEditWindow.ValidateEditRect(&rc); 621 textEditWindow.ShowWindow(SW_SHOWNOACTIVATE); 622 textEditWindow.SetFocus(); 623 } 624 625 void OnFinishDraw() override 626 { 627 if (textEditWindow.GetWindowTextLength() > 0) 628 { 629 imageModel.PushImageForUndo(); 630 draw(m_hdc); 631 } 632 quit(); 633 ToolBase::OnFinishDraw(); 634 } 635 636 void OnCancelDraw() override 637 { 638 quit(); 639 ToolBase::OnCancelDraw(); 640 } 641 }; 642 643 // TOOL_LINE 644 struct LineTool : TwoPointDrawTool 645 { 646 LineTool() : TwoPointDrawTool(TOOL_LINE) 647 { 648 } 649 650 void OnDrawOverlayOnImage(HDC hdc) override 651 { 652 if (!m_bDrawing) 653 return; 654 if (GetAsyncKeyState(VK_SHIFT) < 0) 655 roundTo8Directions(g_ptStart.x, g_ptStart.y, g_ptEnd.x, g_ptEnd.y); 656 COLORREF rgb = m_bLeftButton ? m_fg : m_bg; 657 Line(hdc, g_ptStart.x, g_ptStart.y, g_ptEnd.x, g_ptEnd.y, rgb, toolsModel.GetLineWidth()); 658 } 659 }; 660 661 // TOOL_BEZIER 662 struct BezierTool : ToolBase 663 { 664 BOOL m_bLeftButton = FALSE; 665 BOOL m_bDrawing = FALSE; 666 667 BezierTool() : ToolBase(TOOL_BEZIER) 668 { 669 } 670 671 void OnDrawOverlayOnImage(HDC hdc) 672 { 673 if (!m_bDrawing) 674 return; 675 676 COLORREF rgb = (m_bLeftButton ? m_fg : m_bg); 677 switch (s_pointSP) 678 { 679 case 1: 680 Line(hdc, s_pointStack[0].x, s_pointStack[0].y, s_pointStack[1].x, s_pointStack[1].y, rgb, 681 toolsModel.GetLineWidth()); 682 break; 683 case 2: 684 Bezier(hdc, s_pointStack[0], s_pointStack[2], s_pointStack[2], s_pointStack[1], rgb, toolsModel.GetLineWidth()); 685 break; 686 case 3: 687 Bezier(hdc, s_pointStack[0], s_pointStack[2], s_pointStack[3], s_pointStack[1], rgb, toolsModel.GetLineWidth()); 688 break; 689 } 690 } 691 692 void OnButtonDown(BOOL bLeftButton, LONG x, LONG y, BOOL bDoubleClick) override 693 { 694 m_bLeftButton = bLeftButton; 695 696 if (!m_bDrawing) 697 { 698 m_bDrawing = TRUE; 699 s_pointStack[s_pointSP].x = s_pointStack[s_pointSP + 1].x = x; 700 s_pointStack[s_pointSP].y = s_pointStack[s_pointSP + 1].y = y; 701 ++s_pointSP; 702 } 703 else 704 { 705 ++s_pointSP; 706 s_pointStack[s_pointSP].x = x; 707 s_pointStack[s_pointSP].y = y; 708 } 709 710 imageModel.NotifyImageChanged(); 711 } 712 713 void OnMouseMove(BOOL bLeftButton, LONG x, LONG y) override 714 { 715 s_pointStack[s_pointSP].x = x; 716 s_pointStack[s_pointSP].y = y; 717 imageModel.NotifyImageChanged(); 718 } 719 720 void OnButtonUp(BOOL bLeftButton, LONG x, LONG y) override 721 { 722 s_pointStack[s_pointSP].x = x; 723 s_pointStack[s_pointSP].y = y; 724 if (s_pointSP >= 3) 725 { 726 OnFinishDraw(); 727 return; 728 } 729 imageModel.NotifyImageChanged(); 730 } 731 732 void OnCancelDraw() override 733 { 734 m_bDrawing = FALSE; 735 ToolBase::OnCancelDraw(); 736 } 737 738 void OnFinishDraw() override 739 { 740 imageModel.PushImageForUndo(); 741 OnDrawOverlayOnImage(m_hdc); 742 m_bDrawing = FALSE; 743 ToolBase::OnFinishDraw(); 744 } 745 }; 746 747 // TOOL_RECT 748 struct RectTool : TwoPointDrawTool 749 { 750 RectTool() : TwoPointDrawTool(TOOL_RECT) 751 { 752 } 753 754 void OnDrawOverlayOnImage(HDC hdc) override 755 { 756 if (!m_bDrawing) 757 return; 758 if (GetAsyncKeyState(VK_SHIFT) < 0) 759 regularize(g_ptStart.x, g_ptStart.y, g_ptEnd.x, g_ptEnd.y); 760 if (m_bLeftButton) 761 Rect(hdc, g_ptStart.x, g_ptStart.y, g_ptEnd.x, g_ptEnd.y, m_fg, m_bg, toolsModel.GetLineWidth(), toolsModel.GetShapeStyle()); 762 else 763 Rect(hdc, g_ptStart.x, g_ptStart.y, g_ptEnd.x, g_ptEnd.y, m_bg, m_fg, toolsModel.GetLineWidth(), toolsModel.GetShapeStyle()); 764 } 765 }; 766 767 // TOOL_SHAPE 768 struct ShapeTool : ToolBase 769 { 770 BOOL m_bLeftButton = FALSE; 771 BOOL m_bClosed = FALSE; 772 773 ShapeTool() : ToolBase(TOOL_SHAPE) 774 { 775 } 776 777 void OnDrawOverlayOnImage(HDC hdc) 778 { 779 if (s_pointSP <= 0) 780 return; 781 782 if (m_bLeftButton) 783 Poly(hdc, s_pointStack, s_pointSP + 1, m_fg, m_bg, toolsModel.GetLineWidth(), toolsModel.GetShapeStyle(), m_bClosed, FALSE); 784 else 785 Poly(hdc, s_pointStack, s_pointSP + 1, m_bg, m_fg, toolsModel.GetLineWidth(), toolsModel.GetShapeStyle(), m_bClosed, FALSE); 786 } 787 788 void OnButtonDown(BOOL bLeftButton, LONG x, LONG y, BOOL bDoubleClick) override 789 { 790 m_bLeftButton = bLeftButton; 791 m_bClosed = FALSE; 792 793 if ((s_pointSP > 0) && (GetAsyncKeyState(VK_SHIFT) < 0)) 794 roundTo8Directions(s_pointStack[s_pointSP - 1].x, s_pointStack[s_pointSP - 1].y, x, y); 795 796 s_pointStack[s_pointSP].x = x; 797 s_pointStack[s_pointSP].y = y; 798 799 if (s_pointSP && bDoubleClick) 800 { 801 OnFinishDraw(); 802 return; 803 } 804 805 if (s_pointSP == 0) 806 { 807 s_pointSP++; 808 s_pointStack[s_pointSP].x = x; 809 s_pointStack[s_pointSP].y = y; 810 } 811 812 imageModel.NotifyImageChanged(); 813 } 814 815 void OnMouseMove(BOOL bLeftButton, LONG x, LONG y) override 816 { 817 if ((s_pointSP > 0) && (GetAsyncKeyState(VK_SHIFT) < 0)) 818 roundTo8Directions(s_pointStack[s_pointSP - 1].x, s_pointStack[s_pointSP - 1].y, x, y); 819 820 s_pointStack[s_pointSP].x = x; 821 s_pointStack[s_pointSP].y = y; 822 823 imageModel.NotifyImageChanged(); 824 } 825 826 void OnButtonUp(BOOL bLeftButton, LONG x, LONG y) override 827 { 828 if ((s_pointSP > 0) && (GetAsyncKeyState(VK_SHIFT) < 0)) 829 roundTo8Directions(s_pointStack[s_pointSP - 1].x, s_pointStack[s_pointSP - 1].y, x, y); 830 831 m_bClosed = FALSE; 832 if (nearlyEqualPoints(x, y, s_pointStack[0].x, s_pointStack[0].y)) 833 { 834 OnFinishDraw(); 835 return; 836 } 837 else 838 { 839 s_pointSP++; 840 s_pointStack[s_pointSP].x = x; 841 s_pointStack[s_pointSP].y = y; 842 } 843 844 if (s_pointSP == _countof(s_pointStack)) 845 s_pointSP--; 846 847 imageModel.NotifyImageChanged(); 848 } 849 850 void OnCancelDraw() override 851 { 852 ToolBase::OnCancelDraw(); 853 } 854 855 void OnFinishDraw() override 856 { 857 if (s_pointSP) 858 { 859 --s_pointSP; 860 m_bClosed = TRUE; 861 862 imageModel.PushImageForUndo(); 863 OnDrawOverlayOnImage(m_hdc); 864 } 865 866 m_bClosed = FALSE; 867 s_pointSP = 0; 868 869 ToolBase::OnFinishDraw(); 870 } 871 }; 872 873 // TOOL_ELLIPSE 874 struct EllipseTool : TwoPointDrawTool 875 { 876 EllipseTool() : TwoPointDrawTool(TOOL_ELLIPSE) 877 { 878 } 879 880 void OnDrawOverlayOnImage(HDC hdc) override 881 { 882 if (!m_bDrawing) 883 return; 884 if (GetAsyncKeyState(VK_SHIFT) < 0) 885 regularize(g_ptStart.x, g_ptStart.y, g_ptEnd.x, g_ptEnd.y); 886 if (m_bLeftButton) 887 Ellp(hdc, g_ptStart.x, g_ptStart.y, g_ptEnd.x, g_ptEnd.y, m_fg, m_bg, toolsModel.GetLineWidth(), toolsModel.GetShapeStyle()); 888 else 889 Ellp(hdc, g_ptStart.x, g_ptStart.y, g_ptEnd.x, g_ptEnd.y, m_bg, m_fg, toolsModel.GetLineWidth(), toolsModel.GetShapeStyle()); 890 } 891 }; 892 893 // TOOL_RRECT 894 struct RRectTool : TwoPointDrawTool 895 { 896 RRectTool() : TwoPointDrawTool(TOOL_RRECT) 897 { 898 } 899 900 void OnDrawOverlayOnImage(HDC hdc) override 901 { 902 if (!m_bDrawing) 903 return; 904 if (GetAsyncKeyState(VK_SHIFT) < 0) 905 regularize(g_ptStart.x, g_ptStart.y, g_ptEnd.x, g_ptEnd.y); 906 if (m_bLeftButton) 907 RRect(hdc, g_ptStart.x, g_ptStart.y, g_ptEnd.x, g_ptEnd.y, m_fg, m_bg, toolsModel.GetLineWidth(), toolsModel.GetShapeStyle()); 908 else 909 RRect(hdc, g_ptStart.x, g_ptStart.y, g_ptEnd.x, g_ptEnd.y, m_bg, m_fg, toolsModel.GetLineWidth(), toolsModel.GetShapeStyle()); 910 } 911 }; 912 913 /*static*/ ToolBase* 914 ToolBase::createToolObject(TOOLTYPE type) 915 { 916 switch (type) 917 { 918 case TOOL_FREESEL: return new FreeSelTool(); 919 case TOOL_RECTSEL: return new RectSelTool(); 920 case TOOL_RUBBER: return new RubberTool(); 921 case TOOL_FILL: return new FillTool(); 922 case TOOL_COLOR: return new ColorTool(); 923 case TOOL_ZOOM: return new ZoomTool(); 924 case TOOL_PEN: return new PenTool(); 925 case TOOL_BRUSH: return new BrushTool(); 926 case TOOL_AIRBRUSH: return new AirBrushTool(); 927 case TOOL_TEXT: return new TextTool(); 928 case TOOL_LINE: return new LineTool(); 929 case TOOL_BEZIER: return new BezierTool(); 930 case TOOL_RECT: return new RectTool(); 931 case TOOL_SHAPE: return new ShapeTool(); 932 case TOOL_ELLIPSE: return new EllipseTool(); 933 case TOOL_RRECT: return new RRectTool(); 934 } 935 UNREACHABLE; 936 return NULL; 937 } 938