[MSPAINT_NEW] manage palette and tools data in a PaletteModel and ToolsModel class...
[reactos.git] / reactos / base / applications / mspaint_new / selection.cpp
1 /*
2 * PROJECT: PAINT for ReactOS
3 * LICENSE: LGPL
4 * FILE: base/applications/mspaint_new/selection.cpp
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 DWORD system_selection_color;
41
42 BOOL
43 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)
44 {
45 HDC hTempDC;
46 HDC hTempDC2;
47 HBITMAP hTempBm;
48 HBRUSH hTempBrush;
49 HBITMAP hTempMask;
50
51 hTempDC = CreateCompatibleDC(hdcSrc);
52 hTempDC2 = CreateCompatibleDC(hdcSrc);
53 hTempBm = CreateCompatibleBitmap(hTempDC, nWidth, nHeight);
54 SelectObject(hTempDC, hTempBm);
55 hTempBrush = CreateSolidBrush(keyColor);
56 SelectObject(hTempDC, hTempBrush);
57 BitBlt(hTempDC, 0, 0, nWidth, nHeight, hdcSrc, nXSrc, nYSrc, SRCCOPY);
58 PatBlt(hTempDC, 0, 0, nWidth, nHeight, PATINVERT);
59 hTempMask = CreateBitmap(nWidth, nHeight, 1, 1, NULL);
60 SelectObject(hTempDC2, hTempMask);
61 BitBlt(hTempDC2, 0, 0, nWidth, nHeight, hTempDC, 0, 0, SRCCOPY);
62 SelectObject(hTempDC, hbmMask);
63 BitBlt(hTempDC2, 0, 0, nWidth, nHeight, hTempDC, xMask, yMask, SRCAND);
64 MaskBlt(hdcDest, nXDest, nYDest, nWidth, nHeight, hdcSrc, nXSrc, nYSrc, hTempMask, xMask, yMask, dwRop);
65 DeleteDC(hTempDC);
66 DeleteDC(hTempDC2);
67 DeleteObject(hTempBm);
68 DeleteObject(hTempBrush);
69 DeleteObject(hTempMask);
70 return TRUE;
71 }
72
73 void
74 ForceRefreshSelectionContents()
75 {
76 if (selectionWindow.IsWindowVisible())
77 {
78 selectionWindow.SendMessage(WM_LBUTTONDOWN, 0, MAKELPARAM(0, 0));
79 selectionWindow.SendMessage(WM_MOUSEMOVE, 0, MAKELPARAM(0, 0));
80 selectionWindow.SendMessage(WM_LBUTTONUP, 0, MAKELPARAM(0, 0));
81 }
82 }
83
84 int
85 identifyCorner(short x, short y, short w, short h)
86 {
87 if (y < 3)
88 {
89 if (x < 3)
90 return ACTION_RESIZE_TOP_LEFT;
91 if ((x < w / 2 + 2) && (x >= w / 2 - 1))
92 return ACTION_RESIZE_TOP;
93 if (x >= w - 3)
94 return ACTION_RESIZE_TOP_RIGHT;
95 }
96 if ((y < h / 2 + 2) && (y >= h / 2 - 1))
97 {
98 if (x < 3)
99 return ACTION_RESIZE_LEFT;
100 if (x >= w - 3)
101 return ACTION_RESIZE_RIGHT;
102 }
103 if (y >= h - 3)
104 {
105 if (x < 3)
106 return ACTION_RESIZE_BOTTOM_LEFT;
107 if ((x < w / 2 + 2) && (x >= w / 2 - 1))
108 return ACTION_RESIZE_BOTTOM;
109 if (x >= w - 3)
110 return ACTION_RESIZE_BOTTOM_RIGHT;
111 }
112 return 0;
113 }
114
115 LRESULT CSelectionWindow::OnPaint(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
116 {
117 if (!moving)
118 {
119 HDC hDC = GetDC();
120 DefWindowProc(WM_PAINT, wParam, lParam);
121 SelectionFrame(hDC, 1, 1, RECT_WIDTH(rectSel_dest) * toolsModel.GetZoom() / 1000 + 5,
122 RECT_HEIGHT(rectSel_dest) * toolsModel.GetZoom() / 1000 + 5,
123 system_selection_color);
124 ReleaseDC(hDC);
125 }
126 return 0;
127 }
128
129 LRESULT CSelectionWindow::OnEraseBkgnd(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
130 {
131 // do nothing => transparent background
132 return 0;
133 }
134
135 LRESULT CSelectionWindow::OnCreate(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
136 {
137 /* update the system selection color */
138 system_selection_color = GetSysColor(COLOR_HIGHLIGHT);
139 SendMessage(WM_PAINT, 0, MAKELPARAM(0, 0));
140 return 0;
141 }
142
143 LRESULT CSelectionWindow::OnSysColorChange(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
144 {
145 /* update the system selection color */
146 system_selection_color = GetSysColor(COLOR_HIGHLIGHT);
147 SendMessage(WM_PAINT, 0, MAKELPARAM(0, 0));
148 return 0;
149 }
150
151 LRESULT CSelectionWindow::OnSetCursor(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
152 {
153 SetCursor(LoadCursor(NULL, IDC_SIZEALL));
154 return 0;
155 }
156
157 LRESULT CSelectionWindow::OnLButtonDown(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
158 {
159 pos.x = GET_X_LPARAM(lParam);
160 pos.y = GET_Y_LPARAM(lParam);
161 delta.x = 0;
162 delta.y = 0;
163 SetCapture();
164 if (action != ACTION_MOVE)
165 SetCursor(LoadCursor(NULL, cursors[action]));
166 moving = TRUE;
167 scrlClientWindow.InvalidateRect(NULL, TRUE);
168 imageArea.SendMessage(WM_PAINT, 0, 0);
169 return 0;
170 }
171
172 LRESULT CSelectionWindow::OnMouseMove(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
173 {
174 if (moving)
175 {
176 TCHAR sizeStr[100];
177 POINT deltaUsed;
178 resetToU1();
179 frac.x += GET_X_LPARAM(lParam) - pos.x;
180 frac.y += GET_Y_LPARAM(lParam) - pos.y;
181 delta.x += frac.x * 1000 / toolsModel.GetZoom();
182 delta.y += frac.y * 1000 / toolsModel.GetZoom();
183 if (toolsModel.GetZoom() < 1000)
184 {
185 frac.x = 0;
186 frac.y = 0;
187 }
188 else
189 {
190 frac.x -= (frac.x * 1000 / toolsModel.GetZoom()) * toolsModel.GetZoom() / 1000;
191 frac.y -= (frac.y * 1000 / toolsModel.GetZoom()) * toolsModel.GetZoom() / 1000;
192 }
193 switch (action)
194 {
195 case ACTION_MOVE: /* move selection */
196 deltaUsed.x = delta.x;
197 deltaUsed.y = delta.y;
198 OffsetRect(&rectSel_dest, deltaUsed.x, deltaUsed.y);
199 break;
200 case ACTION_RESIZE_TOP_LEFT: /* resize at upper left corner */
201 deltaUsed.x = min(delta.x, RECT_WIDTH(rectSel_dest) - 1);
202 deltaUsed.y = min(delta.y, RECT_HEIGHT(rectSel_dest) - 1);
203 rectSel_dest.left += deltaUsed.x;
204 rectSel_dest.top += deltaUsed.y;
205 break;
206 case ACTION_RESIZE_TOP: /* resize at top edge */
207 deltaUsed.x = delta.x;
208 deltaUsed.y = min(delta.y, RECT_HEIGHT(rectSel_dest) - 1);
209 rectSel_dest.top += deltaUsed.y;
210 break;
211 case ACTION_RESIZE_TOP_RIGHT: /* resize at upper right corner */
212 deltaUsed.x = max(delta.x, -(RECT_WIDTH(rectSel_dest) - 1));
213 deltaUsed.y = min(delta.y, RECT_HEIGHT(rectSel_dest) - 1);
214 rectSel_dest.top += deltaUsed.y;
215 rectSel_dest.right += deltaUsed.x;
216 break;
217 case ACTION_RESIZE_LEFT: /* resize at left edge */
218 deltaUsed.x = min(delta.x, RECT_WIDTH(rectSel_dest) - 1);
219 deltaUsed.y = delta.y;
220 rectSel_dest.left += deltaUsed.x;
221 break;
222 case ACTION_RESIZE_RIGHT: /* resize at right edge */
223 deltaUsed.x = max(delta.x, -(RECT_WIDTH(rectSel_dest) - 1));
224 deltaUsed.y = delta.y;
225 rectSel_dest.right += deltaUsed.x;
226 break;
227 case ACTION_RESIZE_BOTTOM_LEFT: /* resize at lower left corner */
228 deltaUsed.x = min(delta.x, RECT_WIDTH(rectSel_dest) - 1);
229 deltaUsed.y = max(delta.y, -(RECT_HEIGHT(rectSel_dest) - 1));
230 rectSel_dest.left += deltaUsed.x;
231 rectSel_dest.bottom += deltaUsed.y;
232 break;
233 case ACTION_RESIZE_BOTTOM: /* resize at bottom edge */
234 deltaUsed.x = delta.x;
235 deltaUsed.y = max(delta.y, -(RECT_HEIGHT(rectSel_dest) - 1));
236 rectSel_dest.bottom += deltaUsed.y;
237 break;
238 case ACTION_RESIZE_BOTTOM_RIGHT: /* resize at lower right corner */
239 deltaUsed.x = max(delta.x, -(RECT_WIDTH(rectSel_dest) - 1));
240 deltaUsed.y = max(delta.y, -(RECT_HEIGHT(rectSel_dest) - 1));
241 rectSel_dest.right += deltaUsed.x;
242 rectSel_dest.bottom += deltaUsed.y;
243 break;
244 }
245 delta.x -= deltaUsed.x;
246 delta.y -= deltaUsed.y;
247
248 _stprintf(sizeStr, _T("%d x %d"), RECT_WIDTH(rectSel_dest), RECT_HEIGHT(rectSel_dest));
249 SendMessage(hStatusBar, SB_SETTEXT, 2, (LPARAM) sizeStr);
250
251 if (toolsModel.GetActiveTool() == TOOL_TEXT)
252 {
253 Text(hDrawingDC, rectSel_dest.left, rectSel_dest.top, rectSel_dest.right, rectSel_dest.bottom, paletteModel.GetFgColor(), paletteModel.GetBgColor(), textToolText, hfontTextFont, toolsModel.IsBackgroundTransparent());
254 }
255 else
256 {
257 if (action != ACTION_MOVE)
258 StretchBlt(hDrawingDC, rectSel_dest.left, rectSel_dest.top, RECT_WIDTH(rectSel_dest), RECT_HEIGHT(rectSel_dest), hSelDC, 0, 0, GetDIBWidth(hSelBm), GetDIBHeight(hSelBm), SRCCOPY);
259 else
260 if (toolsModel.IsBackgroundTransparent() == 0)
261 MaskBlt(hDrawingDC, rectSel_dest.left, rectSel_dest.top, RECT_WIDTH(rectSel_dest), RECT_HEIGHT(rectSel_dest),
262 hSelDC, 0, 0, hSelMask, 0, 0, MAKEROP4(SRCCOPY, SRCAND));
263 else
264 {
265 ColorKeyedMaskBlt(hDrawingDC, rectSel_dest.left, rectSel_dest.top, RECT_WIDTH(rectSel_dest), RECT_HEIGHT(rectSel_dest),
266 hSelDC, 0, 0, hSelMask, 0, 0, MAKEROP4(SRCCOPY, SRCAND), paletteModel.GetBgColor());
267 }
268 }
269 imageArea.InvalidateRect(NULL, FALSE);
270 imageArea.SendMessage(WM_PAINT, 0, 0);
271 pos.x = GET_X_LPARAM(lParam);
272 pos.y = GET_Y_LPARAM(lParam);
273 }
274 else
275 {
276 int w = RECT_WIDTH(rectSel_dest) * toolsModel.GetZoom() / 1000 + 6;
277 int h = RECT_HEIGHT(rectSel_dest) * toolsModel.GetZoom() / 1000 + 6;
278 pos.x = GET_X_LPARAM(lParam);
279 pos.y = GET_Y_LPARAM(lParam);
280 SendMessage(hStatusBar, SB_SETTEXT, 2, (LPARAM) NULL);
281 action = identifyCorner(pos.x, pos.y, w, h);
282 if (action != ACTION_MOVE)
283 SetCursor(LoadCursor(NULL, cursors[action]));
284 }
285 return 0;
286 }
287
288 LRESULT CSelectionWindow::OnLButtonUp(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
289 {
290 if (moving)
291 {
292 moving = FALSE;
293 ReleaseCapture();
294 if (action != ACTION_MOVE)
295 {
296 if (toolsModel.GetActiveTool() == TOOL_TEXT)
297 {
298 // FIXME: What to do?
299 }
300 else
301 {
302 HDC hTempDC;
303 HBITMAP hTempBm;
304 hTempDC = CreateCompatibleDC(hSelDC);
305 hTempBm = CreateDIBWithProperties(RECT_WIDTH(rectSel_dest), RECT_HEIGHT(rectSel_dest));
306 SelectObject(hTempDC, hTempBm);
307 SelectObject(hSelDC, hSelBm);
308 StretchBlt(hTempDC, 0, 0, RECT_WIDTH(rectSel_dest), RECT_HEIGHT(rectSel_dest), hSelDC, 0, 0,
309 GetDIBWidth(hSelBm), GetDIBHeight(hSelBm), SRCCOPY);
310 DeleteObject(hSelBm);
311 hSelBm = hTempBm;
312 hTempBm = CreateBitmap(RECT_WIDTH(rectSel_dest), RECT_HEIGHT(rectSel_dest), 1, 1, NULL);
313 SelectObject(hTempDC, hTempBm);
314 SelectObject(hSelDC, hSelMask);
315 StretchBlt(hTempDC, 0, 0, RECT_WIDTH(rectSel_dest), RECT_HEIGHT(rectSel_dest), hSelDC, 0, 0,
316 GetDIBWidth(hSelMask), GetDIBHeight(hSelMask), SRCCOPY);
317 DeleteObject(hSelMask);
318 hSelMask = hTempBm;
319 SelectObject(hSelDC, hSelBm);
320 DeleteDC(hTempDC);
321 }
322 }
323 placeSelWin();
324 ShowWindow(SW_HIDE);
325 ShowWindow(SW_SHOW);
326 }
327 return 0;
328 }