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