|
|
1.1 ! root 1: /*************************************************************************** ! 2: * * ! 3: * MODULE : WorkWP.c * ! 4: * * ! 5: * DESCRIPTION : Functions controlling the workspace window. * ! 6: * * ! 7: * HISTORY : 6/21/89 LR * ! 8: * * ! 9: ***************************************************************************/ ! 10: ! 11: #include "imagedit.h" ! 12: ! 13: #include <stdlib.h> ! 14: ! 15: ! 16: /* ! 17: * This structure is used in conjunction with DeltaGenInit() and DeltaGen(). ! 18: */ ! 19: typedef struct _DELTAGEN { /* dg */ ! 20: BOOL fSwap; ! 21: INT xf; ! 22: INT yf; ! 23: INT dx; ! 24: INT dy; ! 25: INT d; ! 26: INT incx; ! 27: INT incy; ! 28: INT inc1; ! 29: INT inc2; ! 30: } DELTAGEN; ! 31: typedef DELTAGEN *PDELTAGEN; ! 32: ! 33: ! 34: STATICFN VOID NEAR WorkPaint(HWND hwnd); ! 35: STATICFN VOID WorkButtonDown(HWND hwnd, UINT msg, PPOINT ppt); ! 36: STATICFN VOID WorkButtonMouseMove(HWND hwnd, UINT msg, PPOINT ppt); ! 37: STATICFN VOID WorkButtonUp(HWND hwnd, UINT msg, PPOINT ppt); ! 38: STATICFN VOID NEAR SnapPointToGrid(PPOINT ppt); ! 39: STATICFN VOID DrawToPoint(HWND hwnd, PPOINT ppt, BOOL fBrush); ! 40: STATICFN BOOL NEAR DeltaGenInit(PDELTAGEN pdg, INT x0, INT y0, ! 41: INT xf, INT yf, PINT px, PINT py); ! 42: STATICFN BOOL NEAR DeltaGen(PDELTAGEN pdg, PINT px, PINT py); ! 43: STATICFN VOID DrawPoint(HWND hwnd, PPOINT ppt, BOOL fBrush); ! 44: STATICFN VOID NEAR RubberBandLine(BOOL fFirstTime); ! 45: STATICFN VOID NEAR RectDPDraw(HWND hwnd); ! 46: STATICFN VOID NEAR RubberBandRect(BOOL fFirstTime); ! 47: STATICFN VOID NEAR CircleDPDraw(HWND hwnd); ! 48: STATICFN VOID NEAR RubberBandCircle(BOOL fFirstTime); ! 49: STATICFN VOID NEAR MarkHotSpotPosition(INT x, INT y); ! 50: STATICFN VOID NEAR StartRubberBanding(HWND hwnd); ! 51: STATICFN VOID NEAR EndRubberBanding(HWND hwnd); ! 52: ! 53: ! 54: static BOOL fDrawing = FALSE; // TRUE if mouse button is down. ! 55: static BOOL fLeftButtonDown; // TRUE if left button was pressed. ! 56: static POINT ptStart; // Saves the starting point. ! 57: static POINT ptEnd; // Saves the ending point. ! 58: static POINT ptPrev; // Saves the previous point. ! 59: static HDC hdcRubberBand; // DC used during rubber banding. ! 60: static BOOL fRubberBanding = FALSE; // Tracking is in progress. ! 61: ! 62: ! 63: ! 64: /**************************************************************************** ! 65: * WorkWndProc ! 66: * * ! 67: * purpose: Processes basic create and size and paint messages for the * ! 68: * workspace window. ! 69: * * ! 70: ****************************************************************************/ ! 71: ! 72: WINDOWPROC WorkWndProc( ! 73: HWND hwnd, ! 74: UINT msg, ! 75: WPARAM wParam, ! 76: LPARAM lParam) ! 77: { ! 78: LPCREATESTRUCT cs; ! 79: POINT pt; ! 80: ! 81: switch (msg) { ! 82: case WM_CREATE: ! 83: /* set up image variables */ ! 84: cs = (LPCREATESTRUCT)lParam; ! 85: gcxWorkSpace = cs->cx; ! 86: gcyWorkSpace = cs->cy; ! 87: break; ! 88: ! 89: case WM_SIZE: ! 90: gcxWorkSpace = LOWORD(lParam); ! 91: gcyWorkSpace = HIWORD(lParam); ! 92: ! 93: break; ! 94: ! 95: case WM_PAINT: ! 96: WorkPaint(hwnd); ! 97: break; ! 98: ! 99: case WM_MOUSEMOVE: ! 100: ((pt).x = ((*((POINTS *)&(lParam)))).x, (pt).y = ((*((POINTS *)&(lParam)))).y); ! 101: WorkButtonMouseMove(hwnd, msg, &pt); ! 102: break; ! 103: ! 104: case WM_RBUTTONDOWN: ! 105: case WM_LBUTTONDOWN: ! 106: ((pt).x = ((*((POINTS *)&(lParam)))).x, (pt).y = ((*((POINTS *)&(lParam)))).y); ! 107: WorkButtonDown(hwnd, msg, &pt); ! 108: break; ! 109: ! 110: case WM_LBUTTONUP: ! 111: case WM_RBUTTONUP: ! 112: ((pt).x = ((*((POINTS *)&(lParam)))).x, (pt).y = ((*((POINTS *)&(lParam)))).y); ! 113: WorkButtonUp(hwnd, msg, &pt); ! 114: break; ! 115: ! 116: case WM_KEYDOWN: ! 117: switch (wParam) { ! 118: case VK_ESCAPE: ! 119: if (fDrawing) { ! 120: if (fRubberBanding) { ! 121: EndRubberBanding(hwnd); ! 122: WorkUpdate(); ! 123: } ! 124: ! 125: PropBarClearSize(); ! 126: ReleaseCapture(); ! 127: fDrawing = FALSE; ! 128: } ! 129: ! 130: break; ! 131: } ! 132: ! 133: break; ! 134: ! 135: default: ! 136: return DefWindowProc(hwnd, msg, wParam, lParam); ! 137: } ! 138: ! 139: return 0; ! 140: } ! 141: ! 142: ! 143: ! 144: /**************************************************************************** ! 145: * WorkPaint ! 146: * ! 147: * Handles WM_PAINT for the workspace window. ! 148: * ! 149: * History: ! 150: * ! 151: ****************************************************************************/ ! 152: ! 153: STATICFN VOID NEAR WorkPaint( HWND hwnd) ! 154: { ! 155: register INT i; ! 156: PAINTSTRUCT ps; ! 157: HCURSOR hcurOld; ! 158: HDC hdcTemp; ! 159: HBITMAP hbmTemp; ! 160: ! 161: hcurOld = SetCursor(hcurWait); ! 162: BeginPaint(hwnd, &ps); ! 163: ! 164: /* ! 165: * Do they want a grid and is there enough room to show the lines? ! 166: */ ! 167: if (gfGrid && gZoomFactor > 1) { ! 168: /* ! 169: * Stretch the bits onto a temporary DC. ! 170: */ ! 171: hdcTemp = CreateCompatibleDC(ghdcImage); ! 172: hbmTemp = CreateCompatibleBitmap(ghdcImage, ! 173: gcxWorkSpace, gcyWorkSpace); ! 174: SelectObject(hdcTemp, hbmTemp); ! 175: StretchBlt(hdcTemp, 0, 0, gcxWorkSpace, gcyWorkSpace, ! 176: ghdcImage, 0, 0, gcxImage, gcyImage, SRCCOPY); ! 177: ! 178: /* ! 179: * Draw the grid lines on the temp DC. ! 180: */ ! 181: for (i = gZoomFactor - 1; i < gcxWorkSpace; i += gZoomFactor) ! 182: PatBlt(hdcTemp, i, 0, 1, gcyWorkSpace, BLACKNESS); ! 183: for (i = gZoomFactor - 1; i < gcyWorkSpace; i += gZoomFactor) ! 184: PatBlt(hdcTemp, 0, i, gcxWorkSpace, 1, BLACKNESS); ! 185: ! 186: /* ! 187: * Copy the bits to the screen. ! 188: */ ! 189: BitBlt(ps.hdc, 0, 0, gcxWorkSpace, gcyWorkSpace, ! 190: hdcTemp, 0, 0, SRCCOPY); ! 191: ! 192: DeleteDC(hdcTemp); ! 193: DeleteObject(hbmTemp); ! 194: } ! 195: else { ! 196: /* ! 197: * No grid. Just stretch the image to the screen. ! 198: */ ! 199: StretchBlt(ps.hdc, 0, 0, gcxWorkSpace, gcyWorkSpace, ! 200: ghdcImage, 0, 0, gcxImage, gcyImage, SRCCOPY); ! 201: } ! 202: ! 203: EndPaint(hwnd, &ps); ! 204: SetCursor(hcurOld); ! 205: } ! 206: ! 207: ! 208: ! 209: /**************************************************************************** ! 210: * WorkUpdate ! 211: * ! 212: * This function updates the workspace window. ! 213: * ! 214: * History: ! 215: * ! 216: ****************************************************************************/ ! 217: ! 218: VOID WorkUpdate(VOID) ! 219: { ! 220: /* ! 221: * Invalidate the workspace window. Because the image will be ! 222: * be blt'ed onto it, we do not need to force the background to ! 223: * be cleared first. ! 224: */ ! 225: InvalidateRect(ghwndWork, NULL, FALSE); ! 226: } ! 227: ! 228: ! 229: ! 230: /**************************************************************************** ! 231: * WorkReset ! 232: * ! 233: * This function reset the workspace window. It should be called ! 234: * any time that a new image is loaded (because the size could ! 235: * change) or the size of the main window changes (because the ! 236: * workspace window needs to be resized to fit). ! 237: * ! 238: * History: ! 239: * ! 240: ****************************************************************************/ ! 241: ! 242: VOID WorkReset(VOID) ! 243: { ! 244: RECT rcClient; ! 245: INT cx; ! 246: INT cy; ! 247: INT xScale; ! 248: INT yScale; ! 249: INT cxBorder; ! 250: INT cyBorder; ! 251: ! 252: cxBorder = GetSystemMetrics(SM_CXBORDER); ! 253: cyBorder = GetSystemMetrics(SM_CYBORDER); ! 254: ! 255: if (!gcxImage || !gcyImage) { ! 256: gZoomFactor = 1; ! 257: } ! 258: else { ! 259: GetClientRect(ghwndMain, &rcClient); ! 260: cx = rcClient.right - (2 * PALETTEMARGIN) - (2 * cxBorder); ! 261: cy = rcClient.bottom - (2 * PALETTEMARGIN) - (2 * cyBorder) - ! 262: gcyPropBar; ! 263: ! 264: xScale = cx / gcxImage; ! 265: yScale = cy / gcyImage; ! 266: ! 267: if (xScale > 0 && yScale > 0) ! 268: gZoomFactor = min(xScale, yScale); ! 269: else ! 270: gZoomFactor = 1; ! 271: } ! 272: ! 273: SetWindowPos(ghwndWork, NULL, ! 274: PALETTEMARGIN, PALETTEMARGIN + gcyPropBar, ! 275: (gZoomFactor * gcxImage) + (2 * cxBorder), ! 276: (gZoomFactor * gcyImage) + (2 * cyBorder), ! 277: SWP_NOACTIVATE | SWP_NOZORDER); ! 278: WorkUpdate(); ! 279: } ! 280: ! 281: ! 282: ! 283: /************************************************************************ ! 284: * WorkButtonDown ! 285: * ! 286: * ! 287: * ! 288: * Arguments: ! 289: * ! 290: * History: ! 291: * ! 292: ************************************************************************/ ! 293: ! 294: STATICFN VOID WorkButtonDown( ! 295: HWND hwnd, ! 296: UINT msg, ! 297: PPOINT ppt) ! 298: { ! 299: /* ! 300: * If the other button is already down, just ignore this one. ! 301: */ ! 302: if (fDrawing) ! 303: return; ! 304: ! 305: SetFocus(hwnd); ! 306: fLeftButtonDown = (msg == WM_LBUTTONDOWN) ? TRUE : FALSE; ! 307: ! 308: SnapPointToGrid(ppt); ! 309: ptStart = ptPrev = ptEnd = *ppt; ! 310: ! 311: if (fLeftButtonDown) { ! 312: ghbrDraw = ghbrLeft; ! 313: ghbrDrawSolid = ghbrLeftSolid; ! 314: gfDrawMode = gfModeLeft; ! 315: ghpenDraw = ghpenLeft; ! 316: } ! 317: else { ! 318: ghbrDraw = ghbrRight; ! 319: ghbrDrawSolid = ghbrRightSolid; ! 320: gfDrawMode = gfModeRight; ! 321: ghpenDraw = ghpenRight; ! 322: } ! 323: ! 324: /* ! 325: * If this tool draws on the down-click, update the undo ! 326: * buffer now. ! 327: */ ! 328: if (gaTools[gCurTool].fDrawOnDown) ! 329: ImageUpdateUndo(); ! 330: ! 331: SetCapture(ghwndWork); ! 332: fDrawing = TRUE; ! 333: ! 334: (*gpfnDrawProc)(hwnd, msg, *ppt); ! 335: ! 336: PropBarSetSize(ptStart, ptEnd); ! 337: } ! 338: ! 339: ! 340: ! 341: /************************************************************************ ! 342: * WorkButtonMouseMove ! 343: * ! 344: * ! 345: * ! 346: * Arguments: ! 347: * ! 348: * History: ! 349: * ! 350: ************************************************************************/ ! 351: ! 352: STATICFN VOID WorkButtonMouseMove( ! 353: HWND hwnd, ! 354: UINT msg, ! 355: PPOINT ppt) ! 356: { ! 357: static POINT ptNZLast; // Saves the last point (non-zoomed). ! 358: POINT ptNZ; ! 359: ! 360: SetCursor(gaTools[gCurTool].hcur); ! 361: ! 362: SnapPointToGrid(ppt); ! 363: ! 364: /* ! 365: * Calculate the point as it would be on the actual image ! 366: * (non-zoomed). ! 367: */ ! 368: ptNZ.x = ppt->x / gZoomFactor; ! 369: ptNZ.y = ppt->y / gZoomFactor; ! 370: ! 371: /* ! 372: * Only call the drawing proc if the point changed enough to ! 373: * jump over a zoomed pixels width (it jumped a grid square). ! 374: * This prevents calling the DrawProc for a mouse move of ! 375: * a single pixel (unless the zoom factor is 1, of course). ! 376: */ ! 377: if (ptNZLast.x != ptNZ.x || ptNZLast.y != ptNZ.y) { ! 378: ptEnd = *ppt; ! 379: (*gpfnDrawProc)(hwnd, msg, *ppt); ! 380: ptPrev = ptEnd; ! 381: ! 382: PropBarSetPos(ptNZ.x, ptNZ.y); ! 383: ! 384: if (fDrawing) ! 385: PropBarSetSize(ptStart, ptEnd); ! 386: ! 387: ptNZLast = ptNZ; ! 388: } ! 389: } ! 390: ! 391: ! 392: ! 393: /************************************************************************ ! 394: * WorkButtonUp ! 395: * ! 396: * ! 397: * ! 398: * Arguments: ! 399: * ! 400: * History: ! 401: * ! 402: ************************************************************************/ ! 403: ! 404: STATICFN VOID WorkButtonUp( ! 405: HWND hwnd, ! 406: UINT msg, ! 407: PPOINT ppt) ! 408: { ! 409: /* ! 410: * Pass this on to the draw procs, but only if we are still drawing. ! 411: * The drawing could have been cancelled by the Escape key, in ! 412: * which case we just ignore the button up message. ! 413: */ ! 414: if (fDrawing) { ! 415: SnapPointToGrid(ppt); ! 416: ! 417: /* ! 418: * If this tool draws on the up-click, update the undo ! 419: * buffer now. ! 420: */ ! 421: if (gaTools[gCurTool].fDrawOnUp) ! 422: ImageUpdateUndo(); ! 423: ! 424: (*gpfnDrawProc)(hwnd, msg, *ppt); ! 425: ! 426: ReleaseCapture(); ! 427: fDrawing = FALSE; ! 428: } ! 429: } ! 430: ! 431: ! 432: ! 433: /****************************************************************************** ! 434: * SnapPointToGrid ! 435: * ! 436: * PURPOSE : Snap the current mouse coordinate to the nearest grid intersection. ! 437: * ! 438: * PARAMS : PPOINT ppt : current mouse coordinates ! 439: * ! 440: *****************************************************************************/ ! 441: ! 442: STATICFN VOID NEAR SnapPointToGrid( ! 443: PPOINT ppt) ! 444: { ! 445: /* ! 446: * Scale the point down (this gridizes it at the same time). ! 447: */ ! 448: ppt->x = ppt->x / gZoomFactor; ! 449: ppt->y = ppt->y / gZoomFactor; ! 450: ! 451: /* ! 452: * Limit the point to within the image. ! 453: */ ! 454: if (ppt->x < 0) ! 455: ppt->x = 0; ! 456: ! 457: if (ppt->y < 0) ! 458: ppt->y = 0; ! 459: ! 460: if (ppt->x >= gcxImage) ! 461: ppt->x = gcxImage - 1; ! 462: ! 463: if (ppt->y >= gcyImage) ! 464: ppt->y = gcyImage - 1; ! 465: ! 466: /* ! 467: * Finally, scale it back up to the workspace window size. ! 468: */ ! 469: ppt->x *= gZoomFactor; ! 470: ppt->y *= gZoomFactor; ! 471: } ! 472: ! 473: ! 474: ! 475: /************************************************************************ ! 476: * PencilDP ! 477: * ! 478: * ! 479: * ! 480: * Arguments: ! 481: * ! 482: * History: ! 483: * ! 484: ************************************************************************/ ! 485: ! 486: VOID PencilDP( ! 487: HWND hwnd, ! 488: UINT msg, ! 489: POINT ptNew) ! 490: { ! 491: switch (msg) { ! 492: case WM_LBUTTONDOWN: ! 493: case WM_RBUTTONDOWN: ! 494: DrawPoint(hwnd, &ptNew, FALSE); ! 495: break; ! 496: ! 497: case WM_MOUSEMOVE: ! 498: if (fDrawing) ! 499: DrawToPoint(hwnd, &ptNew, FALSE); ! 500: ! 501: break; ! 502: } ! 503: } ! 504: ! 505: ! 506: ! 507: /************************************************************************ ! 508: * BrushDP ! 509: * ! 510: * ! 511: * ! 512: * Arguments: ! 513: * ! 514: * History: ! 515: * ! 516: ************************************************************************/ ! 517: ! 518: VOID BrushDP( ! 519: HWND hwnd, ! 520: UINT msg, ! 521: POINT ptNew) ! 522: { ! 523: switch (msg) { ! 524: case WM_LBUTTONDOWN: ! 525: case WM_RBUTTONDOWN: ! 526: DrawPoint(hwnd, &ptNew, TRUE); ! 527: break; ! 528: ! 529: case WM_MOUSEMOVE: ! 530: if (fDrawing) ! 531: DrawToPoint(hwnd, &ptNew, TRUE); ! 532: ! 533: break; ! 534: } ! 535: } ! 536: ! 537: ! 538: ! 539: /************************************************************************ ! 540: * DrawToPoint ! 541: * ! 542: * This function draws from the previous point to the given point. ! 543: * This includes all points between. ! 544: * ! 545: * The global ptPrev must have been initialized prior to the first time ! 546: * this function is called during a drawing operation. ! 547: * ! 548: * Arguments: ! 549: * ! 550: * History: ! 551: * ! 552: ************************************************************************/ ! 553: ! 554: STATICFN VOID DrawToPoint( ! 555: HWND hwnd, ! 556: PPOINT ppt, ! 557: BOOL fBrush) ! 558: { ! 559: DELTAGEN dg; ! 560: BOOL fContinue; ! 561: POINT pt; ! 562: INT x; ! 563: INT y; ! 564: ! 565: x = ppt->x / gZoomFactor; ! 566: y = ppt->y / gZoomFactor; ! 567: DeltaGenInit(&dg, ptPrev.x / gZoomFactor, ptPrev.y / gZoomFactor, ! 568: ppt->x / gZoomFactor, ppt->y / gZoomFactor, &x, &y); ! 569: do { ! 570: pt.x = x * gZoomFactor; ! 571: pt.y = y * gZoomFactor; ! 572: DrawPoint(hwnd, &pt, fBrush); ! 573: fContinue = DeltaGen(&dg, &x, &y); ! 574: } while (fContinue); ! 575: } ! 576: ! 577: ! 578: ! 579: /***************************** Public Function ****************************\ ! 580: * DeltaGenInit ! 581: * ! 582: * This routine initializes the pdg, px and py in preparation for using ! 583: * DeltaGen(). Returns fContinue. ! 584: * ! 585: * Algorithm derived from BRESENHAM line algorighm on p. 435 of Fund. of ! 586: * interactive computer graphics, Foley/VanDam, addison-wesley 1983. ! 587: * ! 588: * History: ! 589: * 3/7/89 sanfords created ! 590: \***************************************************************************/ ! 591: ! 592: STATICFN BOOL NEAR DeltaGenInit( ! 593: PDELTAGEN pdg, ! 594: INT x0, ! 595: INT y0, ! 596: INT xf, ! 597: INT yf, ! 598: PINT px, ! 599: PINT py) ! 600: { ! 601: INT nT; ! 602: ! 603: pdg->xf = xf; ! 604: pdg->yf = yf; ! 605: ! 606: if (x0 == xf && y0 == yf) ! 607: return FALSE; ! 608: ! 609: if (xf >= x0) ! 610: pdg->incx = 1; ! 611: else ! 612: pdg->incx = -1; ! 613: ! 614: if (yf >= y0) pdg->incy = 1; ! 615: else ! 616: pdg->incy = -1; ! 617: ! 618: pdg->dx = (xf - x0) * pdg->incx; ! 619: pdg->dy = (yf - y0) * pdg->incy; ! 620: ! 621: if (pdg->dy > pdg->dx) { ! 622: nT = pdg->dy; ! 623: pdg->dy = pdg->dx; ! 624: pdg->dx = nT; ! 625: nT = pdg->incx; ! 626: pdg->incx = pdg->incy; ! 627: pdg->incy = nT; ! 628: pdg->fSwap = TRUE; ! 629: } ! 630: else { ! 631: pdg->fSwap = FALSE; ! 632: } ! 633: ! 634: pdg->inc1 = pdg->dy * 2; ! 635: pdg->inc2 = (pdg->dy - pdg->dx) * 2; ! 636: pdg->d = pdg->inc1 - pdg->dx; ! 637: ! 638: pdg->xf = xf; ! 639: pdg->yf = yf; ! 640: ! 641: *px = x0; ! 642: *py = y0; ! 643: ! 644: return TRUE; ! 645: } ! 646: ! 647: ! 648: ! 649: /***************************** Public Function ****************************\ ! 650: * DeltaGen ! 651: * ! 652: * This routine generates the next coordinates for px,py assuming that this ! 653: * point is proceeding linearly from x0,y0 to xf, yf. It returns FALSE only ! 654: * if *px == xf and *py == yf on entry. (ie returns fContinue) pdg should ! 655: * have been previously set by DeltaGenInit(). ! 656: * ! 657: * Algorithm derived from BRESENHAM line algorighm on p. 435 of Fund. of ! 658: * interactive computer graphics, Foley/VanDam, addison-wesley 1983. ! 659: * ! 660: * History: ! 661: * 3/7/89 sanfords created ! 662: \***************************************************************************/ ! 663: ! 664: STATICFN BOOL NEAR DeltaGen( ! 665: PDELTAGEN pdg, ! 666: PINT px, ! 667: PINT py) ! 668: { ! 669: PINT pnT; ! 670: ! 671: if ((*px == pdg->xf) && (*py == pdg->yf)) ! 672: return FALSE; ! 673: ! 674: if (pdg->fSwap) { ! 675: pnT = px; ! 676: px = py; ! 677: py = pnT; ! 678: } ! 679: ! 680: *px += pdg->incx; ! 681: if (pdg->d < 0) { ! 682: pdg->d += pdg->inc1; ! 683: } ! 684: else { ! 685: *py += pdg->incy; ! 686: pdg->d += pdg->inc2; ! 687: } ! 688: ! 689: return TRUE; ! 690: } ! 691: ! 692: ! 693: ! 694: /************************************************************************ ! 695: * DrawPoint ! 696: * ! 697: * This function is called to draw a point on the image. It is used ! 698: * by the Pencil and Brush tools. ! 699: * ! 700: * Arguments: ! 701: * ! 702: * History: ! 703: * ! 704: ************************************************************************/ ! 705: ! 706: STATICFN VOID DrawPoint( HWND hwnd, ! 707: PPOINT ppt, ! 708: BOOL fBrush) ! 709: { ! 710: HDC hDC; ! 711: HBRUSH hbrOld; ! 712: INT wx; ! 713: INT wy; ! 714: INT iStartY; ! 715: INT wStep; ! 716: INT i; ! 717: INT j; ! 718: INT nBrushSize; ! 719: ! 720: if (ppt->x < 0 || ppt->y < 0) ! 721: return; ! 722: ! 723: hDC = GetDC(hwnd); ! 724: ! 725: /* ! 726: * If this is a point from the brush tool, use the current ! 727: * brush width. Otherwise, draw a single pixel point. ! 728: */ ! 729: if (fBrush) ! 730: nBrushSize = gnBrushSize; ! 731: else ! 732: nBrushSize = 1; ! 733: ! 734: /* * Determine some starting factors, then draw the point in ! 735: * the workspace window. ! 736: */ ! 737: hbrOld = SelectObject(hDC, ghbrDrawSolid); ! 738: wy = iStartY = ppt->y - (ppt->y % gZoomFactor) ! 739: -(nBrushSize / 2) * gZoomFactor; ! 740: wx = ppt->x - (ppt->x % gZoomFactor) ! 741: -(nBrushSize / 2) * gZoomFactor; ! 742: wStep = gZoomFactor; ! 743: ! 744: if (gfGrid && gZoomFactor > 1) ! 745: wStep -= 1; ! 746: ! 747: for (i = 0; i < nBrushSize; i++, wx += gZoomFactor) { ! 748: wy = iStartY; ! 749: for (j = 0; j < nBrushSize; j++, wy += gZoomFactor) ! 750: PatBlt(hDC, wx, wy, wStep, wStep, PATCOPY); ! 751: } ! 752: ! 753: SelectObject(hDC, hbrOld); ! 754: ReleaseDC(hwnd, hDC); ! 755: ! 756: /* ! 757: * Set the point in the bitmap directly as an optimization. ! 758: */ ! 759: wx = ppt->x / gZoomFactor; ! 760: wy = ppt->y / gZoomFactor; ! 761: if (wx < gcxImage && wy < gcyImage) { ! 762: hbrOld = SelectObject(ghdcImage, ghbrDrawSolid); ! 763: PatBlt(ghdcImage, wx - nBrushSize / 2, wy - nBrushSize / 2, ! 764: nBrushSize, nBrushSize, PATCOPY); ! 765: ! 766: if (giType != FT_BITMAP) { ! 767: /* ! 768: * If in color mode, set the mask bits black. Otherwise make ! 769: * them white. ! 770: */ ! 771: PatBlt(ghdcANDMask, wx - nBrushSize / 2, wy - nBrushSize / 2, ! 772: nBrushSize, nBrushSize, ! 773: (gfDrawMode == MODE_COLOR) ? BLACKNESS : WHITENESS); ! 774: } ! 775: ! 776: SelectObject(ghdcImage, hbrOld); ! 777: ! 778: /* ! 779: * Draw the point in the view window directly as an optimization. ! 780: */ ! 781: if (ghwndView) ! 782: ViewSetPixel(wx, wy, nBrushSize); ! 783: } ! 784: ! 785: /* ! 786: * Mark the image as changed. ! 787: */ ! 788: fImageDirty = TRUE; ! 789: } ! 790: ! 791: ! 792: ! 793: /************************************************************************ ! 794: * PickDP ! 795: * ! 796: * Drawing proc that selects a rectangular portion of the image. ! 797: * It updates the global picking rectangle. ! 798: * ! 799: * Arguments: ! 800: * ! 801: * History: ! 802: * ! 803: ************************************************************************/ ! 804: ! 805: VOID PickDP( ! 806: HWND hwnd, ! 807: UINT msg, ! 808: POINT ptNew) ! 809: { ! 810: POINT ptTL; // Top-Left point. ! 811: POINT ptBR; // Bottom-Right point ! 812: ! 813: switch (msg) { ! 814: case WM_LBUTTONDOWN: ! 815: case WM_RBUTTONDOWN: ! 816: /* erase any previous ghost rectangle */ ! 817: WorkUpdate(); ! 818: UpdateWindow(ghwndWork); ! 819: ! 820: /* ! 821: * Initialize the pick rectangle to cover the entire screen. ! 822: */ ! 823: PickSetRect(0, 0, gcxImage - 1, gcyImage - 1); ! 824: ! 825: StartRubberBanding(hwnd); ! 826: RubberBandRect(TRUE); ! 827: break; ! 828: ! 829: case WM_MOUSEMOVE: ! 830: if (fRubberBanding) ! 831: RubberBandRect(FALSE); ! 832: ! 833: break; ! 834: ! 835: case WM_LBUTTONUP: ! 836: case WM_RBUTTONUP: ! 837: EndRubberBanding(hwnd); ! 838: ! 839: /* ! 840: * Flip the points (if needed) and scale down. ! 841: */ ! 842: ptTL = ptStart; ! 843: ptBR = ptEnd; ! 844: NormalizePoints(&ptTL, &ptBR); ! 845: ptTL.x /= gZoomFactor; ! 846: ptTL.y /= gZoomFactor; ! 847: ptBR.x /= gZoomFactor; ! 848: ptBR.y /= gZoomFactor; ! 849: ! 850: PickSetRect(ptTL.x, ptTL.y, ptBR.x, ptBR.y); ! 851: ! 852: break; ! 853: } ! 854: } ! 855: ! 856: ! 857: ! 858: /****************************************************************************** ! 859: * VOID LineDP(hwnd, msg, ptNew) ! 860: * ! 861: * PURPOSE: Draw a straight line according to tracking line. ! 862: * ! 863: * PARAMS : HWND hwnd : handle to dest. DC ! 864: * unsigned msg : Upper left corner of rect; ! 865: * POINT ptNew : end pt. of line ! 866: * ! 867: * SIDE EFFECTS: may change bits in image DC ! 868: * ! 869: *****************************************************************************/ ! 870: ! 871: VOID LineDP( ! 872: HWND hwnd, ! 873: UINT msg, ! 874: POINT ptNew) ! 875: { ! 876: INT sx; ! 877: INT sy; ! 878: INT ex; ! 879: INT ey; ! 880: HPEN hpen; ! 881: HPEN hpenOld; ! 882: HBRUSH hbrOld; ! 883: ! 884: switch (msg) { ! 885: case WM_RBUTTONDOWN: ! 886: case WM_LBUTTONDOWN: ! 887: StartRubberBanding(hwnd); ! 888: RubberBandLine(TRUE); ! 889: break; ! 890: ! 891: case WM_MOUSEMOVE: ! 892: if (fRubberBanding) ! 893: RubberBandLine(FALSE); ! 894: ! 895: break; ! 896: ! 897: case WM_LBUTTONUP: ! 898: case WM_RBUTTONUP: ! 899: EndRubberBanding(hwnd); ! 900: ! 901: /* transform selected coordinates to those of actual image */ ! 902: sx = ptStart.x / gZoomFactor; ! 903: sy = ptStart.y / gZoomFactor; ! 904: ex = ptEnd.x / gZoomFactor; ! 905: ey = ptEnd.y / gZoomFactor; ! 906: ! 907: hpenOld = SelectObject(ghdcImage, ghpenDraw); ! 908: MoveToEx(ghdcImage, sx, sy, NULL); ! 909: LineTo(ghdcImage, ex, ey); ! 910: SelectObject(ghdcImage, hpenOld); ! 911: ! 912: if (giType != FT_BITMAP) { ! 913: /* for icons and cursors draw the line on the AND DC (memory) ! 914: * in black (if in color mode) or white (otherwise) ! 915: */ ! 916: hpen = CreatePen(PS_INSIDEFRAME, 1, ! 917: (gfDrawMode == MODE_COLOR) ? RGB_BLACK : RGB_WHITE); ! 918: hpenOld = SelectObject(ghdcANDMask, hpen); ! 919: hbrOld = SelectObject(ghdcANDMask, GetStockObject(NULL_BRUSH)); ! 920: MoveToEx(ghdcANDMask, sx, sy, NULL); ! 921: LineTo(ghdcANDMask, ex, ey); ! 922: SelectObject(ghdcANDMask, hbrOld); ! 923: SelectObject(ghdcANDMask, hpenOld); ! 924: DeleteObject(hpen); ! 925: } ! 926: ! 927: /* ! 928: * Because the LineTo function does not draw the ending ! 929: * point, we must do it manually here. ! 930: */ ! 931: DrawPoint(hwnd, &ptEnd, FALSE); ! 932: ! 933: fImageDirty = TRUE; ! 934: ! 935: ViewUpdate(); ! 936: ! 937: break; ! 938: } ! 939: } ! 940: ! 941: ! 942: ! 943: /************************************************************************ ! 944: * RubberBandLine ! 945: * ! 946: * This function erases the old line and draws the new tracking line ! 947: * when using the "Line" tool. ! 948: * ! 949: * Arguments: ! 950: * BOOL fFirstTime - TRUE if starting to track the line (it doesn't ! 951: * need to erase the old line). ! 952: * ! 953: * History: ! 954: * ! 955: ************************************************************************/ ! 956: ! 957: STATICFN VOID NEAR RubberBandLine( ! 958: BOOL fFirstTime) ! 959: { ! 960: INT nOffset; ! 961: ! 962: /* ! 963: * Set the raster-op to invert. ! 964: */ ! 965: SetROP2(hdcRubberBand, R2_NOT); ! 966: ! 967: /* ! 968: * If we are magnifying the image at all, the line needs to be ! 969: * slightly offset so that it will be draw exactly in between ! 970: * the grid lines. ! 971: */ ! 972: if (gZoomFactor > 1) ! 973: nOffset = -1; ! 974: else ! 975: nOffset = 0; ! 976: ! 977: if (!fFirstTime) { ! 978: /* ! 979: * Erase the old line. ! 980: */ ! 981: ! 982: MoveToEx(hdcRubberBand, ptStart.x + (gZoomFactor / 2) + nOffset, ptStart.y + (gZoomFactor / 2) + nOffset, NULL); ! 983: LineTo(hdcRubberBand, ptPrev.x + (gZoomFactor / 2) + nOffset, ! 984: ptPrev.y + (gZoomFactor / 2) + nOffset); ! 985: } ! 986: ! 987: /* ! 988: * Draw the new one. ! 989: */ ! 990: ! 991: MoveToEx(hdcRubberBand, ptStart.x + (gZoomFactor / 2) + nOffset, ptStart.y + (gZoomFactor / 2) + nOffset, NULL); ! 992: LineTo(hdcRubberBand, ptEnd.x + (gZoomFactor / 2) + nOffset, ! 993: ptEnd.y + (gZoomFactor / 2) + nOffset); ! 994: } ! 995: ! 996: ! 997: ! 998: /****************************************************************************** ! 999: * VOID RectDP(hwnd, msg, ptNew) ! 1000: * ! 1001: * PURPOSE: Draw a rectangle (filled/hollow) in the area specified ! 1002: * ! 1003: * PARAMS : HWND hwnd : handle to dest. DC ! 1004: * WORD msg : ! 1005: * POINT ptNew : end pt. of line ! 1006: * ! 1007: * SIDE EFFECTS: may change bits in image DC ! 1008: * ! 1009: *****************************************************************************/ ! 1010: ! 1011: VOID RectDP( ! 1012: HWND hwnd, ! 1013: UINT msg, ! 1014: POINT ptNew) ! 1015: { ! 1016: switch (msg) { ! 1017: case WM_RBUTTONDOWN: ! 1018: case WM_LBUTTONDOWN: ! 1019: StartRubberBanding(hwnd); ! 1020: RubberBandRect(TRUE); ! 1021: break; ! 1022: ! 1023: case WM_MOUSEMOVE: ! 1024: if (fRubberBanding) ! 1025: RubberBandRect(FALSE); ! 1026: ! 1027: break; ! 1028: ! 1029: case WM_LBUTTONUP: ! 1030: case WM_RBUTTONUP: ! 1031: RectDPDraw(hwnd); ! 1032: break; ! 1033: } ! 1034: } ! 1035: ! 1036: ! 1037: ! 1038: /************************************************************************ ! 1039: * RectDPDraw ! 1040: * ! 1041: * Does the final drawing of a rectangle when using the Rectangle tool. ! 1042: * ! 1043: * Arguments: ! 1044: * HWND hwnd - Window handle to the workspace. ! 1045: * ! 1046: * History: ! 1047: * ! 1048: ************************************************************************/ ! 1049: ! 1050: STATICFN VOID NEAR RectDPDraw( ! 1051: HWND hwnd) ! 1052: { ! 1053: POINT ptTL; // Top-Left point. ! 1054: POINT ptBR; // Bottom-Right point ! 1055: HBRUSH hbr; ! 1056: HBRUSH hbrOld; ! 1057: HPEN hpen; ! 1058: HPEN hpenOld; ! 1059: INT nOutset; ! 1060: ! 1061: EndRubberBanding(hwnd); ! 1062: ! 1063: /* ! 1064: * Flip the points (if needed) and scale down. ! 1065: */ ! 1066: ptTL = ptStart; ! 1067: ptBR = ptEnd; ! 1068: NormalizePoints(&ptTL, &ptBR); ! 1069: ptTL.x /= gZoomFactor; ! 1070: ptTL.y /= gZoomFactor; ! 1071: ptBR.x /= gZoomFactor; ! 1072: ptBR.y /= gZoomFactor; ! 1073: ! 1074: if (gCurTool == TOOL_RECT) { ! 1075: hpen = ghpenDraw; ! 1076: hbr = GetStockObject(NULL_BRUSH); ! 1077: nOutset = 1; ! 1078: } ! 1079: else { ! 1080: hpen = GetStockObject(NULL_PEN); ! 1081: hbr = ghbrDraw; ! 1082: nOutset = 2; ! 1083: } ! 1084: ! 1085: hpenOld = SelectObject(ghdcImage, hpen); ! 1086: hbrOld = SelectObject(ghdcImage, hbr); ! 1087: Rectangle(ghdcImage, ptTL.x, ptTL.y, ! 1088: ptBR.x + nOutset, ptBR.y + nOutset); ! 1089: SelectObject(ghdcImage, hpenOld); ! 1090: SelectObject(ghdcImage, hbrOld); ! 1091: ! 1092: if (giType != FT_BITMAP) { ! 1093: /* for icons and cursors draw the shape on the AND DC (memory) ! 1094: * in black (if in color mode) or white (otherwise) ! 1095: */ ! 1096: if (gCurTool == TOOL_RECT) { ! 1097: hpen = CreatePen(PS_INSIDEFRAME, 1, ! 1098: (gfDrawMode == MODE_COLOR) ? RGB_BLACK : RGB_WHITE); ! 1099: hbr = GetStockObject(NULL_BRUSH); ! 1100: } ! 1101: else { ! 1102: hpen = GetStockObject(NULL_PEN); ! 1103: hbr = GetStockObject((gfDrawMode == MODE_COLOR) ? ! 1104: BLACK_BRUSH : WHITE_BRUSH); ! 1105: } ! 1106: ! 1107: hpenOld = SelectObject(ghdcANDMask, hpen); ! 1108: hbrOld = SelectObject(ghdcANDMask, hbr); ! 1109: Rectangle(ghdcANDMask, ptTL.x, ptTL.y, ! 1110: ptBR.x + nOutset, ptBR.y + nOutset); ! 1111: SelectObject(ghdcANDMask, hpenOld); ! 1112: SelectObject(ghdcANDMask, hbrOld); ! 1113: ! 1114: if (gCurTool == TOOL_RECT) ! 1115: DeleteObject(hpen); ! 1116: } ! 1117: ! 1118: fImageDirty = TRUE; ! 1119: ! 1120: ViewUpdate(); ! 1121: } ! 1122: ! 1123: ! 1124: ! 1125: /****************************************************************************** ! 1126: * VOID PASCAL RubberBandRect() ! 1127: * ! 1128: * PURPOSE: Draw rubberbanding rect. ! 1129: * ! 1130: * PARAMS : HANDLE hDst : handle to dest. DC ! 1131: * ! 1132: *****************************************************************************/ ! 1133: ! 1134: STATICFN VOID NEAR RubberBandRect( ! 1135: BOOL fFirstTime) ! 1136: { ! 1137: POINT ptTL; // Top-Left point. ! 1138: POINT ptBR; // Bottom-Right point ! 1139: ! 1140: /* ! 1141: * Set the raster-op to invert. ! 1142: */ ! 1143: SetROP2(hdcRubberBand, R2_NOT); ! 1144: ! 1145: if (!fFirstTime) { ! 1146: /* ! 1147: * Erase the old rectangle. ! 1148: */ ! 1149: ptTL = ptStart; ! 1150: ptBR = ptPrev; ! 1151: NormalizePoints(&ptTL, &ptBR); ! 1152: Rectangle(hdcRubberBand, ptTL.x, ptTL.y, ! 1153: ptBR.x + gZoomFactor, ptBR.y + gZoomFactor); ! 1154: } ! 1155: ! 1156: ! 1157: /* ! 1158: * Draw the new one. ! 1159: */ ! 1160: ptTL = ptStart; ! 1161: ptBR = ptEnd; ! 1162: NormalizePoints(&ptTL, &ptBR); ! 1163: Rectangle(hdcRubberBand, ptTL.x, ptTL.y, ! 1164: ptBR.x + gZoomFactor, ptBR.y + gZoomFactor); ! 1165: } ! 1166: ! 1167: ! 1168: ! 1169: /****************************************************************************** ! 1170: * VOID CircleDP(hwnd, msg, ptNew) ! 1171: * ! 1172: * PURPOSE: Draw an ellipse (filled/hollow) in the area specified. ! 1173: * ! 1174: * PARAMS : HWND hwnd : handle to dest. DC ! 1175: * unsigned msg : Upper left corner of rect; ! 1176: * POINT ptNew : end pt. of line ! 1177: * ! 1178: * SIDE EFFECTS: may change bits in image DC ! 1179: * ! 1180: *****************************************************************************/ ! 1181: ! 1182: VOID CircleDP( ! 1183: HWND hwnd, ! 1184: UINT msg, ! 1185: POINT ptNew) ! 1186: { ! 1187: switch (msg) { ! 1188: case WM_RBUTTONDOWN: ! 1189: case WM_LBUTTONDOWN: ! 1190: StartRubberBanding(hwnd); ! 1191: RubberBandCircle(TRUE); ! 1192: break; ! 1193: ! 1194: case WM_MOUSEMOVE: ! 1195: if (fRubberBanding) ! 1196: RubberBandCircle(FALSE); ! 1197: ! 1198: break; ! 1199: ! 1200: case WM_LBUTTONUP: ! 1201: case WM_RBUTTONUP: ! 1202: CircleDPDraw(hwnd); ! 1203: break; ! 1204: } ! 1205: } ! 1206: ! 1207: ! 1208: ! 1209: /************************************************************************ ! 1210: * CircleDPDraw ! 1211: * ! 1212: * Does the final drawing of an ellipse when using the Ellipse tool. ! 1213: * ! 1214: * Arguments: ! 1215: * HWND hwnd - Window handle to the workspace. ! 1216: * ! 1217: * History: ! 1218: * ! 1219: ************************************************************************/ ! 1220: ! 1221: STATICFN VOID NEAR CircleDPDraw( ! 1222: HWND hwnd) ! 1223: { ! 1224: POINT ptTL; // Top-Left point. ! 1225: POINT ptBR; // Bottom-Right point ! 1226: HBRUSH hbr; ! 1227: HBRUSH hbrOld; ! 1228: HPEN hpen; ! 1229: HPEN hpenOld; ! 1230: INT nOutset; ! 1231: ! 1232: EndRubberBanding(hwnd); ! 1233: ! 1234: /* ! 1235: * Flip the points (if needed) and scale down. ! 1236: */ ! 1237: ptTL = ptStart; ! 1238: ptBR = ptEnd; ! 1239: NormalizePoints(&ptTL, &ptBR); ! 1240: ptTL.x /= gZoomFactor; ! 1241: ptTL.y /= gZoomFactor; ! 1242: ptBR.x /= gZoomFactor; ! 1243: ptBR.y /= gZoomFactor; ! 1244: ! 1245: #ifdef WIN16 ! 1246: /* ! 1247: * The win 3.x code does not properly draw an ellipse if it ! 1248: * has a NULL pen selected in (to not draw the border). For ! 1249: * this platform, we must select in the drawing pen. This is ! 1250: * not necessary for NT (we can use a NULL pen to avoid ! 1251: * drawing the solid border). ! 1252: */ ! 1253: ! 1254: if (gCurTool == TOOL_CIRCLE) ! 1255: hbr = GetStockObject(NULL_BRUSH); ! 1256: else ! 1257: hbr = ghbrDraw; ! 1258: ! 1259: hpenOld = SelectObject(ghdcImage, ghpenDraw); ! 1260: hbrOld = SelectObject(ghdcImage, hbr); ! 1261: Ellipse(ghdcImage, ptTL.x, ptTL.y, ptBR.x + 1, ptBR.y + 1); ! 1262: SelectObject(ghdcImage, hbrOld); ! 1263: SelectObject(ghdcImage, hpenOld); ! 1264: ! 1265: if (giType != FT_BITMAP) { ! 1266: /* for icons and cursors draw the shape on the AND DC (memory) ! 1267: * in black (if in color mode) or white (otherwise) ! 1268: */ ! 1269: hpen = CreatePen(PS_INSIDEFRAME, 1, ! 1270: (gfDrawMode == MODE_COLOR) ? RGB_BLACK : RGB_WHITE); ! 1271: ! 1272: if (gCurTool == TOOL_CIRCLE) ! 1273: hbr = GetStockObject(NULL_BRUSH); ! 1274: else ! 1275: hbr = GetStockObject((gfDrawMode == MODE_COLOR) ? ! 1276: BLACK_BRUSH : WHITE_BRUSH); ! 1277: ! 1278: hpenOld = SelectObject(ghdcANDMask, hpen); ! 1279: hbrOld = SelectObject(ghdcANDMask, hbr); ! 1280: Ellipse(ghdcANDMask, ptTL.x, ptTL.y, ptBR.x + 1, ptBR.y + 1); ! 1281: SelectObject(ghdcANDMask, hpenOld); ! 1282: SelectObject(ghdcANDMask, hbrOld); ! 1283: DeleteObject(hpen); ! 1284: } ! 1285: ! 1286: #else ! 1287: ! 1288: if (gCurTool == TOOL_CIRCLE) { ! 1289: hpen = ghpenDraw; ! 1290: hbr = GetStockObject(NULL_BRUSH); ! 1291: nOutset = 1; ! 1292: } ! 1293: else { ! 1294: hpen = GetStockObject(NULL_PEN); ! 1295: hbr = ghbrDraw; ! 1296: nOutset = 2; ! 1297: } ! 1298: ! 1299: hpenOld = SelectObject(ghdcImage, hpen); ! 1300: hbrOld = SelectObject(ghdcImage, hbr); ! 1301: Ellipse(ghdcImage, ptTL.x, ptTL.y, ptBR.x + nOutset, ptBR.y + nOutset); ! 1302: SelectObject(ghdcImage, hpenOld); ! 1303: SelectObject(ghdcImage, hbrOld); ! 1304: ! 1305: if (giType != FT_BITMAP) { ! 1306: /* for icons and cursors draw the shape on the AND DC (memory) ! 1307: * in black (if in color mode) or white (otherwise) ! 1308: */ ! 1309: if (gCurTool == TOOL_CIRCLE) { ! 1310: hpen = CreatePen(PS_INSIDEFRAME, 1, ! 1311: (gfDrawMode == MODE_COLOR) ? RGB_BLACK : RGB_WHITE); ! 1312: hbr = GetStockObject(NULL_BRUSH); ! 1313: } ! 1314: else { ! 1315: hpen = GetStockObject(NULL_PEN); ! 1316: hbr = GetStockObject((gfDrawMode == MODE_COLOR) ? ! 1317: BLACK_BRUSH : WHITE_BRUSH); ! 1318: } ! 1319: ! 1320: hpenOld = SelectObject(ghdcANDMask, hpen); ! 1321: hbrOld = SelectObject(ghdcANDMask, hbr); ! 1322: Ellipse(ghdcANDMask, ptTL.x, ptTL.y, ptBR.x + nOutset, ptBR.y + nOutset); ! 1323: SelectObject(ghdcANDMask, hpenOld); ! 1324: SelectObject(ghdcANDMask, hbrOld); ! 1325: ! 1326: if (gCurTool == TOOL_CIRCLE) ! 1327: DeleteObject(hpen); ! 1328: } ! 1329: ! 1330: #endif ! 1331: ! 1332: fImageDirty = TRUE; ! 1333: ! 1334: ViewUpdate(); ! 1335: } ! 1336: ! 1337: ! 1338: ! 1339: /****************************************************************************** ! 1340: * VOID PASCAL RubberBandCircle() ! 1341: * ! 1342: * PURPOSE: Draw rubberbanding circle ! 1343: * ! 1344: * ! 1345: *****************************************************************************/ ! 1346: ! 1347: STATICFN VOID NEAR RubberBandCircle( ! 1348: BOOL fFirstTime) ! 1349: { ! 1350: POINT ptTL; // Top-Left point. ! 1351: POINT ptBR; // Bottom-Right point ! 1352: ! 1353: /* ! 1354: * Set the raster-op to invert. ! 1355: */ ! 1356: SetROP2(hdcRubberBand, R2_NOT); ! 1357: ! 1358: if (!fFirstTime) { ! 1359: /* ! 1360: * Erase the old circle. ! 1361: */ ! 1362: ptTL = ptStart; ! 1363: ptBR = ptPrev; ! 1364: NormalizePoints(&ptTL, &ptBR); ! 1365: Ellipse(hdcRubberBand, ptTL.x, ptTL.y, ! 1366: ptBR.x + gZoomFactor, ptBR.y + gZoomFactor); ! 1367: } ! 1368: ! 1369: ! 1370: /* ! 1371: * Draw the new one. ! 1372: */ ! 1373: ptTL = ptStart; ! 1374: ptBR = ptEnd; ! 1375: NormalizePoints(&ptTL, &ptBR); ! 1376: Ellipse(hdcRubberBand, ptTL.x, ptTL.y, ! 1377: ptBR.x + gZoomFactor, ptBR.y + gZoomFactor); ! 1378: } ! 1379: ! 1380: ! 1381: ! 1382: /************************************************************************ ! 1383: * FloodDP ! 1384: * ! 1385: * ! 1386: * ! 1387: * Arguments: ! 1388: * ! 1389: * History: ! 1390: * ! 1391: ************************************************************************/ ! 1392: ! 1393: VOID FloodDP( ! 1394: HWND hwnd, ! 1395: UINT msg, ! 1396: POINT ptNew) ! 1397: { ! 1398: HDC dc; ! 1399: HDC bwdc; ! 1400: HBRUSH hbrOld; ! 1401: HBITMAP bwbit; ! 1402: HCURSOR hcurSave; ! 1403: ! 1404: switch (msg) { ! 1405: case WM_RBUTTONDOWN: ! 1406: case WM_LBUTTONDOWN: ! 1407: hcurSave = SetCursor(hcurWait); ! 1408: ! 1409: dc = GetDC(hwnd); ! 1410: /* create temporary DC */ ! 1411: bwdc = CreateCompatibleDC(dc); ! 1412: ! 1413: /* create temporary monochrome bitmap */ ! 1414: if (!(bwbit = CreateBitmap(gcxImage, gcyImage, 1, 1, NULL))) { ! 1415: DeleteDC(bwdc); ! 1416: ReleaseDC(hwnd, dc); ! 1417: Message(MSG_OUTOFMEMORY); ! 1418: return; ! 1419: } ! 1420: SelectObject(bwdc, bwbit); ! 1421: ! 1422: /* Set background color of image DC to desired floodfill color.*/ ! 1423: SetBkColor(ghdcImage, ! 1424: GetPixel(ghdcImage, (ptNew.x / gZoomFactor), ! 1425: (ptNew.y / gZoomFactor))); ! 1426: ! 1427: /******* OPERATION 0 ******/ ! 1428: /* First create a monochrome mask of the image after setting background ! 1429: * color to the floodfill color. This will make the region to be ! 1430: * flooded white(background), and it's boundary black (foreground) in the ! 1431: * mask. ! 1432: */ ! 1433: BitBlt(bwdc, 0, 0, gcxImage, gcyImage, ghdcImage, 0, 0, SRCCOPY); ! 1434: ! 1435: /******* OPERATION 1 ******/ ! 1436: /* floodfill selected region in mask (which is white bounded by black) ! 1437: * with black. ! 1438: */ ! 1439: SelectObject(bwdc, GetStockObject(BLACK_BRUSH)); ! 1440: ExtFloodFill(bwdc, ptNew.x / gZoomFactor, ! 1441: ptNew.y / gZoomFactor, RGB_BLACK, FLOODFILLBORDER); ! 1442: ! 1443: /******* OPERATION 2 ******/ ! 1444: /* Now XOR the original image on the mask , inverting the ! 1445: * flood-filled pixels on mask (black --> white). ! 1446: */ ! 1447: BitBlt(bwdc, 0, 0, gcxImage, gcyImage, ghdcImage, 0, 0, SRCINVERT); ! 1448: ! 1449: /* the AND mask needs to be updated only if in screen or inverse mode */ ! 1450: if ((giType == FT_CURSOR) || (giType == FT_ICON)) { ! 1451: if (gfDrawMode == MODE_COLOR) { ! 1452: SetBkColor(ghdcANDMask, RGB(0, 0, 0)); ! 1453: BitBlt(ghdcANDMask, 0, 0, gcxImage, gcyImage, bwdc, ! 1454: 0, 0, ROP_DSna); ! 1455: SelectObject(ghdcANDMask, GetStockObject(BLACK_BRUSH)); ! 1456: BitBlt(ghdcANDMask, 0, 0, gcxImage, gcyImage, bwdc, ! 1457: 0, 0, ROP_DSPao); ! 1458: } ! 1459: else { ! 1460: SetBkColor(ghdcANDMask, RGB(0xff, 0xff, 0xff)); BitBlt(ghdcANDMask, 0, 0, gcxImage, gcyImage, bwdc, ! 1461: 0, 0, ROP_DSna); ! 1462: SelectObject(ghdcANDMask, GetStockObject(WHITE_BRUSH)); ! 1463: BitBlt(ghdcANDMask, 0, 0, gcxImage, gcyImage, bwdc, ! 1464: 0, 0, ROP_DSPao); ! 1465: } ! 1466: } ! 1467: ! 1468: SetBkColor(ghdcImage, RGB_WHITE); ! 1469: /****** OPERATION 3 ******/ ! 1470: /* The following operation turns the flooded area on-screen black, ! 1471: * on the image, preserving the rest of the it. ! 1472: */ ! 1473: BitBlt(ghdcImage, 0, 0, gcxImage, gcyImage, bwdc, 0, 0, ROP_DSna); ! 1474: ! 1475: /****** OPERATION 4 ******/ ! 1476: /* Rop_DSPao ANDs the pattern (current brush which is the floodfill ! 1477: * color) on the source making flooded area (which was white as a ! 1478: * result of operation 2 ) the current brush color, and keeps the rest ! 1479: * of the source black. The source is then ORed into the original image ! 1480: * (whose flooded area is black as a result of operation 3) to get ! 1481: * the desired end result. ! 1482: */ ! 1483: hbrOld = SelectObject(ghdcImage, ghbrDraw); ! 1484: BitBlt(ghdcImage, 0, 0, gcxImage, gcyImage, bwdc, 0, 0, ROP_DSPao); ! 1485: SelectObject(ghdcImage, hbrOld); ! 1486: ! 1487: /* clean up */ ! 1488: DeleteDC(bwdc); ! 1489: DeleteObject(bwbit); ! 1490: ReleaseDC(hwnd, dc); ! 1491: ! 1492: /* ! 1493: * Mark the image as changed. ! 1494: */ ! 1495: fImageDirty = TRUE; ! 1496: ! 1497: ViewUpdate(); ! 1498: ! 1499: SetCursor(hcurSave); ! 1500: ! 1501: break; ! 1502: } ! 1503: } ! 1504: ! 1505: ! 1506: ! 1507: /****************************************************************************** ! 1508: * VOID HotSpotDP(hwnd, msg, ptNew) ! 1509: * ! 1510: * PURPOSE: Sets the hotspot. ! 1511: * ! 1512: * PARAMS : HWND hwnd : handle to dest. DC ! 1513: * WORD msg : ! 1514: * POINT ptNew : end pt. ! 1515: * ! 1516: *****************************************************************************/ ! 1517: ! 1518: VOID HotSpotDP( ! 1519: HWND hwnd, ! 1520: UINT msg, ! 1521: POINT ptNew) ! 1522: { ! 1523: switch (msg) { ! 1524: case WM_LBUTTONDOWN: ! 1525: PropBarSetHotSpot(ptNew.x / gZoomFactor, ptNew.y / gZoomFactor); ! 1526: break; ! 1527: ! 1528: case WM_MOUSEMOVE: ! 1529: if (fDrawing && fLeftButtonDown) ! 1530: PropBarSetHotSpot(ptNew.x / gZoomFactor, ! 1531: ptNew.y / gZoomFactor); ! 1532: ! 1533: break; ! 1534: ! 1535: case WM_LBUTTONUP: ! 1536: MarkHotSpotPosition(ptNew.x / gZoomFactor, ptNew.y / gZoomFactor); ! 1537: break; ! 1538: } ! 1539: } ! 1540: ! 1541: ! 1542: ! 1543: /************************************************************************ ! 1544: * MarkHotSpotPosition ! 1545: * ! 1546: * Updates the hotspot location in the currently selected cursor image. ! 1547: * ! 1548: * Arguments: ! 1549: * ! 1550: * History: ! 1551: * ! 1552: ************************************************************************/ ! 1553: ! 1554: STATICFN VOID NEAR MarkHotSpotPosition( ! 1555: INT x, ! 1556: INT y) ! 1557: { ! 1558: gpImageCur->iHotspotX = x; ! 1559: gpImageCur->iHotspotY = y; ! 1560: PropBarSetHotSpot(x, y); ! 1561: ! 1562: /* ! 1563: * Mark the image as changed. ! 1564: */ ! 1565: fImageDirty = TRUE; ! 1566: } ! 1567: ! 1568: ! 1569: ! 1570: /****************************************************************************** ! 1571: * NormalizePoints ! 1572: * ! 1573: * PURPOSE : interchange start and end pts ! 1574: * if start point is > end point. ! 1575: * ! 1576: *****************************************************************************/ ! 1577: ! 1578: VOID NormalizePoints( ! 1579: PPOINT pptStart, ! 1580: PPOINT pptEnd) ! 1581: { ! 1582: INT n; ! 1583: ! 1584: if (pptStart->x > pptEnd->x) { ! 1585: n = pptEnd->x; ! 1586: pptEnd->x = pptStart->x; ! 1587: pptStart->x = n; ! 1588: } ! 1589: ! 1590: if (pptStart->y > pptEnd->y) { ! 1591: n = pptEnd->y; ! 1592: pptEnd->y = pptStart->y; ! 1593: pptStart->y = n; ! 1594: } ! 1595: } ! 1596: ! 1597: ! 1598: ! 1599: /****************************************************************************** ! 1600: * HDC PASCAL StartRubberBanding(hwnd) ! 1601: * ! 1602: * PURPOSE: Sets up rubberbanding for all tools. ! 1603: * ! 1604: * PARAMS : HANDLE hDst : handle to box DC ! 1605: * ! 1606: * RETURNS :handle to destination display context ! 1607: * ! 1608: * SIDE EFFECTS: alters a few global flags for tracking ! 1609: * ! 1610: *****************************************************************************/ ! 1611: ! 1612: STATICFN VOID NEAR StartRubberBanding( ! 1613: HWND hwnd) ! 1614: { ! 1615: hdcRubberBand = GetDC(hwnd); ! 1616: ! 1617: /* ! 1618: * Select a white pen, and a null brush (prevents drawing the ! 1619: * interior of rectangles and ellipses). ! 1620: */ ! 1621: SelectObject(hdcRubberBand, GetStockObject(WHITE_PEN)); ! 1622: SelectObject(hdcRubberBand, GetStockObject(NULL_BRUSH)); ! 1623: ! 1624: fRubberBanding = TRUE; ! 1625: } ! 1626: ! 1627: ! 1628: ! 1629: /****************************************************************************** ! 1630: * VOID PASCAL EndRubberBanding() ! 1631: * ! 1632: * PURPOSE: Stops rubberbanding rect. and cleans up ! 1633: * ! 1634: *****************************************************************************/ ! 1635: ! 1636: STATICFN VOID NEAR EndRubberBanding( ! 1637: HWND hwnd) ! 1638: { ! 1639: ReleaseDC(hwnd, hdcRubberBand); ! 1640: fRubberBanding = FALSE; ! 1641: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.