543e34e92ed0a8429e57d3b2cfbbd2b2f0b1e012
[reactos.git] / reactos / base / applications / paint / mouse.c
1 /*
2 * PROJECT: PAINT for ReactOS
3 * LICENSE: LGPL
4 * FILE: base/applications/paint/mouse.c
5 * PURPOSE: Things which should not be in the mouse event handler itself
6 * PROGRAMMERS: Benedikt Freisen
7 */
8
9 /* INCLUDES *********************************************************/
10
11 #include "globalvar.h"
12 #include "dib.h"
13 #include "drawing.h"
14 #include "history.h"
15
16 /* FUNCTIONS ********************************************************/
17
18 void
19 placeSelWin()
20 {
21 MoveWindow(hSelection, rectSel_dest[0] * zoom / 1000, rectSel_dest[1] * zoom / 1000,
22 rectSel_dest[2] * zoom / 1000 + 6, rectSel_dest[3] * zoom / 1000 + 6, TRUE);
23 BringWindowToTop(hSelection);
24 SendMessage(hImageArea, WM_PAINT, 0, 0);
25 //SendMessage(hSelection, WM_PAINT, 0, 0);
26 }
27
28 void
29 regularize(short x0, short y0, short *x1, short *y1)
30 {
31 if (abs(*x1 - x0) >= abs(*y1 - y0))
32 *y1 = y0 + (*y1 > y0 ? abs(*x1 - x0) : -abs(*x1 - x0));
33 else
34 *x1 = x0 + (*x1 > x0 ? abs(*y1 - y0) : -abs(*y1 - y0));
35 }
36
37 void
38 roundTo8Directions(short x0, short y0, short *x1, short *y1)
39 {
40 if (abs(*x1 - x0) >= abs(*y1 - y0))
41 {
42 if (abs(*y1 - y0) * 5 < abs(*x1 - x0) * 2)
43 *y1 = y0;
44 else
45 *y1 = y0 + (*y1 > y0 ? abs(*x1 - x0) : -abs(*x1 - x0));
46 }
47 else
48 {
49 if (abs(*x1 - x0) * 5 < abs(*y1 - y0) * 2)
50 *x1 = x0;
51 else
52 *x1 = x0 + (*x1 > x0 ? abs(*y1 - y0) : -abs(*y1 - y0));
53 }
54 }
55
56 POINT pointStack[256];
57 short pointSP;
58 POINT *ptStack = NULL;
59 int ptSP = 0;
60
61 void
62 startPaintingL(HDC hdc, short x, short y, int fg, int bg)
63 {
64 startX = x;
65 startY = y;
66 lastX = x;
67 lastY = y;
68 switch (activeTool)
69 {
70 case TOOL_FREESEL:
71 ShowWindow(hSelection, SW_HIDE);
72 if (ptStack != NULL)
73 HeapFree(GetProcessHeap(), 0, ptStack);
74 ptStack = HeapAlloc(GetProcessHeap(), HEAP_GENERATE_EXCEPTIONS, sizeof(POINT) * 1024);
75 ptSP = 0;
76 ptStack[0].x = x;
77 ptStack[0].y = y;
78 break;
79 case TOOL_TEXT:
80 case TOOL_LINE:
81 case TOOL_RECT:
82 case TOOL_ELLIPSE:
83 case TOOL_RRECT:
84 newReversible();
85 break;
86 case TOOL_RECTSEL:
87 newReversible();
88 ShowWindow(hSelection, SW_HIDE);
89 rectSel_src[2] = rectSel_src[3] = 0;
90 break;
91 case TOOL_RUBBER:
92 newReversible();
93 Erase(hdc, x, y, x, y, bg, rubberRadius);
94 break;
95 case TOOL_FILL:
96 newReversible();
97 Fill(hdc, x, y, fg);
98 break;
99 case TOOL_PEN:
100 newReversible();
101 SetPixel(hdc, x, y, fg);
102 break;
103 case TOOL_BRUSH:
104 newReversible();
105 Brush(hdc, x, y, x, y, fg, brushStyle);
106 break;
107 case TOOL_AIRBRUSH:
108 newReversible();
109 Airbrush(hdc, x, y, fg, airBrushWidth);
110 break;
111 case TOOL_BEZIER:
112 pointStack[pointSP].x = x;
113 pointStack[pointSP].y = y;
114 if (pointSP == 0)
115 {
116 newReversible();
117 pointSP++;
118 }
119 break;
120 case TOOL_SHAPE:
121 pointStack[pointSP].x = x;
122 pointStack[pointSP].y = y;
123 if (pointSP + 1 >= 2)
124 Poly(hdc, pointStack, pointSP + 1, fg, bg, lineWidth, shapeStyle, FALSE);
125 if (pointSP == 0)
126 {
127 newReversible();
128 pointSP++;
129 }
130 break;
131 }
132 }
133
134 void
135 whilePaintingL(HDC hdc, short x, short y, int fg, int bg)
136 {
137 switch (activeTool)
138 {
139 case TOOL_FREESEL:
140 if (ptSP == 0)
141 newReversible();
142 ptSP++;
143 if (ptSP % 1024 == 0)
144 ptStack = HeapReAlloc(GetProcessHeap(), HEAP_GENERATE_EXCEPTIONS, ptStack, sizeof(POINT) * (ptSP + 1024));
145 ptStack[ptSP].x = max(0, min(x, imgXRes));
146 ptStack[ptSP].y = max(0, min(y, imgYRes));
147 resetToU1();
148 Poly(hdc, ptStack, ptSP + 1, 0, 0, 2, 0, FALSE);
149 break;
150 case TOOL_RECTSEL:
151 {
152 short tempX;
153 short tempY;
154 resetToU1();
155 tempX = max(0, min(x, imgXRes));
156 tempY = max(0, min(y, imgYRes));
157 rectSel_dest[0] = rectSel_src[0] = min(startX, tempX);
158 rectSel_dest[1] = rectSel_src[1] = min(startY, tempY);
159 rectSel_dest[2] = rectSel_src[2] = max(startX, tempX) - min(startX, tempX);
160 rectSel_dest[3] = rectSel_src[3] = max(startY, tempY) - min(startY, tempY);
161 RectSel(hdc, startX, startY, tempX, tempY);
162 break;
163 }
164 case TOOL_RUBBER:
165 Erase(hdc, lastX, lastY, x, y, bg, rubberRadius);
166 break;
167 case TOOL_PEN:
168 Line(hdc, lastX, lastY, x, y, fg, 1);
169 break;
170 case TOOL_BRUSH:
171 Brush(hdc, lastX, lastY, x, y, fg, brushStyle);
172 break;
173 case TOOL_AIRBRUSH:
174 Airbrush(hdc, x, y, fg, airBrushWidth);
175 break;
176 case TOOL_LINE:
177 resetToU1();
178 if (GetAsyncKeyState(VK_SHIFT) < 0)
179 roundTo8Directions(startX, startY, &x, &y);
180 Line(hdc, startX, startY, x, y, fg, lineWidth);
181 break;
182 case TOOL_BEZIER:
183 resetToU1();
184 pointStack[pointSP].x = x;
185 pointStack[pointSP].y = y;
186 switch (pointSP)
187 {
188 case 1:
189 Line(hdc, pointStack[0].x, pointStack[0].y, pointStack[1].x, pointStack[1].y, fg,
190 lineWidth);
191 break;
192 case 2:
193 Bezier(hdc, pointStack[0], pointStack[2], pointStack[2], pointStack[1], fg, lineWidth);
194 break;
195 case 3:
196 Bezier(hdc, pointStack[0], pointStack[2], pointStack[3], pointStack[1], fg, lineWidth);
197 break;
198 }
199 break;
200 case TOOL_RECT:
201 resetToU1();
202 if (GetAsyncKeyState(VK_SHIFT) < 0)
203 regularize(startX, startY, &x, &y);
204 Rect(hdc, startX, startY, x, y, fg, bg, lineWidth, shapeStyle);
205 break;
206 case TOOL_SHAPE:
207 resetToU1();
208 pointStack[pointSP].x = x;
209 pointStack[pointSP].y = y;
210 if ((pointSP > 0) && (GetAsyncKeyState(VK_SHIFT) < 0))
211 roundTo8Directions(pointStack[pointSP - 1].x, pointStack[pointSP - 1].y,
212 (short *)&pointStack[pointSP].x, (short *)&pointStack[pointSP].y);
213 if (pointSP + 1 >= 2)
214 Poly(hdc, pointStack, pointSP + 1, fg, bg, lineWidth, shapeStyle, FALSE);
215 break;
216 case TOOL_ELLIPSE:
217 resetToU1();
218 if (GetAsyncKeyState(VK_SHIFT) < 0)
219 regularize(startX, startY, &x, &y);
220 Ellp(hdc, startX, startY, x, y, fg, bg, lineWidth, shapeStyle);
221 break;
222 case TOOL_RRECT:
223 resetToU1();
224 if (GetAsyncKeyState(VK_SHIFT) < 0)
225 regularize(startX, startY, &x, &y);
226 RRect(hdc, startX, startY, x, y, fg, bg, lineWidth, shapeStyle);
227 break;
228 }
229
230 lastX = x;
231 lastY = y;
232 }
233
234 void
235 endPaintingL(HDC hdc, short x, short y, int fg, int bg)
236 {
237 switch (activeTool)
238 {
239 case TOOL_FREESEL:
240 {
241 POINT *ptStackCopy;
242 int i;
243 rectSel_src[0] = rectSel_src[1] = 0x7fffffff;
244 rectSel_src[2] = rectSel_src[3] = 0;
245 for (i = 0; i <= ptSP; i++)
246 {
247 if (ptStack[i].x < rectSel_src[0])
248 rectSel_src[0] = ptStack[i].x;
249 if (ptStack[i].y < rectSel_src[1])
250 rectSel_src[1] = ptStack[i].y;
251 if (ptStack[i].x > rectSel_src[2])
252 rectSel_src[2] = ptStack[i].x;
253 if (ptStack[i].y > rectSel_src[3])
254 rectSel_src[3] = ptStack[i].y;
255 }
256 rectSel_src[2] += 1 - rectSel_src[0];
257 rectSel_src[3] += 1 - rectSel_src[1];
258 rectSel_dest[0] = rectSel_src[0];
259 rectSel_dest[1] = rectSel_src[1];
260 rectSel_dest[2] = rectSel_src[2];
261 rectSel_dest[3] = rectSel_src[3];
262 if (ptSP != 0)
263 {
264 DeleteObject(hSelMask);
265 hSelMask = CreateBitmap(rectSel_src[2], rectSel_src[3], 1, 1, NULL);
266 DeleteObject(SelectObject(hSelDC, hSelMask));
267 ptStackCopy = HeapAlloc(GetProcessHeap(), HEAP_GENERATE_EXCEPTIONS, sizeof(POINT) * (ptSP + 1));
268 for (i = 0; i <= ptSP; i++)
269 {
270 ptStackCopy[i].x = ptStack[i].x - rectSel_src[0];
271 ptStackCopy[i].y = ptStack[i].y - rectSel_src[1];
272 }
273 Poly(hSelDC, ptStackCopy, ptSP + 1, 0x00ffffff, 0x00ffffff, 1, 2, TRUE);
274 HeapFree(GetProcessHeap(), 0, ptStackCopy);
275 SelectObject(hSelDC, hSelBm = CreateDIBWithProperties(rectSel_src[2], rectSel_src[3]));
276 resetToU1();
277 MaskBlt(hSelDC, 0, 0, rectSel_src[2], rectSel_src[3], hDrawingDC, rectSel_src[0],
278 rectSel_src[1], hSelMask, 0, 0, MAKEROP4(SRCCOPY, WHITENESS));
279 Poly(hdc, ptStack, ptSP + 1, bg, bg, 1, 2, TRUE);
280 newReversible();
281
282 placeSelWin();
283 ShowWindow(hSelection, SW_SHOW);
284 }
285 HeapFree(GetProcessHeap(), 0, ptStack);
286 ptStack = NULL;
287 break;
288 }
289 case TOOL_RECTSEL:
290 resetToU1();
291 if ((rectSel_src[2] != 0) && (rectSel_src[3] != 0))
292 {
293 DeleteObject(hSelMask);
294 hSelMask = CreateBitmap(rectSel_src[2], rectSel_src[3], 1, 1, NULL);
295 DeleteObject(SelectObject(hSelDC, hSelMask));
296 Rect(hSelDC, 0, 0, rectSel_src[2], rectSel_src[3], 0x00ffffff, 0x00ffffff, 1, 2);
297 SelectObject(hSelDC, hSelBm = CreateDIBWithProperties(rectSel_src[2], rectSel_src[3]));
298 resetToU1();
299 BitBlt(hSelDC, 0, 0, rectSel_src[2], rectSel_src[3], hDrawingDC, rectSel_src[0],
300 rectSel_src[1], SRCCOPY);
301 Rect(hdc, rectSel_src[0], rectSel_src[1], rectSel_src[0] + rectSel_src[2],
302 rectSel_src[1] + rectSel_src[3], bgColor, bgColor, 0, TRUE);
303 newReversible();
304
305 placeSelWin();
306 ShowWindow(hSelection, SW_SHOW);
307 }
308 break;
309 case TOOL_RUBBER:
310 Erase(hdc, lastX, lastY, x, y, bg, rubberRadius);
311 break;
312 case TOOL_PEN:
313 Line(hdc, lastX, lastY, x, y, fg, 1);
314 SetPixel(hdc, x, y, fg);
315 break;
316 case TOOL_LINE:
317 resetToU1();
318 if (GetAsyncKeyState(VK_SHIFT) < 0)
319 roundTo8Directions(startX, startY, &x, &y);
320 Line(hdc, startX, startY, x, y, fg, lineWidth);
321 break;
322 case TOOL_BEZIER:
323 pointSP++;
324 if (pointSP == 4)
325 pointSP = 0;
326 break;
327 case TOOL_RECT:
328 resetToU1();
329 if (GetAsyncKeyState(VK_SHIFT) < 0)
330 regularize(startX, startY, &x, &y);
331 Rect(hdc, startX, startY, x, y, fg, bg, lineWidth, shapeStyle);
332 break;
333 case TOOL_SHAPE:
334 resetToU1();
335 pointStack[pointSP].x = x;
336 pointStack[pointSP].y = y;
337 if ((pointSP > 0) && (GetAsyncKeyState(VK_SHIFT) < 0))
338 roundTo8Directions(pointStack[pointSP - 1].x, pointStack[pointSP - 1].y,
339 (short *)&pointStack[pointSP].x, (short *)&pointStack[pointSP].y);
340 pointSP++;
341 if (pointSP >= 2)
342 {
343 if ((pointStack[0].x - x) * (pointStack[0].x - x) +
344 (pointStack[0].y - y) * (pointStack[0].y - y) <= lineWidth * lineWidth + 1)
345 {
346 Poly(hdc, pointStack, pointSP, fg, bg, lineWidth, shapeStyle, TRUE);
347 pointSP = 0;
348 }
349 else
350 {
351 Poly(hdc, pointStack, pointSP, fg, bg, lineWidth, shapeStyle, FALSE);
352 }
353 }
354 if (pointSP == 255)
355 pointSP--;
356 break;
357 case TOOL_ELLIPSE:
358 resetToU1();
359 if (GetAsyncKeyState(VK_SHIFT) < 0)
360 regularize(startX, startY, &x, &y);
361 Ellp(hdc, startX, startY, x, y, fg, bg, lineWidth, shapeStyle);
362 break;
363 case TOOL_RRECT:
364 resetToU1();
365 if (GetAsyncKeyState(VK_SHIFT) < 0)
366 regularize(startX, startY, &x, &y);
367 RRect(hdc, startX, startY, x, y, fg, bg, lineWidth, shapeStyle);
368 break;
369 }
370 }
371
372 void
373 startPaintingR(HDC hdc, short x, short y, int fg, int bg)
374 {
375 startX = x;
376 startY = y;
377 lastX = x;
378 lastY = y;
379 switch (activeTool)
380 {
381 case TOOL_FREESEL:
382 case TOOL_TEXT:
383 case TOOL_LINE:
384 case TOOL_RECT:
385 case TOOL_ELLIPSE:
386 case TOOL_RRECT:
387 newReversible();
388 break;
389 case TOOL_RUBBER:
390 newReversible();
391 Replace(hdc, x, y, x, y, fg, bg, rubberRadius);
392 break;
393 case TOOL_FILL:
394 newReversible();
395 Fill(hdc, x, y, bg);
396 break;
397 case TOOL_PEN:
398 newReversible();
399 SetPixel(hdc, x, y, bg);
400 break;
401 case TOOL_BRUSH:
402 newReversible();
403 Brush(hdc, x, y, x, y, bg, brushStyle);
404 break;
405 case TOOL_AIRBRUSH:
406 newReversible();
407 Airbrush(hdc, x, y, bg, airBrushWidth);
408 break;
409 case TOOL_BEZIER:
410 pointStack[pointSP].x = x;
411 pointStack[pointSP].y = y;
412 if (pointSP == 0)
413 {
414 newReversible();
415 pointSP++;
416 }
417 break;
418 case TOOL_SHAPE:
419 pointStack[pointSP].x = x;
420 pointStack[pointSP].y = y;
421 if (pointSP + 1 >= 2)
422 Poly(hdc, pointStack, pointSP + 1, bg, fg, lineWidth, shapeStyle, FALSE);
423 if (pointSP == 0)
424 {
425 newReversible();
426 pointSP++;
427 }
428 break;
429 }
430 }
431
432 void
433 whilePaintingR(HDC hdc, short x, short y, int fg, int bg)
434 {
435 switch (activeTool)
436 {
437 case TOOL_RUBBER:
438 Replace(hdc, lastX, lastY, x, y, fg, bg, rubberRadius);
439 break;
440 case TOOL_PEN:
441 Line(hdc, lastX, lastY, x, y, bg, 1);
442 break;
443 case TOOL_BRUSH:
444 Brush(hdc, lastX, lastY, x, y, bg, brushStyle);
445 break;
446 case TOOL_AIRBRUSH:
447 Airbrush(hdc, x, y, bg, airBrushWidth);
448 break;
449 case TOOL_LINE:
450 resetToU1();
451 if (GetAsyncKeyState(VK_SHIFT) < 0)
452 roundTo8Directions(startX, startY, &x, &y);
453 Line(hdc, startX, startY, x, y, bg, lineWidth);
454 break;
455 case TOOL_BEZIER:
456 resetToU1();
457 pointStack[pointSP].x = x;
458 pointStack[pointSP].y = y;
459 switch (pointSP)
460 {
461 case 1:
462 Line(hdc, pointStack[0].x, pointStack[0].y, pointStack[1].x, pointStack[1].y, bg,
463 lineWidth);
464 break;
465 case 2:
466 Bezier(hdc, pointStack[0], pointStack[2], pointStack[2], pointStack[1], bg, lineWidth);
467 break;
468 case 3:
469 Bezier(hdc, pointStack[0], pointStack[2], pointStack[3], pointStack[1], bg, lineWidth);
470 break;
471 }
472 break;
473 case TOOL_RECT:
474 resetToU1();
475 if (GetAsyncKeyState(VK_SHIFT) < 0)
476 regularize(startX, startY, &x, &y);
477 Rect(hdc, startX, startY, x, y, bg, fg, lineWidth, shapeStyle);
478 break;
479 case TOOL_SHAPE:
480 resetToU1();
481 pointStack[pointSP].x = x;
482 pointStack[pointSP].y = y;
483 if ((pointSP > 0) && (GetAsyncKeyState(VK_SHIFT) < 0))
484 roundTo8Directions(pointStack[pointSP - 1].x, pointStack[pointSP - 1].y,
485 (short *)&pointStack[pointSP].x, (short *)&pointStack[pointSP].y);
486 if (pointSP + 1 >= 2)
487 Poly(hdc, pointStack, pointSP + 1, bg, fg, lineWidth, shapeStyle, FALSE);
488 break;
489 case TOOL_ELLIPSE:
490 resetToU1();
491 if (GetAsyncKeyState(VK_SHIFT) < 0)
492 regularize(startX, startY, &x, &y);
493 Ellp(hdc, startX, startY, x, y, bg, fg, lineWidth, shapeStyle);
494 break;
495 case TOOL_RRECT:
496 resetToU1();
497 if (GetAsyncKeyState(VK_SHIFT) < 0)
498 regularize(startX, startY, &x, &y);
499 RRect(hdc, startX, startY, x, y, bg, fg, lineWidth, shapeStyle);
500 break;
501 }
502
503 lastX = x;
504 lastY = y;
505 }
506
507 void
508 endPaintingR(HDC hdc, short x, short y, int fg, int bg)
509 {
510 switch (activeTool)
511 {
512 case TOOL_RUBBER:
513 Replace(hdc, lastX, lastY, x, y, fg, bg, rubberRadius);
514 break;
515 case TOOL_PEN:
516 Line(hdc, lastX, lastY, x, y, bg, 1);
517 SetPixel(hdc, x, y, bg);
518 break;
519 case TOOL_LINE:
520 resetToU1();
521 if (GetAsyncKeyState(VK_SHIFT) < 0)
522 roundTo8Directions(startX, startY, &x, &y);
523 Line(hdc, startX, startY, x, y, bg, lineWidth);
524 break;
525 case TOOL_BEZIER:
526 pointSP++;
527 if (pointSP == 4)
528 pointSP = 0;
529 break;
530 case TOOL_RECT:
531 resetToU1();
532 if (GetAsyncKeyState(VK_SHIFT) < 0)
533 regularize(startX, startY, &x, &y);
534 Rect(hdc, startX, startY, x, y, bg, fg, lineWidth, shapeStyle);
535 break;
536 case TOOL_SHAPE:
537 resetToU1();
538 pointStack[pointSP].x = x;
539 pointStack[pointSP].y = y;
540 if ((pointSP > 0) && (GetAsyncKeyState(VK_SHIFT) < 0))
541 roundTo8Directions(pointStack[pointSP - 1].x, pointStack[pointSP - 1].y,
542 (short *)&pointStack[pointSP].x, (short *)&pointStack[pointSP].y);
543 pointSP++;
544 if (pointSP >= 2)
545 {
546 if ((pointStack[0].x - x) * (pointStack[0].x - x) +
547 (pointStack[0].y - y) * (pointStack[0].y - y) <= lineWidth * lineWidth + 1)
548 {
549 Poly(hdc, pointStack, pointSP, bg, fg, lineWidth, shapeStyle, TRUE);
550 pointSP = 0;
551 }
552 else
553 {
554 Poly(hdc, pointStack, pointSP, bg, fg, lineWidth, shapeStyle, FALSE);
555 }
556 }
557 if (pointSP == 255)
558 pointSP--;
559 break;
560 case TOOL_ELLIPSE:
561 resetToU1();
562 if (GetAsyncKeyState(VK_SHIFT) < 0)
563 regularize(startX, startY, &x, &y);
564 Ellp(hdc, startX, startY, x, y, bg, fg, lineWidth, shapeStyle);
565 break;
566 case TOOL_RRECT:
567 resetToU1();
568 if (GetAsyncKeyState(VK_SHIFT) < 0)
569 regularize(startX, startY, &x, &y);
570 RRect(hdc, startX, startY, x, y, bg, fg, lineWidth, shapeStyle);
571 break;
572 }
573 }