xref: /reactos/base/applications/mspaint/mouse.cpp (revision 7e22dc05)
1 /*
2  * PROJECT:     PAINT for ReactOS
3  * LICENSE:     LGPL
4  * FILE:        base/applications/mspaint/mouse.cpp
5  * PURPOSE:     Things which should not be in the mouse event handler itself
6  * PROGRAMMERS: Benedikt Freisen
7  *              Katayama Hirofumi MZ
8  */
9 
10 /* INCLUDES *********************************************************/
11 
12 #include "precomp.h"
13 
14 INT ToolBase::pointSP = 0;
15 POINT ToolBase::pointStack[256] = { { 0 } };
16 
17 /* FUNCTIONS ********************************************************/
18 
19 void
20 placeSelWin()
21 {
22     selectionWindow.MoveWindow(Zoomed(selectionModel.GetDestRectLeft()), Zoomed(selectionModel.GetDestRectTop()),
23         Zoomed(selectionModel.GetDestRectWidth()) + 2 * GRIP_SIZE,
24         Zoomed(selectionModel.GetDestRectHeight()) + 2 * GRIP_SIZE, TRUE);
25     selectionWindow.BringWindowToTop();
26     imageArea.InvalidateRect(NULL, FALSE);
27 }
28 
29 void
30 regularize(LONG x0, LONG y0, LONG& x1, LONG& y1)
31 {
32     if (abs(x1 - x0) >= abs(y1 - y0))
33         y1 = y0 + (y1 > y0 ? abs(x1 - x0) : -abs(x1 - x0));
34     else
35         x1 = x0 + (x1 > x0 ? abs(y1 - y0) : -abs(y1 - y0));
36 }
37 
38 void
39 roundTo8Directions(LONG x0, LONG y0, LONG& x1, LONG& y1)
40 {
41     if (abs(x1 - x0) >= abs(y1 - y0))
42     {
43         if (abs(y1 - y0) * 5 < abs(x1 - x0) * 2)
44             y1 = y0;
45         else
46             y1 = y0 + (y1 > y0 ? abs(x1 - x0) : -abs(x1 - x0));
47     }
48     else
49     {
50         if (abs(x1 - x0) * 5 < abs(y1 - y0) * 2)
51             x1 = x0;
52         else
53             x1 = x0 + (x1 > x0 ? abs(y1 - y0) : -abs(y1 - y0));
54     }
55 }
56 
57 BOOL nearlyEqualPoints(INT x0, INT y0, INT x1, INT y1)
58 {
59     INT cxThreshold = toolsModel.GetLineWidth() + UnZoomed(GetSystemMetrics(SM_CXDRAG));
60     INT cyThreshold = toolsModel.GetLineWidth() + UnZoomed(GetSystemMetrics(SM_CYDRAG));
61     return (abs(x1 - x0) <= cxThreshold) && (abs(y1 - y0) <= cyThreshold);
62 }
63 
64 void updateStartAndLast(LONG x, LONG y)
65 {
66     start.x = last.x = x;
67     start.y = last.y = y;
68 }
69 
70 void updateLast(LONG x, LONG y)
71 {
72     last.x = x;
73     last.y = y;
74 }
75 
76 void ToolBase::reset()
77 {
78     pointSP = 0;
79     start.x = start.y = last.x = last.y = -1;
80     selectionModel.ResetPtStack();
81     if (selectionWindow.IsWindow())
82         selectionWindow.ShowWindow(SW_HIDE);
83 }
84 
85 void ToolBase::OnCancelDraw()
86 {
87     reset();
88 }
89 
90 void ToolBase::OnFinishDraw()
91 {
92     reset();
93 }
94 
95 void ToolBase::beginEvent()
96 {
97     m_hdc = imageModel.GetDC();
98     m_fg = paletteModel.GetFgColor();
99     m_bg = paletteModel.GetBgColor();
100 }
101 
102 void ToolBase::endEvent()
103 {
104     m_hdc = NULL;
105 }
106 
107 /* TOOLS ********************************************************/
108 
109 // TOOL_FREESEL
110 struct FreeSelTool : ToolBase
111 {
112     BOOL m_bLeftButton;
113 
114     FreeSelTool() : ToolBase(TOOL_FREESEL), m_bLeftButton(FALSE)
115     {
116     }
117 
118     void OnButtonDown(BOOL bLeftButton, LONG x, LONG y, BOOL bDoubleClick)
119     {
120         if (bLeftButton)
121         {
122             imageModel.CopyPrevious();
123             selectionWindow.ShowWindow(SW_HIDE);
124             selectionModel.ResetPtStack();
125             selectionModel.PushToPtStack(x, y);
126         }
127         m_bLeftButton = bLeftButton;
128     }
129 
130     void OnMouseMove(BOOL bLeftButton, LONG x, LONG y)
131     {
132         if (bLeftButton)
133         {
134             POINT pt = { x, y };
135             imageModel.Bound(pt);
136             selectionModel.PushToPtStack(pt.x, pt.y);
137             imageModel.ResetToPrevious();
138             selectionModel.DrawFramePoly(m_hdc);
139         }
140     }
141 
142     void OnButtonUp(BOOL bLeftButton, LONG x, LONG y)
143     {
144         if (bLeftButton)
145         {
146             imageModel.ResetToPrevious();
147             if (selectionModel.PtStackSize() > 2)
148             {
149                 selectionModel.CalculateBoundingBoxAndContents(m_hdc);
150                 placeSelWin();
151                 selectionWindow.IsMoved(FALSE);
152                 selectionWindow.ShowWindow(SW_SHOWNOACTIVATE);
153             }
154             else
155             {
156                 imageModel.Undo(TRUE);
157                 selectionWindow.IsMoved(FALSE);
158                 selectionModel.ResetPtStack();
159                 selectionWindow.ShowWindow(SW_HIDE);
160             }
161         }
162     }
163 
164     void OnFinishDraw()
165     {
166         if (m_bLeftButton)
167         {
168             selectionWindow.IsMoved(FALSE);
169             selectionWindow.ForceRefreshSelectionContents();
170         }
171         m_bLeftButton = FALSE;
172         ToolBase::OnFinishDraw();
173     }
174 
175     void OnCancelDraw()
176     {
177         if (m_bLeftButton)
178             imageModel.Undo(TRUE);
179         m_bLeftButton = FALSE;
180         selectionWindow.IsMoved(FALSE);
181         ToolBase::OnCancelDraw();
182     }
183 };
184 
185 // TOOL_RECTSEL
186 struct RectSelTool : ToolBase
187 {
188     BOOL m_bLeftButton;
189 
190     RectSelTool() : ToolBase(TOOL_RECTSEL), m_bLeftButton(FALSE)
191     {
192     }
193 
194     void OnButtonDown(BOOL bLeftButton, LONG x, LONG y, BOOL bDoubleClick)
195     {
196         if (bLeftButton)
197         {
198             imageModel.CopyPrevious();
199             selectionWindow.ShowWindow(SW_HIDE);
200             selectionModel.SetSrcRectSizeToZero();
201         }
202         m_bLeftButton = bLeftButton;
203     }
204 
205     void OnMouseMove(BOOL bLeftButton, LONG x, LONG y)
206     {
207         if (bLeftButton)
208         {
209             imageModel.ResetToPrevious();
210             POINT pt = { x, y };
211             imageModel.Bound(pt);
212             selectionModel.SetSrcAndDestRectFromPoints(start, pt);
213             RectSel(m_hdc, start.x, start.y, pt.x, pt.y);
214         }
215     }
216 
217     void OnButtonUp(BOOL bLeftButton, LONG x, LONG y)
218     {
219         if (bLeftButton)
220         {
221             imageModel.ResetToPrevious();
222             if (start.x == x && start.y == y)
223                 imageModel.Undo(TRUE);
224             selectionModel.CalculateContents(m_hdc);
225             placeSelWin();
226             selectionWindow.IsMoved(FALSE);
227             if (selectionModel.IsSrcRectSizeNonzero())
228                 selectionWindow.ShowWindow(SW_SHOWNOACTIVATE);
229             else
230                 selectionWindow.ShowWindow(SW_HIDE);
231         }
232     }
233 
234     void OnFinishDraw()
235     {
236         if (m_bLeftButton)
237         {
238             selectionWindow.IsMoved(FALSE);
239             selectionWindow.ForceRefreshSelectionContents();
240         }
241         m_bLeftButton = FALSE;
242         ToolBase::OnFinishDraw();
243     }
244 
245     void OnCancelDraw()
246     {
247         if (m_bLeftButton)
248             imageModel.Undo(TRUE);
249         m_bLeftButton = FALSE;
250         selectionWindow.IsMoved(FALSE);
251         ToolBase::OnCancelDraw();
252     }
253 };
254 
255 struct GenericDrawTool : ToolBase
256 {
257     GenericDrawTool(TOOLTYPE type) : ToolBase(type)
258     {
259     }
260 
261     virtual void draw(BOOL bLeftButton, LONG x, LONG y) = 0;
262 
263     void OnButtonDown(BOOL bLeftButton, LONG x, LONG y, BOOL bDoubleClick)
264     {
265         imageModel.CopyPrevious();
266         draw(bLeftButton, x, y);
267     }
268 
269     void OnMouseMove(BOOL bLeftButton, LONG x, LONG y)
270     {
271         draw(bLeftButton, x, y);
272     }
273 
274     void OnButtonUp(BOOL bLeftButton, LONG x, LONG y)
275     {
276         draw(bLeftButton, x, y);
277     }
278 
279     void OnCancelDraw()
280     {
281         OnButtonUp(FALSE, 0, 0);
282         imageModel.Undo(TRUE);
283         ToolBase::OnCancelDraw();
284     }
285 };
286 
287 // TOOL_RUBBER
288 struct RubberTool : GenericDrawTool
289 {
290     RubberTool() : GenericDrawTool(TOOL_RUBBER)
291     {
292     }
293 
294     virtual void draw(BOOL bLeftButton, LONG x, LONG y)
295     {
296         if (bLeftButton)
297             Erase(m_hdc, last.x, last.y, x, y, m_bg, toolsModel.GetRubberRadius());
298         else
299             Replace(m_hdc, last.x, last.y, x, y, m_fg, m_bg, toolsModel.GetRubberRadius());
300     }
301 };
302 
303 // TOOL_FILL
304 struct FillTool : ToolBase
305 {
306     FillTool() : ToolBase(TOOL_FILL)
307     {
308     }
309 
310     void OnButtonDown(BOOL bLeftButton, LONG x, LONG y, BOOL bDoubleClick)
311     {
312         imageModel.CopyPrevious();
313         Fill(m_hdc, x, y, bLeftButton ? m_fg : m_bg);
314     }
315 };
316 
317 // TOOL_COLOR
318 struct ColorTool : ToolBase
319 {
320     ColorTool() : ToolBase(TOOL_COLOR)
321     {
322     }
323 
324     void fetchColor(BOOL bLeftButton, LONG x, LONG y)
325     {
326         COLORREF rgbColor;
327 
328         if (0 <= x && x < imageModel.GetWidth() && 0 <= y && y < imageModel.GetHeight())
329             rgbColor = GetPixel(m_hdc, x, y);
330         else
331             rgbColor = RGB(255, 255, 255); // Outside is white
332 
333         if (bLeftButton)
334             paletteModel.SetFgColor(rgbColor);
335         else
336             paletteModel.SetBgColor(rgbColor);
337     }
338 
339     void OnMouseMove(BOOL bLeftButton, LONG x, LONG y)
340     {
341         fetchColor(bLeftButton, x, y);
342     }
343 
344     void OnButtonUp(BOOL bLeftButton, LONG x, LONG y)
345     {
346         fetchColor(bLeftButton, x, y);
347         toolsModel.SetActiveTool(toolsModel.GetOldActiveTool());
348     }
349 };
350 
351 // TOOL_ZOOM
352 struct ZoomTool : ToolBase
353 {
354     ZoomTool() : ToolBase(TOOL_ZOOM)
355     {
356     }
357 
358     void OnButtonDown(BOOL bLeftButton, LONG x, LONG y, BOOL bDoubleClick)
359     {
360         imageModel.CopyPrevious();
361         if (bLeftButton)
362         {
363             if (toolsModel.GetZoom() < MAX_ZOOM)
364                 zoomTo(toolsModel.GetZoom() * 2, x, y);
365         }
366         else
367         {
368             if (toolsModel.GetZoom() > MIN_ZOOM)
369                 zoomTo(toolsModel.GetZoom() / 2, x, y);
370         }
371     }
372 };
373 
374 // TOOL_PEN
375 struct PenTool : GenericDrawTool
376 {
377     PenTool() : GenericDrawTool(TOOL_PEN)
378     {
379     }
380 
381     virtual void draw(BOOL bLeftButton, LONG x, LONG y)
382     {
383         COLORREF rgb = bLeftButton ? m_fg : m_bg;
384         Line(m_hdc, last.x, last.y, x, y, rgb, 1);
385         SetPixel(m_hdc, x, y, rgb);
386     }
387 };
388 
389 // TOOL_BRUSH
390 struct BrushTool : GenericDrawTool
391 {
392     BrushTool() : GenericDrawTool(TOOL_BRUSH)
393     {
394     }
395 
396     virtual void draw(BOOL bLeftButton, LONG x, LONG y)
397     {
398         COLORREF rgb = bLeftButton ? m_fg : m_bg;
399         Brush(m_hdc, last.x, last.y, x, y, rgb, toolsModel.GetBrushStyle());
400     }
401 };
402 
403 // TOOL_AIRBRUSH
404 struct AirBrushTool : GenericDrawTool
405 {
406     AirBrushTool() : GenericDrawTool(TOOL_AIRBRUSH)
407     {
408     }
409 
410     virtual void draw(BOOL bLeftButton, LONG x, LONG y)
411     {
412         COLORREF rgb = bLeftButton ? m_fg : m_bg;
413         Airbrush(m_hdc, x, y, rgb, toolsModel.GetAirBrushWidth());
414     }
415 };
416 
417 // TOOL_TEXT
418 struct TextTool : ToolBase
419 {
420     TextTool() : ToolBase(TOOL_TEXT)
421     {
422     }
423 
424     void UpdatePoint(LONG x, LONG y)
425     {
426         imageModel.ResetToPrevious();
427         POINT pt = { x, y };
428         imageModel.Bound(pt);
429         selectionModel.SetSrcAndDestRectFromPoints(start, pt);
430         RectSel(m_hdc, start.x, start.y, pt.x, pt.y);
431     }
432 
433     void OnButtonDown(BOOL bLeftButton, LONG x, LONG y, BOOL bDoubleClick)
434     {
435         if (!textEditWindow.IsWindow())
436             textEditWindow.Create(imageArea);
437 
438         imageModel.CopyPrevious();
439         UpdatePoint(x, y);
440     }
441 
442     void OnMouseMove(BOOL bLeftButton, LONG x, LONG y)
443     {
444         UpdatePoint(x, y);
445     }
446 
447     void OnButtonUp(BOOL bLeftButton, LONG x, LONG y)
448     {
449         imageModel.Undo(TRUE);
450 
451         BOOL bTextBoxShown = ::IsWindowVisible(textEditWindow);
452         if (bTextBoxShown && textEditWindow.GetWindowTextLength() > 0)
453         {
454             CString szText;
455             textEditWindow.GetWindowText(szText);
456 
457             RECT rc;
458             textEditWindow.InvalidateEditRect();
459             textEditWindow.GetEditRect(&rc);
460 
461             INT style = (toolsModel.IsBackgroundTransparent() ? 0 : 1);
462             imageModel.CopyPrevious();
463             Text(m_hdc, rc.left, rc.top, rc.right, rc.bottom, m_fg, m_bg, szText,
464                  textEditWindow.GetFont(), style);
465         }
466 
467         if (registrySettings.ShowTextTool)
468         {
469             if (!fontsDialog.IsWindow())
470                 fontsDialog.Create(mainWindow);
471 
472             fontsDialog.ShowWindow(SW_SHOWNOACTIVATE);
473         }
474 
475         if (!bTextBoxShown || selectionModel.IsSrcRectSizeNonzero())
476         {
477             RECT rc;
478             selectionModel.GetRect(&rc);
479 
480             // Enlarge if tool small
481             INT cxMin = CX_MINTEXTEDIT, cyMin = CY_MINTEXTEDIT;
482             if (selectionModel.IsSrcRectSizeNonzero())
483             {
484                 if (rc.right - rc.left < cxMin)
485                     rc.right = rc.left + cxMin;
486                 if (rc.bottom - rc.top < cyMin)
487                     rc.bottom = rc.top + cyMin;
488             }
489             else
490             {
491                 SetRect(&rc, x, y, x + cxMin, y + cyMin);
492             }
493 
494             if (!textEditWindow.IsWindow())
495                 textEditWindow.Create(imageArea);
496 
497             textEditWindow.SetWindowText(NULL);
498             textEditWindow.ValidateEditRect(&rc);
499             textEditWindow.ShowWindow(SW_SHOWNOACTIVATE);
500             textEditWindow.SetFocus();
501         }
502         else
503         {
504             textEditWindow.ShowWindow(SW_HIDE);
505             textEditWindow.SetWindowText(NULL);
506         }
507     }
508 
509     void OnFinishDraw()
510     {
511         toolsModel.OnButtonDown(TRUE, -1, -1, TRUE);
512         toolsModel.OnButtonUp(TRUE, -1, -1);
513         selectionWindow.IsMoved(FALSE);
514         ToolBase::OnFinishDraw();
515     }
516 };
517 
518 // TOOL_LINE
519 struct LineTool : GenericDrawTool
520 {
521     LineTool() : GenericDrawTool(TOOL_LINE)
522     {
523     }
524 
525     virtual void draw(BOOL bLeftButton, LONG x, LONG y)
526     {
527         imageModel.ResetToPrevious();
528         if (GetAsyncKeyState(VK_SHIFT) < 0)
529             roundTo8Directions(start.x, start.y, x, y);
530         COLORREF rgb = bLeftButton ? m_fg : m_bg;
531         Line(m_hdc, start.x, start.y, x, y, rgb, toolsModel.GetLineWidth());
532     }
533 };
534 
535 // TOOL_BEZIER
536 struct BezierTool : ToolBase
537 {
538     BOOL m_bLeftButton;
539 
540     BezierTool() : ToolBase(TOOL_BEZIER), m_bLeftButton(FALSE)
541     {
542     }
543 
544     void draw(BOOL bLeftButton)
545     {
546         COLORREF rgb = (bLeftButton ? m_fg : m_bg);
547         switch (pointSP)
548         {
549             case 1:
550                 Line(m_hdc, pointStack[0].x, pointStack[0].y, pointStack[1].x, pointStack[1].y, rgb,
551                      toolsModel.GetLineWidth());
552                 break;
553             case 2:
554                 Bezier(m_hdc, pointStack[0], pointStack[2], pointStack[2], pointStack[1], rgb, toolsModel.GetLineWidth());
555                 break;
556             case 3:
557                 Bezier(m_hdc, pointStack[0], pointStack[2], pointStack[3], pointStack[1], rgb, toolsModel.GetLineWidth());
558                 break;
559         }
560         m_bLeftButton = bLeftButton;
561     }
562 
563     void OnButtonDown(BOOL bLeftButton, LONG x, LONG y, BOOL bDoubleClick)
564     {
565         pointStack[pointSP].x = x;
566         pointStack[pointSP].y = y;
567 
568         if (pointSP == 0)
569         {
570             imageModel.CopyPrevious();
571             pointSP++;
572         }
573     }
574 
575     void OnMouseMove(BOOL bLeftButton, LONG x, LONG y)
576     {
577         imageModel.ResetToPrevious();
578         pointStack[pointSP].x = x;
579         pointStack[pointSP].y = y;
580         draw(bLeftButton);
581     }
582 
583     void OnButtonUp(BOOL bLeftButton, LONG x, LONG y)
584     {
585         imageModel.ResetToPrevious();
586         draw(bLeftButton);
587         pointSP++;
588         if (pointSP == 4)
589             pointSP = 0;
590     }
591 
592     void OnCancelDraw()
593     {
594         OnButtonUp(FALSE, 0, 0);
595         imageModel.Undo(TRUE);
596         ToolBase::OnCancelDraw();
597     }
598 
599     void OnFinishDraw()
600     {
601         if (pointSP)
602         {
603             imageModel.ResetToPrevious();
604             --pointSP;
605             draw(m_bLeftButton);
606         }
607         ToolBase::OnFinishDraw();
608     }
609 };
610 
611 // TOOL_RECT
612 struct RectTool : GenericDrawTool
613 {
614     RectTool() : GenericDrawTool(TOOL_RECT)
615     {
616     }
617 
618     virtual void draw(BOOL bLeftButton, LONG x, LONG y)
619     {
620         imageModel.ResetToPrevious();
621         if (GetAsyncKeyState(VK_SHIFT) < 0)
622             regularize(start.x, start.y, x, y);
623         if (bLeftButton)
624             Rect(m_hdc, start.x, start.y, x, y, m_fg, m_bg, toolsModel.GetLineWidth(), toolsModel.GetShapeStyle());
625         else
626             Rect(m_hdc, start.x, start.y, x, y, m_bg, m_fg, toolsModel.GetLineWidth(), toolsModel.GetShapeStyle());
627     }
628 };
629 
630 // TOOL_SHAPE
631 struct ShapeTool : ToolBase
632 {
633     BOOL m_bLeftButton;
634 
635     ShapeTool() : ToolBase(TOOL_SHAPE), m_bLeftButton(FALSE)
636     {
637     }
638 
639     void draw(BOOL bLeftButton, LONG x, LONG y, BOOL bClosed = FALSE)
640     {
641         if (pointSP + 1 >= 2)
642         {
643             if (bLeftButton)
644                 Poly(m_hdc, pointStack, pointSP + 1, m_fg, m_bg, toolsModel.GetLineWidth(), toolsModel.GetShapeStyle(), bClosed, FALSE);
645             else
646                 Poly(m_hdc, pointStack, pointSP + 1, m_bg, m_fg, toolsModel.GetLineWidth(), toolsModel.GetShapeStyle(), bClosed, FALSE);
647         }
648         m_bLeftButton = bLeftButton;
649     }
650 
651     void OnButtonDown(BOOL bLeftButton, LONG x, LONG y, BOOL bDoubleClick)
652     {
653         pointStack[pointSP].x = x;
654         pointStack[pointSP].y = y;
655 
656         if (pointSP == 0 && !bDoubleClick)
657         {
658             imageModel.CopyPrevious();
659             draw(bLeftButton, x, y);
660             pointSP++;
661         }
662         else
663         {
664             draw(bLeftButton, x, y, bDoubleClick);
665         }
666     }
667 
668     void OnMouseMove(BOOL bLeftButton, LONG x, LONG y)
669     {
670         imageModel.ResetToPrevious();
671         pointStack[pointSP].x = x;
672         pointStack[pointSP].y = y;
673         if ((pointSP > 0) && (GetAsyncKeyState(VK_SHIFT) < 0))
674             roundTo8Directions(pointStack[pointSP - 1].x, pointStack[pointSP - 1].y, x, y);
675         draw(bLeftButton, x, y, FALSE);
676     }
677 
678     void OnButtonUp(BOOL bLeftButton, LONG x, LONG y)
679     {
680         imageModel.ResetToPrevious();
681         if ((pointSP > 0) && (GetAsyncKeyState(VK_SHIFT) < 0))
682             roundTo8Directions(pointStack[pointSP - 1].x, pointStack[pointSP - 1].y, x, y);
683 
684         if (nearlyEqualPoints(x, y, pointStack[0].x, pointStack[0].y))
685         {
686             pointSP--;
687             draw(bLeftButton, x, y, TRUE);
688             pointSP = 0;
689         }
690         else
691         {
692             pointSP++;
693             pointStack[pointSP].x = x;
694             pointStack[pointSP].y = y;
695             draw(bLeftButton, x, y, FALSE);
696         }
697 
698         if (pointSP == _countof(pointStack))
699             pointSP--;
700     }
701 
702     void OnCancelDraw()
703     {
704         imageModel.Undo(TRUE);
705         ToolBase::OnCancelDraw();
706     }
707 
708     void OnFinishDraw()
709     {
710         if (pointSP)
711         {
712             imageModel.ResetToPrevious();
713             --pointSP;
714             draw(m_bLeftButton, -1, -1, TRUE);
715             pointSP = 0;
716         }
717         else
718         {
719             imageModel.Undo(TRUE);
720         }
721         ToolBase::OnFinishDraw();
722     }
723 };
724 
725 // TOOL_ELLIPSE
726 struct EllipseTool : GenericDrawTool
727 {
728     EllipseTool() : GenericDrawTool(TOOL_ELLIPSE)
729     {
730     }
731 
732     virtual void draw(BOOL bLeftButton, LONG x, LONG y)
733     {
734         imageModel.ResetToPrevious();
735         if (GetAsyncKeyState(VK_SHIFT) < 0)
736             regularize(start.x, start.y, x, y);
737         if (bLeftButton)
738             Ellp(m_hdc, start.x, start.y, x, y, m_fg, m_bg, toolsModel.GetLineWidth(), toolsModel.GetShapeStyle());
739         else
740             Ellp(m_hdc, start.x, start.y, x, y, m_bg, m_fg, toolsModel.GetLineWidth(), toolsModel.GetShapeStyle());
741     }
742 };
743 
744 // TOOL_RRECT
745 struct RRectTool : GenericDrawTool
746 {
747     RRectTool() : GenericDrawTool(TOOL_RRECT)
748     {
749     }
750 
751     virtual void draw(BOOL bLeftButton, LONG x, LONG y)
752     {
753         imageModel.ResetToPrevious();
754         if (GetAsyncKeyState(VK_SHIFT) < 0)
755             regularize(start.x, start.y, x, y);
756         if (bLeftButton)
757             RRect(m_hdc, start.x, start.y, x, y, m_fg, m_bg, toolsModel.GetLineWidth(), toolsModel.GetShapeStyle());
758         else
759             RRect(m_hdc, start.x, start.y, x, y, m_bg, m_fg, toolsModel.GetLineWidth(), toolsModel.GetShapeStyle());
760     }
761 };
762 
763 /*static*/ ToolBase*
764 ToolBase::createToolObject(TOOLTYPE type)
765 {
766     switch (type)
767     {
768         case TOOL_FREESEL:  return new FreeSelTool();
769         case TOOL_RECTSEL:  return new RectSelTool();
770         case TOOL_RUBBER:   return new RubberTool();
771         case TOOL_FILL:     return new FillTool();
772         case TOOL_COLOR:    return new ColorTool();
773         case TOOL_ZOOM:     return new ZoomTool();
774         case TOOL_PEN:      return new PenTool();
775         case TOOL_BRUSH:    return new BrushTool();
776         case TOOL_AIRBRUSH: return new AirBrushTool();
777         case TOOL_TEXT:     return new TextTool();
778         case TOOL_LINE:     return new LineTool();
779         case TOOL_BEZIER:   return new BezierTool();
780         case TOOL_RECT:     return new RectTool();
781         case TOOL_SHAPE:    return new ShapeTool();
782         case TOOL_ELLIPSE:  return new EllipseTool();
783         case TOOL_RRECT:    return new RRectTool();
784     }
785     UNREACHABLE;
786     return NULL;
787 }
788