1 /* 2 * PROJECT: PAINT for ReactOS 3 * LICENSE: LGPL 4 * FILE: base/applications/mspaint/canvas.cpp 5 * PURPOSE: Providing the canvas window class 6 * PROGRAMMERS: Benedikt Freisen 7 */ 8 9 #include "precomp.h" 10 11 CCanvasWindow canvasWindow; 12 13 /* FUNCTIONS ********************************************************/ 14 15 CCanvasWindow::CCanvasWindow() 16 : m_drawing(FALSE) 17 , m_hitSelection(HIT_NONE) 18 , m_whereHit(HIT_NONE) 19 , m_ptOrig { -1, -1 } 20 { 21 ::SetRectEmpty(&m_rcNew); 22 } 23 24 VOID CCanvasWindow::drawZoomFrame(INT mouseX, INT mouseY) 25 { 26 // FIXME: Draw the border of the area that is to be zoomed in 27 CRect rc; 28 GetImageRect(rc); 29 ImageToCanvas(rc); 30 31 HDC hdc = GetDC(); 32 DrawXorRect(hdc, &rc); 33 ReleaseDC(hdc); 34 } 35 36 RECT CCanvasWindow::GetBaseRect() 37 { 38 CRect rcBase; 39 GetImageRect(rcBase); 40 ImageToCanvas(rcBase); 41 ::InflateRect(&rcBase, GRIP_SIZE, GRIP_SIZE); 42 return rcBase; 43 } 44 45 VOID CCanvasWindow::ImageToCanvas(POINT& pt) 46 { 47 pt.x = Zoomed(pt.x); 48 pt.y = Zoomed(pt.y); 49 pt.x += GRIP_SIZE - GetScrollPos(SB_HORZ); 50 pt.y += GRIP_SIZE - GetScrollPos(SB_VERT); 51 } 52 53 VOID CCanvasWindow::ImageToCanvas(RECT& rc) 54 { 55 rc.left = Zoomed(rc.left); 56 rc.top = Zoomed(rc.top); 57 rc.right = Zoomed(rc.right); 58 rc.bottom = Zoomed(rc.bottom); 59 ::OffsetRect(&rc, GRIP_SIZE - GetScrollPos(SB_HORZ), GRIP_SIZE - GetScrollPos(SB_VERT)); 60 } 61 62 VOID CCanvasWindow::CanvasToImage(POINT& pt, BOOL bZoomed) 63 { 64 pt.x -= GRIP_SIZE - GetScrollPos(SB_HORZ); 65 pt.y -= GRIP_SIZE - GetScrollPos(SB_VERT); 66 if (bZoomed) 67 return; 68 pt.x = UnZoomed(pt.x); 69 pt.y = UnZoomed(pt.y); 70 } 71 72 VOID CCanvasWindow::CanvasToImage(RECT& rc, BOOL bZoomed) 73 { 74 ::OffsetRect(&rc, GetScrollPos(SB_HORZ) - GRIP_SIZE, GetScrollPos(SB_VERT) - GRIP_SIZE); 75 if (bZoomed) 76 return; 77 rc.left = UnZoomed(rc.left); 78 rc.top = UnZoomed(rc.top); 79 rc.right = UnZoomed(rc.right); 80 rc.bottom = UnZoomed(rc.bottom); 81 } 82 83 VOID CCanvasWindow::GetImageRect(RECT& rc) 84 { 85 ::SetRect(&rc, 0, 0, imageModel.GetWidth(), imageModel.GetHeight()); 86 } 87 88 CANVAS_HITTEST CCanvasWindow::CanvasHitTest(POINT pt) 89 { 90 RECT rcBase = GetBaseRect(); 91 return getSizeBoxHitTest(pt, &rcBase); 92 } 93 94 VOID CCanvasWindow::DoDraw(HDC hDC, RECT& rcClient, RECT& rcPaint) 95 { 96 // We use a memory bitmap to reduce flickering 97 HDC hdcMem = ::CreateCompatibleDC(hDC); 98 HBITMAP hbm = ::CreateCompatibleBitmap(hDC, rcClient.right, rcClient.bottom); 99 HGDIOBJ hbmOld = ::SelectObject(hdcMem, hbm); 100 101 // Fill the background 102 ::FillRect(hdcMem, &rcPaint, (HBRUSH)(COLOR_APPWORKSPACE + 1)); 103 104 // Draw the sizeboxes if necessary 105 RECT rcBase = GetBaseRect(); 106 if (!selectionModel.m_bShow) 107 drawSizeBoxes(hdcMem, &rcBase, FALSE, &rcPaint); 108 109 // Draw the image 110 CRect rcImage; 111 GetImageRect(rcImage); 112 ImageToCanvas(rcImage); 113 SIZE sizeImage = { imageModel.GetWidth(), imageModel.GetHeight() }; 114 StretchBlt(hdcMem, rcImage.left, rcImage.top, rcImage.Width(), rcImage.Height(), 115 imageModel.GetDC(), 0, 0, sizeImage.cx, sizeImage.cy, SRCCOPY); 116 117 // Draw the grid 118 if (showGrid && toolsModel.GetZoom() >= 4000) 119 { 120 HPEN oldPen = (HPEN) SelectObject(hdcMem, CreatePen(PS_SOLID, 1, RGB(160, 160, 160))); 121 for (INT counter = 0; counter < sizeImage.cy; counter++) 122 { 123 POINT pt0 = { 0, counter }, pt1 = { sizeImage.cx, counter }; 124 ImageToCanvas(pt0); 125 ImageToCanvas(pt1); 126 ::MoveToEx(hdcMem, pt0.x, pt0.y, NULL); 127 ::LineTo(hdcMem, pt1.x, pt1.y); 128 } 129 for (INT counter = 0; counter < sizeImage.cx; counter++) 130 { 131 POINT pt0 = { counter, 0 }, pt1 = { counter, sizeImage.cy }; 132 ImageToCanvas(pt0); 133 ImageToCanvas(pt1); 134 ::MoveToEx(hdcMem, pt0.x, pt0.y, NULL); 135 ::LineTo(hdcMem, pt1.x, pt1.y); 136 } 137 ::DeleteObject(::SelectObject(hdcMem, oldPen)); 138 } 139 140 // Draw selection 141 if (selectionModel.m_bShow) 142 { 143 RECT rcSelection = selectionModel.m_rc; 144 ImageToCanvas(rcSelection); 145 146 ::InflateRect(&rcSelection, GRIP_SIZE, GRIP_SIZE); 147 drawSizeBoxes(hdcMem, &rcSelection, TRUE, &rcPaint); 148 ::InflateRect(&rcSelection, -GRIP_SIZE, -GRIP_SIZE); 149 150 INT iSaveDC = ::SaveDC(hdcMem); 151 ::IntersectClipRect(hdcMem, rcImage.left, rcImage.top, rcImage.right, rcImage.bottom); 152 selectionModel.DrawSelection(hdcMem, &rcSelection, paletteModel.GetBgColor(), 153 toolsModel.IsBackgroundTransparent()); 154 ::RestoreDC(hdcMem, iSaveDC); 155 } 156 157 // Draw new frame if any 158 if (m_whereHit != HIT_NONE && !::IsRectEmpty(&m_rcNew)) 159 DrawXorRect(hdcMem, &m_rcNew); 160 161 // Transfer the bits 162 ::BitBlt(hDC, 163 rcPaint.left, rcPaint.top, 164 rcPaint.right - rcPaint.left, rcPaint.bottom - rcPaint.top, 165 hdcMem, rcPaint.left, rcPaint.top, SRCCOPY); 166 167 ::DeleteObject(::SelectObject(hdcMem, hbmOld)); 168 ::DeleteDC(hdcMem); 169 } 170 171 VOID CCanvasWindow::Update(HWND hwndFrom) 172 { 173 CRect rcClient; 174 GetClientRect(&rcClient); 175 176 CSize sizePage(rcClient.right, rcClient.bottom); 177 CSize sizeZoomed = { Zoomed(imageModel.GetWidth()), Zoomed(imageModel.GetHeight()) }; 178 CSize sizeWhole = { sizeZoomed.cx + (GRIP_SIZE * 2), sizeZoomed.cy + (GRIP_SIZE * 2) }; 179 180 // show/hide the scrollbars 181 ShowScrollBar(SB_HORZ, sizePage.cx < sizeWhole.cx); 182 ShowScrollBar(SB_VERT, sizePage.cy < sizeWhole.cy); 183 184 if (sizePage.cx < sizeWhole.cx || sizePage.cy < sizeWhole.cy) 185 { 186 GetClientRect(&rcClient); // Scrollbars might change, get client rectangle again 187 sizePage = CSize(rcClient.right, rcClient.bottom); 188 } 189 190 SCROLLINFO si = { sizeof(si), SIF_PAGE | SIF_RANGE }; 191 si.nMin = 0; 192 193 si.nMax = sizeWhole.cx; 194 si.nPage = sizePage.cx; 195 SetScrollInfo(SB_HORZ, &si); 196 197 si.nMax = sizeWhole.cy; 198 si.nPage = sizePage.cy; 199 SetScrollInfo(SB_VERT, &si); 200 } 201 202 LRESULT CCanvasWindow::OnSize(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) 203 { 204 if (m_hWnd) 205 Update(m_hWnd); 206 207 return 0; 208 } 209 210 VOID CCanvasWindow::OnHVScroll(WPARAM wParam, INT fnBar) 211 { 212 SCROLLINFO si; 213 si.cbSize = sizeof(SCROLLINFO); 214 si.fMask = SIF_ALL; 215 GetScrollInfo(fnBar, &si); 216 switch (LOWORD(wParam)) 217 { 218 case SB_THUMBTRACK: 219 case SB_THUMBPOSITION: 220 si.nPos = HIWORD(wParam); 221 break; 222 case SB_LINELEFT: 223 si.nPos -= 5; 224 break; 225 case SB_LINERIGHT: 226 si.nPos += 5; 227 break; 228 case SB_PAGELEFT: 229 si.nPos -= si.nPage; 230 break; 231 case SB_PAGERIGHT: 232 si.nPos += si.nPage; 233 break; 234 } 235 SetScrollInfo(fnBar, &si); 236 Update(m_hWnd); 237 Invalidate(FALSE); // FIXME: Flicker 238 } 239 240 LRESULT CCanvasWindow::OnHScroll(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) 241 { 242 OnHVScroll(wParam, SB_HORZ); 243 return 0; 244 } 245 246 LRESULT CCanvasWindow::OnVScroll(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) 247 { 248 OnHVScroll(wParam, SB_VERT); 249 return 0; 250 } 251 252 LRESULT CCanvasWindow::OnLRButtonDown(BOOL bLeftButton, UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) 253 { 254 POINT pt = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) }; 255 256 CANVAS_HITTEST hitSelection = SelectionHitTest(pt); 257 if (hitSelection != HIT_NONE) 258 { 259 if (bLeftButton) 260 { 261 UnZoomed(pt); 262 StartSelectionDrag(hitSelection, pt); 263 } 264 return 0; 265 } 266 267 CANVAS_HITTEST hit = CanvasHitTest(pt); 268 if (hit == HIT_NONE || hit == HIT_BORDER) 269 { 270 switch (toolsModel.GetActiveTool()) 271 { 272 case TOOL_BEZIER: 273 case TOOL_SHAPE: 274 toolsModel.OnCancelDraw(); 275 canvasWindow.Invalidate(); 276 break; 277 278 case TOOL_FREESEL: 279 case TOOL_RECTSEL: 280 toolsModel.OnFinishDraw(); 281 canvasWindow.Invalidate(); 282 break; 283 284 default: 285 break; 286 } 287 288 toolsModel.resetTool(); // resets the point-buffer of the polygon and bezier functions 289 return 0; 290 } 291 292 CanvasToImage(pt, TRUE); 293 294 if (hit == HIT_INNER) 295 { 296 m_drawing = TRUE; 297 UnZoomed(pt); 298 SetCapture(); 299 toolsModel.OnButtonDown(bLeftButton, pt.x, pt.y, FALSE); 300 Invalidate(FALSE); 301 return 0; 302 } 303 304 if (bLeftButton) 305 { 306 m_whereHit = hit; 307 UnZoomed(pt); 308 m_ptOrig = pt; 309 SetCapture(); 310 } 311 return 0; 312 } 313 314 LRESULT CCanvasWindow::OnLButtonDown(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) 315 { 316 return OnLRButtonDown(TRUE, nMsg, wParam, lParam, bHandled); 317 } 318 319 LRESULT CCanvasWindow::OnRButtonDown(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) 320 { 321 return OnLRButtonDown(FALSE, nMsg, wParam, lParam, bHandled); 322 } 323 324 LRESULT CCanvasWindow::OnLRButtonDblClk(BOOL bLeftButton, UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) 325 { 326 POINT pt = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) }; 327 CanvasToImage(pt); 328 329 m_drawing = FALSE; 330 ReleaseCapture(); 331 332 toolsModel.OnButtonDown(bLeftButton, pt.x, pt.y, TRUE); 333 toolsModel.resetTool(); 334 Invalidate(FALSE); 335 return 0; 336 } 337 338 LRESULT CCanvasWindow::OnLButtonDblClk(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) 339 { 340 return OnLRButtonDblClk(TRUE, nMsg, wParam, lParam, bHandled); 341 } 342 343 LRESULT CCanvasWindow::OnRButtonDblClk(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) 344 { 345 return OnLRButtonDblClk(FALSE, nMsg, wParam, lParam, bHandled); 346 } 347 348 LRESULT CCanvasWindow::OnMouseMove(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) 349 { 350 POINT pt = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) }; 351 CanvasToImage(pt); 352 353 if (m_hitSelection != HIT_NONE) 354 { 355 SelectionDragging(pt); 356 return 0; 357 } 358 359 if (!m_drawing || toolsModel.GetActiveTool() <= TOOL_AIRBRUSH) 360 { 361 if (toolsModel.GetActiveTool() == TOOL_ZOOM) 362 { 363 Invalidate(FALSE); 364 UpdateWindow(); 365 CanvasToImage(pt); 366 drawZoomFrame(pt.x, pt.y); 367 } 368 369 TRACKMOUSEEVENT tme = { sizeof(tme) }; 370 tme.dwFlags = TME_LEAVE; 371 tme.hwndTrack = m_hWnd; 372 tme.dwHoverTime = 0; 373 ::TrackMouseEvent(&tme); 374 375 if (!m_drawing) 376 { 377 CString strCoord; 378 strCoord.Format(_T("%ld, %ld"), pt.x, pt.y); 379 SendMessage(hStatusBar, SB_SETTEXT, 1, (LPARAM) (LPCTSTR) strCoord); 380 } 381 } 382 383 if (m_drawing) 384 { 385 // values displayed in statusbar 386 LONG xRel = pt.x - start.x; 387 LONG yRel = pt.y - start.y; 388 389 switch (toolsModel.GetActiveTool()) 390 { 391 // freesel, rectsel and text tools always show numbers limited to fit into image area 392 case TOOL_FREESEL: 393 case TOOL_RECTSEL: 394 case TOOL_TEXT: 395 if (xRel < 0) 396 xRel = (pt.x < 0) ? -start.x : xRel; 397 else if (pt.x > imageModel.GetWidth()) 398 xRel = imageModel.GetWidth() - start.x; 399 if (yRel < 0) 400 yRel = (pt.y < 0) ? -start.y : yRel; 401 else if (pt.y > imageModel.GetHeight()) 402 yRel = imageModel.GetHeight() - start.y; 403 break; 404 405 // while drawing, update cursor coordinates only for tools 3, 7, 8, 9, 14 406 case TOOL_RUBBER: 407 case TOOL_PEN: 408 case TOOL_BRUSH: 409 case TOOL_AIRBRUSH: 410 case TOOL_SHAPE: 411 { 412 CString strCoord; 413 strCoord.Format(_T("%ld, %ld"), pt.x, pt.y); 414 SendMessage(hStatusBar, SB_SETTEXT, 1, (LPARAM) (LPCTSTR) strCoord); 415 break; 416 } 417 default: 418 break; 419 } 420 421 // rectsel and shape tools always show non-negative numbers when drawing 422 if (toolsModel.GetActiveTool() == TOOL_RECTSEL || toolsModel.GetActiveTool() == TOOL_SHAPE) 423 { 424 if (xRel < 0) 425 xRel = -xRel; 426 if (yRel < 0) 427 yRel = -yRel; 428 } 429 430 if (wParam & MK_LBUTTON) 431 { 432 toolsModel.OnMouseMove(TRUE, pt.x, pt.y); 433 Invalidate(FALSE); 434 if ((toolsModel.GetActiveTool() >= TOOL_TEXT) || (toolsModel.GetActiveTool() == TOOL_RECTSEL) || (toolsModel.GetActiveTool() == TOOL_FREESEL)) 435 { 436 CString strSize; 437 if ((toolsModel.GetActiveTool() >= TOOL_LINE) && (GetAsyncKeyState(VK_SHIFT) < 0)) 438 yRel = xRel; 439 strSize.Format(_T("%ld x %ld"), xRel, yRel); 440 SendMessage(hStatusBar, SB_SETTEXT, 2, (LPARAM) (LPCTSTR) strSize); 441 } 442 } 443 444 if (wParam & MK_RBUTTON) 445 { 446 toolsModel.OnMouseMove(FALSE, pt.x, pt.y); 447 Invalidate(FALSE); 448 if (toolsModel.GetActiveTool() >= TOOL_TEXT) 449 { 450 CString strSize; 451 if ((toolsModel.GetActiveTool() >= TOOL_LINE) && (GetAsyncKeyState(VK_SHIFT) < 0)) 452 yRel = xRel; 453 strSize.Format(_T("%ld x %ld"), xRel, yRel); 454 SendMessage(hStatusBar, SB_SETTEXT, 2, (LPARAM) (LPCTSTR) strSize); 455 } 456 } 457 return 0; 458 } 459 460 if (m_whereHit == HIT_NONE || ::GetCapture() != m_hWnd) 461 return 0; 462 463 // Dragging now... Calculate the new size 464 INT cxImage = imageModel.GetWidth(), cyImage = imageModel.GetHeight(); 465 INT cxDelta = pt.x - m_ptOrig.x; 466 INT cyDelta = pt.y - m_ptOrig.y; 467 switch (m_whereHit) 468 { 469 case HIT_UPPER_LEFT: 470 cxImage -= cxDelta; 471 cyImage -= cyDelta; 472 break; 473 case HIT_UPPER_CENTER: 474 cyImage -= cyDelta; 475 break; 476 case HIT_UPPER_RIGHT: 477 cxImage += cxDelta; 478 cyImage -= cyDelta; 479 break; 480 case HIT_MIDDLE_LEFT: 481 cxImage -= cxDelta; 482 break; 483 case HIT_MIDDLE_RIGHT: 484 cxImage += cxDelta; 485 break; 486 case HIT_LOWER_LEFT: 487 cxImage -= cxDelta; 488 cyImage += cyDelta; 489 break; 490 case HIT_LOWER_CENTER: 491 cyImage += cyDelta; 492 break; 493 case HIT_LOWER_RIGHT: 494 cxImage += cxDelta; 495 cyImage += cyDelta; 496 break; 497 default: 498 return 0; 499 } 500 501 // Limit bitmap size 502 cxImage = max(1, cxImage); 503 cyImage = max(1, cyImage); 504 cxImage = min(MAXWORD, cxImage); 505 cyImage = min(MAXWORD, cyImage); 506 507 // Display new size 508 CString strSize; 509 strSize.Format(_T("%d x %d"), cxImage, cyImage); 510 SendMessage(hStatusBar, SB_SETTEXT, 2, (LPARAM) (LPCTSTR) strSize); 511 512 CRect rc = { 0, 0, cxImage, cyImage }; 513 switch (m_whereHit) 514 { 515 case HIT_UPPER_LEFT: 516 ::OffsetRect(&rc, cxDelta, cyDelta); 517 break; 518 case HIT_UPPER_CENTER: 519 ::OffsetRect(&rc, 0, cyDelta); 520 break; 521 case HIT_UPPER_RIGHT: 522 ::OffsetRect(&rc, 0, cyDelta); 523 break; 524 case HIT_MIDDLE_LEFT: 525 ::OffsetRect(&rc, cxDelta, 0); 526 break; 527 case HIT_LOWER_LEFT: 528 ::OffsetRect(&rc, cxDelta, 0); 529 break; 530 default: 531 break; 532 } 533 ImageToCanvas(rc); 534 m_rcNew = rc; 535 Invalidate(TRUE); 536 537 return 0; 538 } 539 540 LRESULT CCanvasWindow::OnLRButtonUp(BOOL bLeftButton, UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) 541 { 542 POINT pt = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) }; 543 CanvasToImage(pt); 544 545 ::ReleaseCapture(); 546 547 if (m_drawing) 548 { 549 m_drawing = FALSE; 550 toolsModel.OnButtonUp(bLeftButton, pt.x, pt.y); 551 Invalidate(FALSE); 552 SendMessage(hStatusBar, SB_SETTEXT, 2, (LPARAM) ""); 553 return 0; 554 } 555 else if (m_hitSelection != HIT_NONE && bLeftButton) 556 { 557 EndSelectionDrag(pt); 558 return 0; 559 } 560 561 if (m_whereHit == HIT_NONE || !bLeftButton) 562 return 0; 563 564 // Resize the image 565 INT cxImage = imageModel.GetWidth(), cyImage = imageModel.GetHeight(); 566 INT cxDelta = pt.x - m_ptOrig.x; 567 INT cyDelta = pt.y - m_ptOrig.y; 568 switch (m_whereHit) 569 { 570 case HIT_UPPER_LEFT: 571 imageModel.Crop(cxImage - cxDelta, cyImage - cyDelta, cxDelta, cyDelta); 572 break; 573 case HIT_UPPER_CENTER: 574 imageModel.Crop(cxImage, cyImage - cyDelta, 0, cyDelta); 575 break; 576 case HIT_UPPER_RIGHT: 577 imageModel.Crop(cxImage + cxDelta, cyImage - cyDelta, 0, cyDelta); 578 break; 579 case HIT_MIDDLE_LEFT: 580 imageModel.Crop(cxImage - cxDelta, cyImage, cxDelta, 0); 581 break; 582 case HIT_MIDDLE_RIGHT: 583 imageModel.Crop(cxImage + cxDelta, cyImage, 0, 0); 584 break; 585 case HIT_LOWER_LEFT: 586 imageModel.Crop(cxImage - cxDelta, cyImage + cyDelta, cxDelta, 0); 587 break; 588 case HIT_LOWER_CENTER: 589 imageModel.Crop(cxImage, cyImage + cyDelta, 0, 0); 590 break; 591 case HIT_LOWER_RIGHT: 592 imageModel.Crop(cxImage + cxDelta, cyImage + cyDelta, 0, 0); 593 break; 594 default: 595 break; 596 } 597 ::SetRectEmpty(&m_rcNew); 598 599 imageSaved = FALSE; 600 601 m_whereHit = HIT_NONE; 602 toolsModel.resetTool(); // resets the point-buffer of the polygon and bezier functions 603 Update(NULL); 604 Invalidate(TRUE); 605 return 0; 606 } 607 608 LRESULT CCanvasWindow::OnLButtonUp(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) 609 { 610 return OnLRButtonUp(TRUE, nMsg, wParam, lParam, bHandled); 611 } 612 613 LRESULT CCanvasWindow::OnRButtonUp(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) 614 { 615 return OnLRButtonUp(FALSE, nMsg, wParam, lParam, bHandled); 616 } 617 618 LRESULT CCanvasWindow::OnSetCursor(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) 619 { 620 POINT pt; 621 ::GetCursorPos(&pt); 622 ScreenToClient(&pt); 623 624 CANVAS_HITTEST hitSelection = SelectionHitTest(pt); 625 if (hitSelection != HIT_NONE) 626 { 627 if (!setCursorOnSizeBox(hitSelection)) 628 ::SetCursor(::LoadCursor(NULL, IDC_SIZEALL)); 629 return 0; 630 } 631 632 CRect rcImage; 633 GetImageRect(rcImage); 634 ImageToCanvas(rcImage); 635 if (::PtInRect(&rcImage, pt)) 636 { 637 switch (toolsModel.GetActiveTool()) 638 { 639 case TOOL_FILL: 640 ::SetCursor(::LoadIcon(hProgInstance, MAKEINTRESOURCE(IDC_FILL))); 641 break; 642 case TOOL_COLOR: 643 ::SetCursor(::LoadIcon(hProgInstance, MAKEINTRESOURCE(IDC_COLOR))); 644 break; 645 case TOOL_ZOOM: 646 ::SetCursor(::LoadIcon(hProgInstance, MAKEINTRESOURCE(IDC_ZOOM))); 647 break; 648 case TOOL_PEN: 649 ::SetCursor(::LoadIcon(hProgInstance, MAKEINTRESOURCE(IDC_PEN))); 650 break; 651 case TOOL_AIRBRUSH: 652 ::SetCursor(::LoadIcon(hProgInstance, MAKEINTRESOURCE(IDC_AIRBRUSH))); 653 break; 654 default: 655 ::SetCursor(::LoadCursor(NULL, IDC_CROSS)); 656 } 657 return 0; 658 } 659 660 if (selectionModel.m_bShow || !setCursorOnSizeBox(CanvasHitTest(pt))) 661 ::SetCursor(::LoadCursor(NULL, IDC_ARROW)); 662 663 return 0; 664 } 665 666 LRESULT CCanvasWindow::OnKeyDown(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) 667 { 668 if (wParam == VK_ESCAPE && ::GetCapture() == m_hWnd) 669 { 670 // Cancel dragging 671 ::ReleaseCapture(); 672 m_whereHit = HIT_NONE; 673 ::SetRectEmpty(&m_rcNew); 674 Invalidate(TRUE); 675 } 676 677 return 0; 678 } 679 680 LRESULT CCanvasWindow::OnCancelMode(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) 681 { 682 // Cancel dragging 683 m_whereHit = HIT_NONE; 684 ::SetRectEmpty(&m_rcNew); 685 Invalidate(TRUE); 686 return 0; 687 } 688 689 LRESULT CCanvasWindow::OnMouseWheel(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) 690 { 691 return ::SendMessage(GetParent(), nMsg, wParam, lParam); 692 } 693 694 LRESULT CCanvasWindow::OnCaptureChanged(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) 695 { 696 SendMessage(hStatusBar, SB_SETTEXT, 2, (LPARAM)_T("")); 697 return 0; 698 } 699 700 LRESULT CCanvasWindow::OnEraseBkgnd(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) 701 { 702 return TRUE; // do nothing => transparent background 703 } 704 705 LRESULT CCanvasWindow::OnPaint(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) 706 { 707 RECT rcClient; 708 GetClientRect(&rcClient); 709 710 PAINTSTRUCT ps; 711 HDC hDC = BeginPaint(&ps); 712 DoDraw(hDC, rcClient, ps.rcPaint); 713 EndPaint(&ps); 714 return 0; 715 } 716 717 VOID CCanvasWindow::cancelDrawing() 718 { 719 selectionModel.ClearColor(); 720 selectionModel.ClearMask(); 721 m_hitSelection = HIT_NONE; 722 m_drawing = FALSE; 723 toolsModel.OnCancelDraw(); 724 Invalidate(FALSE); 725 } 726 727 VOID CCanvasWindow::finishDrawing() 728 { 729 toolsModel.OnFinishDraw(); 730 m_drawing = FALSE; 731 Invalidate(FALSE); 732 } 733 734 CANVAS_HITTEST CCanvasWindow::SelectionHitTest(POINT ptZoomed) 735 { 736 if (!selectionModel.m_bShow) 737 return HIT_NONE; 738 739 RECT rcSelection = selectionModel.m_rc; 740 Zoomed(rcSelection); 741 ::OffsetRect(&rcSelection, GRIP_SIZE - GetScrollPos(SB_HORZ), GRIP_SIZE - GetScrollPos(SB_VERT)); 742 ::InflateRect(&rcSelection, GRIP_SIZE, GRIP_SIZE); 743 744 return getSizeBoxHitTest(ptZoomed, &rcSelection); 745 } 746 747 VOID CCanvasWindow::StartSelectionDrag(CANVAS_HITTEST hit, POINT ptUnZoomed) 748 { 749 m_hitSelection = hit; 750 selectionModel.m_ptHit = ptUnZoomed; 751 selectionModel.TakeOff(); 752 753 SetCapture(); 754 Invalidate(FALSE); 755 } 756 757 VOID CCanvasWindow::SelectionDragging(POINT ptUnZoomed) 758 { 759 selectionModel.Dragging(m_hitSelection, ptUnZoomed); 760 Invalidate(FALSE); 761 } 762 763 VOID CCanvasWindow::EndSelectionDrag(POINT ptUnZoomed) 764 { 765 selectionModel.Dragging(m_hitSelection, ptUnZoomed); 766 m_hitSelection = HIT_NONE; 767 Invalidate(FALSE); 768 } 769