1 /* 2 * PROJECT: PAINT for ReactOS 3 * LICENSE: LGPL-2.0-or-later (https://spdx.org/licenses/LGPL-2.0-or-later) 4 * PURPOSE: Providing the canvas window class 5 * COPYRIGHT: Copyright 2015 Benedikt Freisen <b.freisen@gmx.net> 6 */ 7 8 #include "precomp.h" 9 10 CCanvasWindow canvasWindow; 11 12 /* FUNCTIONS ********************************************************/ 13 14 CCanvasWindow::CCanvasWindow() 15 : m_drawing(FALSE) 16 , m_hitCanvasSizeBox(HIT_NONE) 17 , m_ptOrig { -1, -1 } 18 { 19 m_ahbmCached[0] = m_ahbmCached[1] = NULL; 20 m_rcResizing.SetRectEmpty(); 21 } 22 23 CCanvasWindow::~CCanvasWindow() 24 { 25 if (m_ahbmCached[0]) 26 ::DeleteObject(m_ahbmCached[0]); 27 if (m_ahbmCached[1]) 28 ::DeleteObject(m_ahbmCached[1]); 29 } 30 31 RECT CCanvasWindow::GetBaseRect() 32 { 33 CRect rcBase; 34 GetImageRect(rcBase); 35 ImageToCanvas(rcBase); 36 rcBase.InflateRect(GRIP_SIZE, GRIP_SIZE); 37 return rcBase; 38 } 39 40 VOID CCanvasWindow::ImageToCanvas(POINT& pt) 41 { 42 Zoomed(pt); 43 pt.x += GRIP_SIZE - GetScrollPos(SB_HORZ); 44 pt.y += GRIP_SIZE - GetScrollPos(SB_VERT); 45 } 46 47 VOID CCanvasWindow::ImageToCanvas(RECT& rc) 48 { 49 Zoomed(rc); 50 ::OffsetRect(&rc, GRIP_SIZE - GetScrollPos(SB_HORZ), GRIP_SIZE - GetScrollPos(SB_VERT)); 51 } 52 53 VOID CCanvasWindow::CanvasToImage(POINT& pt) 54 { 55 pt.x -= GRIP_SIZE - GetScrollPos(SB_HORZ); 56 pt.y -= GRIP_SIZE - GetScrollPos(SB_VERT); 57 UnZoomed(pt); 58 } 59 60 VOID CCanvasWindow::CanvasToImage(RECT& rc) 61 { 62 ::OffsetRect(&rc, GetScrollPos(SB_HORZ) - GRIP_SIZE, GetScrollPos(SB_VERT) - GRIP_SIZE); 63 UnZoomed(rc); 64 } 65 66 VOID CCanvasWindow::GetImageRect(RECT& rc) 67 { 68 rc = { 0, 0, imageModel.GetWidth(), imageModel.GetHeight() }; 69 } 70 71 HITTEST CCanvasWindow::CanvasHitTest(POINT pt) 72 { 73 if (selectionModel.m_bShow || ::IsWindowVisible(textEditWindow)) 74 return HIT_INNER; 75 RECT rcBase = GetBaseRect(); 76 return getSizeBoxHitTest(pt, &rcBase); 77 } 78 79 VOID CCanvasWindow::getNewZoomRect(CRect& rcView, INT newZoom, CPoint ptTarget) 80 { 81 CRect rcImage; 82 GetImageRect(rcImage); 83 ImageToCanvas(rcImage); 84 85 // Calculate the zoom rectangle 86 INT oldZoom = toolsModel.GetZoom(); 87 GetClientRect(rcView); 88 LONG cxView = rcView.right * oldZoom / newZoom, cyView = rcView.bottom * oldZoom / newZoom; 89 rcView.SetRect(ptTarget.x - cxView / 2, ptTarget.y - cyView / 2, 90 ptTarget.x + cxView / 2, ptTarget.y + cyView / 2); 91 92 // Shift the rectangle if necessary 93 INT dx = 0, dy = 0; 94 if (rcView.left < rcImage.left) 95 dx = rcImage.left - rcView.left; 96 else if (rcImage.right < rcView.right) 97 dx = rcImage.right - rcView.right; 98 if (rcView.top < rcImage.top) 99 dy = rcImage.top - rcView.top; 100 else if (rcImage.bottom < rcView.bottom) 101 dy = rcImage.bottom - rcView.bottom; 102 rcView.OffsetRect(dx, dy); 103 104 rcView.IntersectRect(&rcView, &rcImage); 105 } 106 107 VOID CCanvasWindow::zoomTo(INT newZoom, LONG left, LONG top) 108 { 109 POINT pt = { left, top }; 110 CanvasToImage(pt); 111 112 toolsModel.SetZoom(newZoom); 113 ImageToCanvas(pt); 114 pt.x += GetScrollPos(SB_HORZ); 115 pt.y += GetScrollPos(SB_VERT); 116 117 updateScrollRange(); 118 updateScrollPos(pt.x, pt.y); 119 Invalidate(TRUE); 120 } 121 122 VOID CCanvasWindow::DoDraw(HDC hDC, RECT& rcClient, RECT& rcPaint) 123 { 124 // This is the target area we have to draw on 125 CRect rcCanvasDraw; 126 rcCanvasDraw.IntersectRect(&rcClient, &rcPaint); 127 128 // We use a memory bitmap to reduce flickering 129 HDC hdcMem0 = ::CreateCompatibleDC(hDC); 130 m_ahbmCached[0] = CachedBufferDIB(m_ahbmCached[0], rcClient.right, rcClient.bottom); 131 HGDIOBJ hbm0Old = ::SelectObject(hdcMem0, m_ahbmCached[0]); 132 133 // Fill the background on hdcMem0 134 ::FillRect(hdcMem0, &rcCanvasDraw, (HBRUSH)(COLOR_APPWORKSPACE + 1)); 135 136 // Draw the sizeboxes if necessary 137 RECT rcBase = GetBaseRect(); 138 if (!selectionModel.m_bShow && !::IsWindowVisible(textEditWindow)) 139 drawSizeBoxes(hdcMem0, &rcBase, FALSE, &rcCanvasDraw); 140 141 // Calculate image size 142 CRect rcImage; 143 GetImageRect(rcImage); 144 SIZE sizeImage = { imageModel.GetWidth(), imageModel.GetHeight() }; 145 146 // Calculate the target area on the image 147 CRect rcImageDraw = rcCanvasDraw; 148 CanvasToImage(rcImageDraw); 149 rcImageDraw.IntersectRect(&rcImageDraw, &rcImage); 150 151 // Consider rounding down by zooming 152 rcImageDraw.right += 1; 153 rcImageDraw.bottom += 1; 154 155 // hdcMem1 <-- imageModel 156 HDC hdcMem1 = ::CreateCompatibleDC(hDC); 157 m_ahbmCached[1] = CachedBufferDIB(m_ahbmCached[1], sizeImage.cx, sizeImage.cy); 158 HGDIOBJ hbm1Old = ::SelectObject(hdcMem1, m_ahbmCached[1]); 159 ::BitBlt(hdcMem1, rcImageDraw.left, rcImageDraw.top, rcImageDraw.Width(), rcImageDraw.Height(), 160 imageModel.GetDC(), rcImageDraw.left, rcImageDraw.top, SRCCOPY); 161 162 // Draw overlay #1 on hdcMem1 163 toolsModel.OnDrawOverlayOnImage(hdcMem1); 164 165 // Transfer the bits with stretch (hdcMem0 <-- hdcMem1) 166 ImageToCanvas(rcImage); 167 ::StretchBlt(hdcMem0, rcImage.left, rcImage.top, rcImage.Width(), rcImage.Height(), 168 hdcMem1, 0, 0, sizeImage.cx, sizeImage.cy, SRCCOPY); 169 170 // Clean up hdcMem1 171 ::SelectObject(hdcMem1, hbm1Old); 172 ::DeleteDC(hdcMem1); 173 174 // Draw the grid on hdcMem0 175 if (g_showGrid && toolsModel.GetZoom() >= 4000) 176 { 177 HPEN oldPen = (HPEN) ::SelectObject(hdcMem0, ::CreatePen(PS_SOLID, 1, RGB(160, 160, 160))); 178 for (INT counter = 0; counter < sizeImage.cy; counter++) 179 { 180 POINT pt0 = { 0, counter }, pt1 = { sizeImage.cx, counter }; 181 ImageToCanvas(pt0); 182 ImageToCanvas(pt1); 183 ::MoveToEx(hdcMem0, pt0.x, pt0.y, NULL); 184 ::LineTo(hdcMem0, pt1.x, pt1.y); 185 } 186 for (INT counter = 0; counter < sizeImage.cx; counter++) 187 { 188 POINT pt0 = { counter, 0 }, pt1 = { counter, sizeImage.cy }; 189 ImageToCanvas(pt0); 190 ImageToCanvas(pt1); 191 ::MoveToEx(hdcMem0, pt0.x, pt0.y, NULL); 192 ::LineTo(hdcMem0, pt1.x, pt1.y); 193 } 194 ::DeleteObject(::SelectObject(hdcMem0, oldPen)); 195 } 196 197 // Draw overlay #2 on hdcMem0 198 toolsModel.OnDrawOverlayOnCanvas(hdcMem0); 199 200 // Draw new frame on hdcMem0 if any 201 if (m_hitCanvasSizeBox != HIT_NONE && !m_rcResizing.IsRectEmpty()) 202 DrawXorRect(hdcMem0, &m_rcResizing); 203 204 // Transfer the bits (hDC <-- hdcMem0) 205 ::BitBlt(hDC, rcCanvasDraw.left, rcCanvasDraw.top, rcCanvasDraw.Width(), rcCanvasDraw.Height(), 206 hdcMem0, rcCanvasDraw.left, rcCanvasDraw.top, SRCCOPY); 207 208 // Clean up hdcMem0 209 ::SelectObject(hdcMem0, hbm0Old); 210 ::DeleteDC(hdcMem0); 211 } 212 213 VOID CCanvasWindow::updateScrollRange() 214 { 215 CRect rcClient; 216 GetClientRect(&rcClient); 217 218 CSize sizePage(rcClient.right, rcClient.bottom); 219 CSize sizeZoomed = { Zoomed(imageModel.GetWidth()), Zoomed(imageModel.GetHeight()) }; 220 CSize sizeWhole = { sizeZoomed.cx + (GRIP_SIZE * 2), sizeZoomed.cy + (GRIP_SIZE * 2) }; 221 222 // show/hide the scrollbars 223 ShowScrollBar(SB_HORZ, sizePage.cx < sizeWhole.cx); 224 ShowScrollBar(SB_VERT, sizePage.cy < sizeWhole.cy); 225 226 if (sizePage.cx < sizeWhole.cx || sizePage.cy < sizeWhole.cy) 227 { 228 GetClientRect(&rcClient); // Scrollbars might change, get client rectangle again 229 sizePage = CSize(rcClient.right, rcClient.bottom); 230 } 231 232 SCROLLINFO si = { sizeof(si), SIF_PAGE | SIF_RANGE }; 233 si.nMin = 0; 234 235 si.nMax = sizeWhole.cx; 236 si.nPage = sizePage.cx; 237 SetScrollInfo(SB_HORZ, &si); 238 239 si.nMax = sizeWhole.cy; 240 si.nPage = sizePage.cy; 241 SetScrollInfo(SB_VERT, &si); 242 } 243 244 VOID CCanvasWindow::updateScrollPos(INT x, INT y) 245 { 246 SetScrollPos(SB_HORZ, x); 247 SetScrollPos(SB_VERT, y); 248 } 249 250 LRESULT CCanvasWindow::OnSize(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) 251 { 252 if (m_hWnd) 253 updateScrollRange(); 254 255 return 0; 256 } 257 258 VOID CCanvasWindow::OnHVScroll(WPARAM wParam, INT fnBar) 259 { 260 SCROLLINFO si; 261 si.cbSize = sizeof(SCROLLINFO); 262 si.fMask = SIF_ALL; 263 GetScrollInfo(fnBar, &si); 264 switch (LOWORD(wParam)) 265 { 266 case SB_THUMBTRACK: 267 case SB_THUMBPOSITION: 268 si.nPos = (SHORT)HIWORD(wParam); 269 break; 270 case SB_LINELEFT: 271 si.nPos -= 5; 272 break; 273 case SB_LINERIGHT: 274 si.nPos += 5; 275 break; 276 case SB_PAGELEFT: 277 si.nPos -= si.nPage; 278 break; 279 case SB_PAGERIGHT: 280 si.nPos += si.nPage; 281 break; 282 } 283 si.nPos = max(min(si.nPos, si.nMax), si.nMin); 284 SetScrollInfo(fnBar, &si); 285 Invalidate(); 286 } 287 288 LRESULT CCanvasWindow::OnHScroll(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) 289 { 290 OnHVScroll(wParam, SB_HORZ); 291 return 0; 292 } 293 294 LRESULT CCanvasWindow::OnVScroll(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) 295 { 296 OnHVScroll(wParam, SB_VERT); 297 return 0; 298 } 299 300 LRESULT CCanvasWindow::OnButtonDown(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) 301 { 302 POINT pt = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) }; 303 304 m_nMouseDownMsg = nMsg; 305 BOOL bLeftButton = (nMsg == WM_LBUTTONDOWN); 306 307 if (nMsg == WM_MBUTTONDOWN) 308 { 309 m_ptOrig = pt; 310 SetCapture(); 311 ::SetCursor(::LoadCursorW(g_hinstExe, MAKEINTRESOURCEW(IDC_HANDDRAG))); 312 return 0; 313 } 314 315 HITTEST hitSelection = selectionModel.hitTest(pt); 316 if (hitSelection != HIT_NONE) 317 { 318 m_drawing = TRUE; 319 CanvasToImage(pt); 320 SetCapture(); 321 toolsModel.OnButtonDown(bLeftButton, pt.x, pt.y, FALSE); 322 Invalidate(); 323 return 0; 324 } 325 326 HITTEST hit = CanvasHitTest(pt); 327 if (hit == HIT_NONE || hit == HIT_BORDER) 328 { 329 switch (toolsModel.GetActiveTool()) 330 { 331 case TOOL_BEZIER: 332 case TOOL_SHAPE: 333 toolsModel.OnEndDraw(TRUE); 334 Invalidate(); 335 break; 336 337 case TOOL_FREESEL: 338 case TOOL_RECTSEL: 339 toolsModel.OnEndDraw(FALSE); 340 Invalidate(); 341 break; 342 343 default: 344 break; 345 } 346 347 toolsModel.resetTool(); // resets the point-buffer of the polygon and bezier functions 348 return 0; 349 } 350 351 CanvasToImage(pt); 352 353 if (hit == HIT_INNER) 354 { 355 m_drawing = TRUE; 356 SetCapture(); 357 toolsModel.OnButtonDown(bLeftButton, pt.x, pt.y, FALSE); 358 Invalidate(); 359 return 0; 360 } 361 362 if (bLeftButton) 363 { 364 m_hitCanvasSizeBox = hit; 365 m_ptOrig = pt; 366 SetCapture(); 367 } 368 369 return 0; 370 } 371 372 LRESULT CCanvasWindow::OnButtonDblClk(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) 373 { 374 POINT pt = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) }; 375 CanvasToImage(pt); 376 377 m_drawing = FALSE; 378 ::ReleaseCapture(); 379 m_nMouseDownMsg = 0; 380 381 toolsModel.OnButtonDown(nMsg == WM_LBUTTONDBLCLK, pt.x, pt.y, TRUE); 382 toolsModel.resetTool(); 383 Invalidate(); 384 return 0; 385 } 386 387 LRESULT CCanvasWindow::OnMouseMove(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) 388 { 389 POINT pt = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) }; 390 391 if (m_nMouseDownMsg == WM_MBUTTONDOWN) 392 { 393 INT x = GetScrollPos(SB_HORZ) - (pt.x - m_ptOrig.x); 394 INT y = GetScrollPos(SB_VERT) - (pt.y - m_ptOrig.y); 395 SendMessage(WM_HSCROLL, MAKEWPARAM(SB_THUMBPOSITION, x), 0); 396 SendMessage(WM_VSCROLL, MAKEWPARAM(SB_THUMBPOSITION, y), 0); 397 m_ptOrig = pt; 398 return 0; 399 } 400 401 CanvasToImage(pt); 402 403 if (toolsModel.GetActiveTool() == TOOL_ZOOM) 404 Invalidate(); 405 406 if (!m_drawing || toolsModel.GetActiveTool() <= TOOL_AIRBRUSH) 407 { 408 TRACKMOUSEEVENT tme = { sizeof(tme) }; 409 tme.dwFlags = TME_LEAVE; 410 tme.hwndTrack = m_hWnd; 411 tme.dwHoverTime = 0; 412 ::TrackMouseEvent(&tme); 413 414 if (!m_drawing) 415 { 416 CRect rcImage; 417 GetImageRect(rcImage); 418 419 CStringW strCoord; 420 if (rcImage.PtInRect(pt)) 421 strCoord.Format(L"%ld, %ld", pt.x, pt.y); 422 ::SendMessageW(g_hStatusBar, SB_SETTEXT, 1, (LPARAM)(LPCWSTR)strCoord); 423 } 424 } 425 426 if (m_drawing || toolsModel.IsSelection()) 427 { 428 toolsModel.DrawWithMouseTool(pt, wParam); 429 return 0; 430 } 431 432 if (m_hitCanvasSizeBox == HIT_NONE || ::GetCapture() != m_hWnd) 433 return 0; 434 435 // Dragging now... Calculate the new size 436 INT cxImage = imageModel.GetWidth(), cyImage = imageModel.GetHeight(); 437 INT cxDelta = pt.x - m_ptOrig.x; 438 INT cyDelta = pt.y - m_ptOrig.y; 439 switch (m_hitCanvasSizeBox) 440 { 441 case HIT_UPPER_LEFT: 442 cxImage -= cxDelta; 443 cyImage -= cyDelta; 444 break; 445 case HIT_UPPER_CENTER: 446 cyImage -= cyDelta; 447 break; 448 case HIT_UPPER_RIGHT: 449 cxImage += cxDelta; 450 cyImage -= cyDelta; 451 break; 452 case HIT_MIDDLE_LEFT: 453 cxImage -= cxDelta; 454 break; 455 case HIT_MIDDLE_RIGHT: 456 cxImage += cxDelta; 457 break; 458 case HIT_LOWER_LEFT: 459 cxImage -= cxDelta; 460 cyImage += cyDelta; 461 break; 462 case HIT_LOWER_CENTER: 463 cyImage += cyDelta; 464 break; 465 case HIT_LOWER_RIGHT: 466 cxImage += cxDelta; 467 cyImage += cyDelta; 468 break; 469 default: 470 return 0; 471 } 472 473 // Limit bitmap size 474 cxImage = max(1, cxImage); 475 cyImage = max(1, cyImage); 476 cxImage = min(MAXWORD, cxImage); 477 cyImage = min(MAXWORD, cyImage); 478 479 // Display new size 480 CStringW strSize; 481 strSize.Format(L"%d x %d", cxImage, cyImage); 482 ::SendMessageW(g_hStatusBar, SB_SETTEXT, 2, (LPARAM)(LPCWSTR)strSize); 483 484 // Dragging now... Fix the position... 485 CRect rcResizing = { 0, 0, cxImage, cyImage }; 486 switch (m_hitCanvasSizeBox) 487 { 488 case HIT_UPPER_LEFT: 489 rcResizing.OffsetRect(cxDelta, cyDelta); 490 break; 491 case HIT_UPPER_CENTER: 492 rcResizing.OffsetRect(0, cyDelta); 493 break; 494 case HIT_UPPER_RIGHT: 495 rcResizing.OffsetRect(0, cyDelta); 496 break; 497 case HIT_MIDDLE_LEFT: 498 rcResizing.OffsetRect(cxDelta, 0); 499 break; 500 case HIT_LOWER_LEFT: 501 rcResizing.OffsetRect(cxDelta, 0); 502 break; 503 default: 504 break; 505 } 506 ImageToCanvas(rcResizing); 507 m_rcResizing = rcResizing; 508 Invalidate(TRUE); 509 510 return 0; 511 } 512 513 LRESULT CCanvasWindow::OnButtonUp(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) 514 { 515 POINT pt = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) }; 516 CanvasToImage(pt); 517 518 ::ReleaseCapture(); 519 520 BOOL bLeftButton = (m_nMouseDownMsg == WM_LBUTTONDOWN); 521 m_nMouseDownMsg = 0; 522 523 if (m_drawing) 524 { 525 m_drawing = FALSE; 526 toolsModel.OnButtonUp(bLeftButton, pt.x, pt.y); 527 Invalidate(FALSE); 528 ::SendMessageW(g_hStatusBar, SB_SETTEXT, 2, (LPARAM)L""); 529 return 0; 530 } 531 532 if (m_hitCanvasSizeBox == HIT_NONE || !bLeftButton) 533 return 0; 534 535 // Resize the image 536 INT cxImage = imageModel.GetWidth(), cyImage = imageModel.GetHeight(); 537 INT cxDelta = pt.x - m_ptOrig.x; 538 INT cyDelta = pt.y - m_ptOrig.y; 539 switch (m_hitCanvasSizeBox) 540 { 541 case HIT_UPPER_LEFT: 542 imageModel.Crop(cxImage - cxDelta, cyImage - cyDelta, cxDelta, cyDelta); 543 break; 544 case HIT_UPPER_CENTER: 545 imageModel.Crop(cxImage, cyImage - cyDelta, 0, cyDelta); 546 break; 547 case HIT_UPPER_RIGHT: 548 imageModel.Crop(cxImage + cxDelta, cyImage - cyDelta, 0, cyDelta); 549 break; 550 case HIT_MIDDLE_LEFT: 551 imageModel.Crop(cxImage - cxDelta, cyImage, cxDelta, 0); 552 break; 553 case HIT_MIDDLE_RIGHT: 554 imageModel.Crop(cxImage + cxDelta, cyImage, 0, 0); 555 break; 556 case HIT_LOWER_LEFT: 557 imageModel.Crop(cxImage - cxDelta, cyImage + cyDelta, cxDelta, 0); 558 break; 559 case HIT_LOWER_CENTER: 560 imageModel.Crop(cxImage, cyImage + cyDelta, 0, 0); 561 break; 562 case HIT_LOWER_RIGHT: 563 imageModel.Crop(cxImage + cxDelta, cyImage + cyDelta, 0, 0); 564 break; 565 default: 566 break; 567 } 568 m_rcResizing.SetRectEmpty(); 569 570 g_imageSaved = FALSE; 571 572 m_hitCanvasSizeBox = HIT_NONE; 573 toolsModel.resetTool(); // resets the point-buffer of the polygon and bezier functions 574 updateScrollRange(); 575 Invalidate(TRUE); 576 return 0; 577 } 578 579 LRESULT CCanvasWindow::OnSetCursor(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) 580 { 581 if (CWaitCursor::IsWaiting()) 582 { 583 bHandled = FALSE; 584 return 0; 585 } 586 587 if (m_nMouseDownMsg == WM_MBUTTONDOWN) 588 { 589 ::SetCursor(::LoadCursorW(g_hinstExe, MAKEINTRESOURCEW(IDC_HANDDRAG))); 590 return 0; 591 } 592 593 POINT pt; 594 ::GetCursorPos(&pt); 595 ScreenToClient(&pt); 596 597 CRect rcClient; 598 GetClientRect(&rcClient); 599 600 if (!rcClient.PtInRect(pt)) 601 { 602 bHandled = FALSE; 603 return 0; 604 } 605 606 HITTEST hitSelection = selectionModel.hitTest(pt); 607 if (hitSelection != HIT_NONE) 608 { 609 if (!setCursorOnSizeBox(hitSelection)) 610 ::SetCursor(::LoadCursorW(NULL, (LPCWSTR)IDC_SIZEALL)); 611 return 0; 612 } 613 614 CRect rcImage; 615 GetImageRect(rcImage); 616 ImageToCanvas(rcImage); 617 618 if (rcImage.PtInRect(pt)) 619 { 620 switch (toolsModel.GetActiveTool()) 621 { 622 case TOOL_FILL: 623 ::SetCursor(::LoadCursorW(g_hinstExe, MAKEINTRESOURCEW(IDC_FILL))); 624 break; 625 case TOOL_COLOR: 626 ::SetCursor(::LoadCursorW(g_hinstExe, MAKEINTRESOURCEW(IDC_COLOR))); 627 break; 628 case TOOL_ZOOM: 629 ::SetCursor(::LoadCursorW(g_hinstExe, MAKEINTRESOURCEW(IDC_ZOOM))); 630 break; 631 case TOOL_PEN: 632 ::SetCursor(::LoadCursorW(g_hinstExe, MAKEINTRESOURCEW(IDC_PEN))); 633 break; 634 case TOOL_AIRBRUSH: 635 ::SetCursor(::LoadCursorW(g_hinstExe, MAKEINTRESOURCEW(IDC_AIRBRUSH))); 636 break; 637 default: 638 ::SetCursor(::LoadCursorW(NULL, (LPCWSTR)IDC_CROSS)); 639 } 640 return 0; 641 } 642 643 if (selectionModel.m_bShow || !setCursorOnSizeBox(CanvasHitTest(pt))) 644 bHandled = FALSE; 645 646 return 0; 647 } 648 649 LRESULT CCanvasWindow::OnKeyDown(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) 650 { 651 if (wParam == VK_ESCAPE) 652 { 653 OnEndDraw(TRUE); 654 ::ReleaseCapture(); 655 m_nMouseDownMsg = 0; 656 m_hitCanvasSizeBox = HIT_NONE; 657 m_rcResizing.SetRectEmpty(); 658 Invalidate(TRUE); 659 } 660 661 return 0; 662 } 663 664 LRESULT CCanvasWindow::OnCancelMode(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) 665 { 666 // Cancel dragging 667 m_hitCanvasSizeBox = HIT_NONE; 668 m_rcResizing.SetRectEmpty(); 669 Invalidate(TRUE); 670 return 0; 671 } 672 673 LRESULT CCanvasWindow::OnMouseWheel(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) 674 { 675 return ::SendMessageW(GetParent(), nMsg, wParam, lParam); 676 } 677 678 LRESULT CCanvasWindow::OnCaptureChanged(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) 679 { 680 ::SendMessageW(g_hStatusBar, SB_SETTEXT, 2, (LPARAM)L""); 681 return 0; 682 } 683 684 LRESULT CCanvasWindow::OnEraseBkgnd(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) 685 { 686 return TRUE; // do nothing => transparent background 687 } 688 689 LRESULT CCanvasWindow::OnPaint(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) 690 { 691 RECT rcClient; 692 GetClientRect(&rcClient); 693 694 PAINTSTRUCT ps; 695 HDC hDC = BeginPaint(&ps); 696 DoDraw(hDC, rcClient, ps.rcPaint); 697 EndPaint(&ps); 698 return 0; 699 } 700 701 VOID CCanvasWindow::OnEndDraw(BOOL bCancel) 702 { 703 m_drawing = FALSE; 704 toolsModel.OnEndDraw(bCancel); 705 Invalidate(FALSE); 706 } 707 708 LRESULT CCanvasWindow::OnCtlColorEdit(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) 709 { 710 SetTextColor((HDC)wParam, paletteModel.GetFgColor()); 711 SetBkMode((HDC)wParam, TRANSPARENT); 712 return (LRESULT)GetStockObject(NULL_BRUSH); 713 } 714 715 LRESULT CCanvasWindow::OnPaletteModelColorChanged(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) 716 { 717 imageModel.NotifyImageChanged(); 718 return 0; 719 } 720