Create a branch for console restructuration work.
[reactos.git] / 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 /* DEFINES **********************************************************/
14
15 #define ACTION_MOVE 0
16 #define ACTION_RESIZE_TOP_LEFT 1
17 #define ACTION_RESIZE_TOP 2
18 #define ACTION_RESIZE_TOP_RIGHT 3
19 #define ACTION_RESIZE_LEFT 4
20 #define ACTION_RESIZE_RIGHT 5
21 #define ACTION_RESIZE_BOTTOM_LEFT 6
22 #define ACTION_RESIZE_BOTTOM 7
23 #define ACTION_RESIZE_BOTTOM_RIGHT 8
24
25 /* FUNCTIONS ********************************************************/
26
27 LPCTSTR cursors[9] = { /* action to mouse cursor lookup table */
28 IDC_SIZEALL,
29
30 IDC_SIZENWSE, IDC_SIZENS, IDC_SIZENESW,
31 IDC_SIZEWE, IDC_SIZEWE,
32 IDC_SIZENESW, IDC_SIZENS, IDC_SIZENWSE
33 };
34
35 BOOL moving = FALSE;
36 int action = ACTION_MOVE;
37 POINTS pos;
38 POINTS frac;
39 POINT delta;
40
41 void
42 RegisterWclSelection()
43 {
44 WNDCLASSEX wclSelection;
45 /* initializing and registering the window class for the selection frame */
46 wclSelection.hInstance = hProgInstance;
47 wclSelection.lpszClassName = _T("Selection");
48 wclSelection.lpfnWndProc = SelectionWinProc;
49 wclSelection.style = CS_DBLCLKS;
50 wclSelection.cbSize = sizeof(WNDCLASSEX);
51 wclSelection.hIcon = NULL;
52 wclSelection.hIconSm = NULL;
53 wclSelection.hCursor = LoadCursor(NULL, IDC_SIZEALL);
54 wclSelection.lpszMenuName = NULL;
55 wclSelection.cbClsExtra = 0;
56 wclSelection.cbWndExtra = 0;
57 wclSelection.hbrBackground = NULL;
58 RegisterClassEx (&wclSelection);
59 }
60
61 BOOL
62 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)
63 {
64 HDC hTempDC;
65 HDC hTempDC2;
66 HBITMAP hTempBm;
67 HBRUSH hTempBrush;
68 HBITMAP hTempMask;
69
70 hTempDC = CreateCompatibleDC(hdcSrc);
71 hTempDC2 = CreateCompatibleDC(hdcSrc);
72 hTempBm = CreateCompatibleBitmap(hTempDC, nWidth, nHeight);
73 SelectObject(hTempDC, hTempBm);
74 hTempBrush = CreateSolidBrush(keyColor);
75 SelectObject(hTempDC, hTempBrush);
76 BitBlt(hTempDC, 0, 0, nWidth, nHeight, hdcSrc, nXSrc, nYSrc, SRCCOPY);
77 PatBlt(hTempDC, 0, 0, nWidth, nHeight, PATINVERT);
78 hTempMask = CreateBitmap(nWidth, nHeight, 1, 1, NULL);
79 SelectObject(hTempDC2, hTempMask);
80 BitBlt(hTempDC2, 0, 0, nWidth, nHeight, hTempDC, 0, 0, SRCCOPY);
81 SelectObject(hTempDC, hbmMask);
82 BitBlt(hTempDC2, 0, 0, nWidth, nHeight, hTempDC, xMask, yMask, SRCAND);
83 MaskBlt(hdcDest, nXDest, nYDest, nWidth, nHeight, hdcSrc, nXSrc, nYSrc, hTempMask, xMask, yMask, dwRop);
84 DeleteDC(hTempDC);
85 DeleteDC(hTempDC2);
86 DeleteObject(hTempBm);
87 DeleteObject(hTempBrush);
88 DeleteObject(hTempMask);
89 return TRUE;
90 }
91
92 void
93 ForceRefreshSelectionContents()
94 {
95 if (IsWindowVisible(hSelection))
96 {
97 SendMessage(hSelection, WM_LBUTTONDOWN, 0, MAKELPARAM(0, 0));
98 SendMessage(hSelection, WM_MOUSEMOVE, 0, MAKELPARAM(0, 0));
99 SendMessage(hSelection, WM_LBUTTONUP, 0, MAKELPARAM(0, 0));
100 }
101 }
102
103 int
104 identifyCorner(short x, short y, short w, short h)
105 {
106 if (y < 3)
107 {
108 if (x < 3)
109 return ACTION_RESIZE_TOP_LEFT;
110 if ((x < w / 2 + 2) && (x >= w / 2 - 1))
111 return ACTION_RESIZE_TOP;
112 if (x >= w - 3)
113 return ACTION_RESIZE_TOP_RIGHT;
114 }
115 if ((y < h / 2 + 2) && (y >= h / 2 - 1))
116 {
117 if (x < 3)
118 return ACTION_RESIZE_LEFT;
119 if (x >= w - 3)
120 return ACTION_RESIZE_RIGHT;
121 }
122 if (y >= h - 3)
123 {
124 if (x < 3)
125 return ACTION_RESIZE_BOTTOM_LEFT;
126 if ((x < w / 2 + 2) && (x >= w / 2 - 1))
127 return ACTION_RESIZE_BOTTOM;
128 if (x >= w - 3)
129 return ACTION_RESIZE_BOTTOM_RIGHT;
130 }
131 return 0;
132 }
133
134 LRESULT CALLBACK
135 SelectionWinProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
136 {
137 switch (message)
138 {
139 case WM_PAINT:
140 {
141 if (!moving)
142 {
143 HDC hDC = GetDC(hwnd);
144 DefWindowProc(hwnd, message, wParam, lParam);
145 SelectionFrame(hDC, 1, 1, RECT_WIDTH(rectSel_dest) * zoom / 1000 + 5,
146 RECT_HEIGHT(rectSel_dest) * zoom / 1000 + 5);
147 ReleaseDC(hwnd, hDC);
148 }
149 break;
150 }
151 case WM_LBUTTONDOWN:
152 pos.x = GET_X_LPARAM(lParam);
153 pos.y = GET_Y_LPARAM(lParam);
154 delta.x = 0;
155 delta.y = 0;
156 SetCapture(hwnd);
157 if (action != ACTION_MOVE)
158 SetCursor(LoadCursor(NULL, cursors[action]));
159 moving = TRUE;
160 InvalidateRect(hScrlClient, NULL, TRUE);
161 break;
162 case WM_MOUSEMOVE:
163 if (moving)
164 {
165 TCHAR sizeStr[100];
166 POINT deltaUsed;
167 resetToU1();
168 frac.x += GET_X_LPARAM(lParam) - pos.x;
169 frac.y += GET_Y_LPARAM(lParam) - pos.y;
170 delta.x += frac.x * 1000 / zoom;
171 delta.y += frac.y * 1000 / zoom;
172 if (zoom < 1000)
173 {
174 frac.x = 0;
175 frac.y = 0;
176 }
177 else
178 {
179 frac.x -= (frac.x * 1000 / zoom) * zoom / 1000;
180 frac.y -= (frac.y * 1000 / zoom) * zoom / 1000;
181 }
182 switch (action)
183 {
184 case ACTION_MOVE: /* move selection */
185 deltaUsed.x = delta.x;
186 deltaUsed.y = delta.y;
187 OffsetRect(&rectSel_dest, deltaUsed.x, deltaUsed.y);
188 break;
189 case ACTION_RESIZE_TOP_LEFT: /* resize at upper left corner */
190 deltaUsed.x = min(delta.x, RECT_WIDTH(rectSel_dest) - 1);
191 deltaUsed.y = min(delta.y, RECT_HEIGHT(rectSel_dest) - 1);
192 rectSel_dest.left += deltaUsed.x;
193 rectSel_dest.top += deltaUsed.y;
194 break;
195 case ACTION_RESIZE_TOP: /* resize at top edge */
196 deltaUsed.x = delta.x;
197 deltaUsed.y = min(delta.y, RECT_HEIGHT(rectSel_dest) - 1);
198 rectSel_dest.top += deltaUsed.y;
199 break;
200 case ACTION_RESIZE_TOP_RIGHT: /* resize at upper right corner */
201 deltaUsed.x = max(delta.x, -(RECT_WIDTH(rectSel_dest) - 1));
202 deltaUsed.y = min(delta.y, RECT_HEIGHT(rectSel_dest) - 1);
203 rectSel_dest.top += deltaUsed.y;
204 rectSel_dest.right += deltaUsed.x;
205 break;
206 case ACTION_RESIZE_LEFT: /* resize at left edge */
207 deltaUsed.x = min(delta.x, RECT_WIDTH(rectSel_dest) - 1);
208 deltaUsed.y = delta.y;
209 rectSel_dest.left += deltaUsed.x;
210 break;
211 case ACTION_RESIZE_RIGHT: /* resize at right edge */
212 deltaUsed.x = max(delta.x, -(RECT_WIDTH(rectSel_dest) - 1));
213 deltaUsed.y = delta.y;
214 rectSel_dest.right += deltaUsed.x;
215 break;
216 case ACTION_RESIZE_BOTTOM_LEFT: /* resize at lower left corner */
217 deltaUsed.x = min(delta.x, RECT_WIDTH(rectSel_dest) - 1);
218 deltaUsed.y = max(delta.y, -(RECT_HEIGHT(rectSel_dest) - 1));
219 rectSel_dest.left += deltaUsed.x;
220 rectSel_dest.bottom += deltaUsed.y;
221 break;
222 case ACTION_RESIZE_BOTTOM: /* resize at bottom edge */
223 deltaUsed.x = delta.x;
224 deltaUsed.y = max(delta.y, -(RECT_HEIGHT(rectSel_dest) - 1));
225 rectSel_dest.bottom += deltaUsed.y;
226 break;
227 case ACTION_RESIZE_BOTTOM_RIGHT: /* resize at lower right corner */
228 deltaUsed.x = max(delta.x, -(RECT_WIDTH(rectSel_dest) - 1));
229 deltaUsed.y = max(delta.y, -(RECT_HEIGHT(rectSel_dest) - 1));
230 rectSel_dest.right += deltaUsed.x;
231 rectSel_dest.bottom += deltaUsed.y;
232 break;
233 }
234 delta.x -= deltaUsed.x;
235 delta.y -= deltaUsed.y;
236
237 _stprintf(sizeStr, _T("%d x %d"), RECT_WIDTH(rectSel_dest), RECT_HEIGHT(rectSel_dest));
238 SendMessage(hStatusBar, SB_SETTEXT, 2, (LPARAM) sizeStr);
239
240 if (activeTool == TOOL_TEXT)
241 {
242 Text(hDrawingDC, rectSel_dest.left, rectSel_dest.top, rectSel_dest.right, rectSel_dest.bottom, fgColor, bgColor, textToolText, hfontTextFont, transpBg);
243 }
244 else
245 {
246 if (action != ACTION_MOVE)
247 StretchBlt(hDrawingDC, rectSel_dest.left, rectSel_dest.top, RECT_WIDTH(rectSel_dest), RECT_HEIGHT(rectSel_dest), hSelDC, 0, 0, GetDIBWidth(hSelBm), GetDIBHeight(hSelBm), SRCCOPY);
248 else
249 if (transpBg == 0)
250 MaskBlt(hDrawingDC, rectSel_dest.left, rectSel_dest.top, RECT_WIDTH(rectSel_dest), RECT_HEIGHT(rectSel_dest),
251 hSelDC, 0, 0, hSelMask, 0, 0, MAKEROP4(SRCCOPY, SRCAND));
252 else
253 {
254 ColorKeyedMaskBlt(hDrawingDC, rectSel_dest.left, rectSel_dest.top, RECT_WIDTH(rectSel_dest), RECT_HEIGHT(rectSel_dest),
255 hSelDC, 0, 0, hSelMask, 0, 0, MAKEROP4(SRCCOPY, SRCAND), bgColor);
256 }
257 }
258 InvalidateRect(hImageArea, NULL, FALSE);
259 pos.x = GET_X_LPARAM(lParam);
260 pos.y = GET_Y_LPARAM(lParam);
261 }
262 else
263 {
264 int w = RECT_WIDTH(rectSel_dest) * zoom / 1000 + 6;
265 int h = RECT_HEIGHT(rectSel_dest) * zoom / 1000 + 6;
266 pos.x = GET_X_LPARAM(lParam);
267 pos.y = GET_Y_LPARAM(lParam);
268 SendMessage(hStatusBar, SB_SETTEXT, 2, (LPARAM) NULL);
269 action = identifyCorner(pos.x, pos.y, w, h);
270 if (action != ACTION_MOVE)
271 SetCursor(LoadCursor(NULL, cursors[action]));
272 }
273 break;
274 case WM_LBUTTONUP:
275 if (moving)
276 {
277 moving = FALSE;
278 ReleaseCapture();
279 if (action != ACTION_MOVE)
280 {
281 if (activeTool == TOOL_TEXT)
282 {
283
284 }
285 else
286 {
287 HDC hTempDC;
288 HBITMAP hTempBm;
289 hTempDC = CreateCompatibleDC(hSelDC);
290 hTempBm = CreateDIBWithProperties(RECT_WIDTH(rectSel_dest), RECT_HEIGHT(rectSel_dest));
291 SelectObject(hTempDC, hTempBm);
292 SelectObject(hSelDC, hSelBm);
293 StretchBlt(hTempDC, 0, 0, RECT_WIDTH(rectSel_dest), RECT_HEIGHT(rectSel_dest), hSelDC, 0, 0,
294 GetDIBWidth(hSelBm), GetDIBHeight(hSelBm), SRCCOPY);
295 DeleteObject(hSelBm);
296 hSelBm = hTempBm;
297 hTempBm = CreateBitmap(RECT_WIDTH(rectSel_dest), RECT_HEIGHT(rectSel_dest), 1, 1, NULL);
298 SelectObject(hTempDC, hTempBm);
299 SelectObject(hSelDC, hSelMask);
300 StretchBlt(hTempDC, 0, 0, RECT_WIDTH(rectSel_dest), RECT_HEIGHT(rectSel_dest), hSelDC, 0, 0,
301 GetDIBWidth(hSelMask), GetDIBHeight(hSelMask), SRCCOPY);
302 DeleteObject(hSelMask);
303 hSelMask = hTempBm;
304 SelectObject(hSelDC, hSelBm);
305 DeleteDC(hTempDC);
306 }
307 }
308 placeSelWin();
309 ShowWindow(hSelection, SW_HIDE);
310 ShowWindow(hSelection, SW_SHOW);
311 }
312 break;
313 default:
314 return DefWindowProc(hwnd, message, wParam, lParam);
315 }
316
317 return 0;
318 }