[MSPAINT] Make sure that the selection is not resized to less than 1x1 pixels
[reactos.git] / reactos / base / applications / mspaint / selection.c
1 /*
2 * PROJECT: PAINT for ReactOS
3 * LICENSE: LGPL
4 * FILE: base/applications/paint/selection.c
5 * PURPOSE: Window procedure of the selection window
6 * PROGRAMMERS: Benedikt Freisen
7 */
8
9 /* INCLUDES *********************************************************/
10
11 #include "precomp.h"
12
13 /* FUNCTIONS ********************************************************/
14
15 LPCTSTR cursors[9] = { IDC_SIZEALL, IDC_SIZENWSE, IDC_SIZENS, IDC_SIZENESW,
16 IDC_SIZEWE, IDC_SIZEWE, IDC_SIZENESW, IDC_SIZENS, IDC_SIZENWSE
17 };
18
19 BOOL moving = FALSE;
20 int action = 0;
21 POINTS pos;
22 POINTS frac;
23 POINT delta;
24
25 BOOL
26 ColorKeyedMaskBlt(HDC hdcDest, int nXDest, int nYDest, int nWidth, int nHeight, HDC hdcSrc, int nXSrc, int nYSrc, HBITMAP hbmMask, int xMask, int yMask, DWORD dwRop, COLORREF keyColor)
27 {
28 HDC hTempDC;
29 HDC hTempDC2;
30 HBITMAP hTempBm;
31 HBRUSH hTempBrush;
32 HBITMAP hTempMask;
33
34 hTempDC = CreateCompatibleDC(hdcSrc);
35 hTempDC2 = CreateCompatibleDC(hdcSrc);
36 hTempBm = CreateCompatibleBitmap(hTempDC, nWidth, nHeight);
37 SelectObject(hTempDC, hTempBm);
38 hTempBrush = CreateSolidBrush(keyColor);
39 SelectObject(hTempDC, hTempBrush);
40 BitBlt(hTempDC, 0, 0, nWidth, nHeight, hdcSrc, nXSrc, nYSrc, SRCCOPY);
41 PatBlt(hTempDC, 0, 0, nWidth, nHeight, PATINVERT);
42 hTempMask = CreateBitmap(nWidth, nHeight, 1, 1, NULL);
43 SelectObject(hTempDC2, hTempMask);
44 BitBlt(hTempDC2, 0, 0, nWidth, nHeight, hTempDC, 0, 0, SRCCOPY);
45 SelectObject(hTempDC, hbmMask);
46 BitBlt(hTempDC2, 0, 0, nWidth, nHeight, hTempDC, xMask, yMask, SRCAND);
47 MaskBlt(hdcDest, nXDest, nYDest, nWidth, nHeight, hdcSrc, nXSrc, nYSrc, hTempMask, xMask, yMask, dwRop);
48 DeleteDC(hTempDC);
49 DeleteDC(hTempDC2);
50 DeleteObject(hTempBm);
51 DeleteObject(hTempBrush);
52 DeleteObject(hTempMask);
53 return TRUE;
54 }
55
56 void
57 ForceRefreshSelectionContents()
58 {
59 if (IsWindowVisible(hSelection))
60 {
61 SendMessage(hSelection, WM_LBUTTONDOWN, 0, MAKELPARAM(0, 0));
62 SendMessage(hSelection, WM_MOUSEMOVE, 0, MAKELPARAM(0, 0));
63 SendMessage(hSelection, WM_LBUTTONUP, 0, MAKELPARAM(0, 0));
64 }
65 }
66
67 int
68 identifyCorner(short x, short y, short w, short h)
69 {
70 if (y < 3)
71 {
72 if (x < 3)
73 return 1;
74 if ((x < w / 2 + 2) && (x >= w / 2 - 1))
75 return 2;
76 if (x >= w - 3)
77 return 3;
78 }
79 if ((y < h / 2 + 2) && (y >= h / 2 - 1))
80 {
81 if (x < 3)
82 return 4;
83 if (x >= w - 3)
84 return 5;
85 }
86 if (y >= h - 3)
87 {
88 if (x < 3)
89 return 6;
90 if ((x < w / 2 + 2) && (x >= w / 2 - 1))
91 return 7;
92 if (x >= w - 3)
93 return 8;
94 }
95 return 0;
96 }
97
98 LRESULT CALLBACK
99 SelectionWinProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
100 {
101 switch (message)
102 {
103 case WM_PAINT:
104 {
105 if (!moving)
106 {
107 HDC hDC = GetDC(hwnd);
108 DefWindowProc(hwnd, message, wParam, lParam);
109 SelectionFrame(hDC, 1, 1, RECT_WIDTH(rectSel_dest) * zoom / 1000 + 5,
110 RECT_HEIGHT(rectSel_dest) * zoom / 1000 + 5);
111 ReleaseDC(hwnd, hDC);
112 }
113 break;
114 }
115 case WM_LBUTTONDOWN:
116 pos.x = GET_X_LPARAM(lParam);
117 pos.y = GET_Y_LPARAM(lParam);
118 delta.x = 0;
119 delta.y = 0;
120 SetCapture(hwnd);
121 if (action != 0)
122 SetCursor(LoadCursor(NULL, cursors[action]));
123 moving = TRUE;
124 break;
125 case WM_MOUSEMOVE:
126 if (moving)
127 {
128 TCHAR sizeStr[100];
129 POINT deltaUsed;
130 resetToU1();
131 frac.x += GET_X_LPARAM(lParam) - pos.x;
132 frac.y += GET_Y_LPARAM(lParam) - pos.y;
133 delta.x += frac.x * 1000 / zoom;
134 delta.y += frac.y * 1000 / zoom;
135 if (zoom < 1000)
136 {
137 frac.x = 0;
138 frac.y = 0;
139 }
140 else
141 {
142 frac.x -= (frac.x * 1000 / zoom) * zoom / 1000;
143 frac.y -= (frac.y * 1000 / zoom) * zoom / 1000;
144 }
145 switch (action)
146 {
147 case 0: /* move selection */
148 deltaUsed.x = delta.x;
149 deltaUsed.y = delta.y;
150 OffsetRect(&rectSel_dest, deltaUsed.x, deltaUsed.y);
151 break;
152 case 1: /* resize at upper left corner */
153 deltaUsed.x = min(delta.x, RECT_WIDTH(rectSel_dest) - 1);
154 deltaUsed.y = min(delta.y, RECT_HEIGHT(rectSel_dest) - 1);
155 rectSel_dest.left += deltaUsed.x;
156 rectSel_dest.top += deltaUsed.y;
157 break;
158 case 2: /* resize at top edge */
159 deltaUsed.x = delta.x;
160 deltaUsed.y = min(delta.y, RECT_HEIGHT(rectSel_dest) - 1);
161 rectSel_dest.top += deltaUsed.y;
162 break;
163 case 3: /* resize at upper right corner */
164 deltaUsed.x = max(delta.x, -(RECT_WIDTH(rectSel_dest) - 1));
165 deltaUsed.y = min(delta.y, RECT_HEIGHT(rectSel_dest) - 1);
166 rectSel_dest.top += deltaUsed.y;
167 rectSel_dest.right += deltaUsed.x;
168 break;
169 case 4: /* resize at left edge */
170 deltaUsed.x = min(delta.x, RECT_WIDTH(rectSel_dest) - 1);
171 deltaUsed.y = delta.y;
172 rectSel_dest.left += deltaUsed.x;
173 break;
174 case 5: /* resize at right edge */
175 deltaUsed.x = max(delta.x, -(RECT_WIDTH(rectSel_dest) - 1));
176 deltaUsed.y = delta.y;
177 rectSel_dest.right += deltaUsed.x;
178 break;
179 case 6: /* resize at lower left corner */
180 deltaUsed.x = min(delta.x, RECT_WIDTH(rectSel_dest) - 1);
181 deltaUsed.y = max(delta.y, -(RECT_HEIGHT(rectSel_dest) - 1));
182 rectSel_dest.left += deltaUsed.x;
183 rectSel_dest.bottom += deltaUsed.y;
184 break;
185 case 7: /* resize at bottom edge */
186 deltaUsed.x = delta.x;
187 deltaUsed.y = max(delta.y, -(RECT_HEIGHT(rectSel_dest) - 1));
188 rectSel_dest.bottom += deltaUsed.y;
189 break;
190 case 8: /* resize at lower right corner */
191 deltaUsed.x = max(delta.x, -(RECT_WIDTH(rectSel_dest) - 1));
192 deltaUsed.y = max(delta.y, -(RECT_HEIGHT(rectSel_dest) - 1));
193 rectSel_dest.right += deltaUsed.x;
194 rectSel_dest.bottom += deltaUsed.y;
195 break;
196 }
197 delta.x -= deltaUsed.x;
198 delta.y -= deltaUsed.y;
199
200 _stprintf(sizeStr, _T("%d x %d"), RECT_WIDTH(rectSel_dest), RECT_HEIGHT(rectSel_dest));
201 SendMessage(hStatusBar, SB_SETTEXT, 2, (LPARAM) sizeStr);
202
203 if (activeTool == 10) /* text tool */
204 {
205 Text(hDrawingDC, rectSel_dest.left, rectSel_dest.top, rectSel_dest.right, rectSel_dest.bottom, fgColor, bgColor, textToolText, hfontTextFont, transpBg);
206 }
207 else
208 {
209 if (action != 0)
210 StretchBlt(hDrawingDC, rectSel_dest.left, rectSel_dest.top, RECT_WIDTH(rectSel_dest), RECT_HEIGHT(rectSel_dest), hSelDC, 0, 0, GetDIBWidth(hSelBm), GetDIBHeight(hSelBm), SRCCOPY);
211 else
212 if (transpBg == 0)
213 MaskBlt(hDrawingDC, rectSel_dest.left, rectSel_dest.top, RECT_WIDTH(rectSel_dest), RECT_HEIGHT(rectSel_dest),
214 hSelDC, 0, 0, hSelMask, 0, 0, MAKEROP4(SRCCOPY, SRCAND));
215 else
216 {
217 ColorKeyedMaskBlt(hDrawingDC, rectSel_dest.left, rectSel_dest.top, RECT_WIDTH(rectSel_dest), RECT_HEIGHT(rectSel_dest),
218 hSelDC, 0, 0, hSelMask, 0, 0, MAKEROP4(SRCCOPY, SRCAND), bgColor);
219 }
220 }
221 InvalidateRect(hImageArea, NULL, FALSE);
222 pos.x = GET_X_LPARAM(lParam);
223 pos.y = GET_Y_LPARAM(lParam);
224 //SendMessage(hwnd, WM_PAINT, 0, 0);
225 }
226 else
227 {
228 int w = RECT_WIDTH(rectSel_dest) * zoom / 1000 + 6;
229 int h = RECT_HEIGHT(rectSel_dest) * zoom / 1000 + 6;
230 pos.x = GET_X_LPARAM(lParam);
231 pos.y = GET_Y_LPARAM(lParam);
232 SendMessage(hStatusBar, SB_SETTEXT, 2, (LPARAM) NULL);
233 action = identifyCorner(pos.x, pos.y, w, h);
234 if (action != 0)
235 SetCursor(LoadCursor(NULL, cursors[action]));
236 }
237 break;
238 case WM_LBUTTONUP:
239 if (moving)
240 {
241 moving = FALSE;
242 ReleaseCapture();
243 if (action != 0)
244 {
245 if (activeTool == 10) /* text tool */
246 {
247
248 }
249 else
250 {
251 HDC hTempDC;
252 HBITMAP hTempBm;
253 hTempDC = CreateCompatibleDC(hSelDC);
254 hTempBm = CreateDIBWithProperties(RECT_WIDTH(rectSel_dest), RECT_HEIGHT(rectSel_dest));
255 SelectObject(hTempDC, hTempBm);
256 SelectObject(hSelDC, hSelBm);
257 StretchBlt(hTempDC, 0, 0, RECT_WIDTH(rectSel_dest), RECT_HEIGHT(rectSel_dest), hSelDC, 0, 0,
258 GetDIBWidth(hSelBm), GetDIBHeight(hSelBm), SRCCOPY);
259 DeleteObject(hSelBm);
260 hSelBm = hTempBm;
261 hTempBm = CreateBitmap(RECT_WIDTH(rectSel_dest), RECT_HEIGHT(rectSel_dest), 1, 1, NULL);
262 SelectObject(hTempDC, hTempBm);
263 SelectObject(hSelDC, hSelMask);
264 StretchBlt(hTempDC, 0, 0, RECT_WIDTH(rectSel_dest), RECT_HEIGHT(rectSel_dest), hSelDC, 0, 0,
265 GetDIBWidth(hSelMask), GetDIBHeight(hSelMask), SRCCOPY);
266 DeleteObject(hSelMask);
267 hSelMask = hTempBm;
268 SelectObject(hSelDC, hSelBm);
269 DeleteDC(hTempDC);
270 }
271 }
272 placeSelWin();
273 ShowWindow(hSelection, SW_HIDE);
274 ShowWindow(hSelection, SW_SHOW);
275 }
276 break;
277 default:
278 return DefWindowProc(hwnd, message, wParam, lParam);
279 }
280
281 return 0;
282 }