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