|
|
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.