[MSPAINT]
[reactos.git] / reactos / base / applications / mspaint / imgarea.cpp
1 /*
2 * PROJECT: PAINT for ReactOS
3 * LICENSE: LGPL
4 * FILE: base/applications/mspaint/imgarea.cpp
5 * PURPOSE: Window procedure of the main window and all children apart from
6 * hPalWin, hToolSettings and hSelection
7 * PROGRAMMERS: Benedikt Freisen
8 * Katayama Hirofumi MZ
9 */
10
11 /* INCLUDES *********************************************************/
12
13 #include "precomp.h"
14
15 #include "dialogs.h"
16
17 /* FUNCTIONS ********************************************************/
18
19 extern void
20 zoomTo(int newZoom, int mouseX, int mouseY);
21
22 void
23 updateCanvasAndScrollbars()
24 {
25 selectionWindow.ShowWindow(SW_HIDE);
26 imageArea.MoveWindow(3, 3, imageModel.GetWidth() * toolsModel.GetZoom() / 1000, imageModel.GetHeight() * toolsModel.GetZoom() / 1000, FALSE);
27 scrollboxWindow.Invalidate(TRUE);
28 imageArea.Invalidate(FALSE);
29
30 scrollboxWindow.SetScrollPos(SB_HORZ, 0, TRUE);
31 scrollboxWindow.SetScrollPos(SB_VERT, 0, TRUE);
32 }
33
34 void CImgAreaWindow::drawZoomFrame(int mouseX, int mouseY)
35 {
36 HDC hdc;
37 HPEN oldPen;
38 HBRUSH oldBrush;
39 LOGBRUSH logbrush;
40 int rop;
41
42 RECT clientRectScrollbox;
43 RECT clientRectImageArea;
44 int x, y, w, h;
45 scrollboxWindow.GetClientRect(&clientRectScrollbox);
46 GetClientRect(&clientRectImageArea);
47 w = clientRectImageArea.right * clientRectScrollbox.right / (clientRectImageArea.right * 2);
48 h = clientRectImageArea.bottom * clientRectScrollbox.bottom / (clientRectImageArea.bottom * 2);
49 x = max(0, min(clientRectImageArea.right - w, mouseX - w / 2));
50 y = max(0, min(clientRectImageArea.bottom - h, mouseY - h / 2));
51
52 hdc = GetDC();
53 oldPen = (HPEN) SelectObject(hdc, CreatePen(PS_SOLID, 0, 0));
54 logbrush.lbStyle = BS_HOLLOW;
55 oldBrush = (HBRUSH) SelectObject(hdc, CreateBrushIndirect(&logbrush));
56 rop = SetROP2(hdc, R2_NOT);
57 Rectangle(hdc, x, y, x + w, y + h);
58 SetROP2(hdc, rop);
59 DeleteObject(SelectObject(hdc, oldBrush));
60 DeleteObject(SelectObject(hdc, oldPen));
61 ReleaseDC(hdc);
62 }
63
64 LRESULT CImgAreaWindow::OnSize(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
65 {
66 int imgXRes = imageModel.GetWidth();
67 int imgYRes = imageModel.GetHeight();
68 sizeboxLeftTop.MoveWindow(
69 0,
70 0, 3, 3, TRUE);
71 sizeboxCenterTop.MoveWindow(
72 imgXRes * toolsModel.GetZoom() / 2000 + 3 * 3 / 4,
73 0, 3, 3, TRUE);
74 sizeboxRightTop.MoveWindow(
75 imgXRes * toolsModel.GetZoom() / 1000 + 3,
76 0, 3, 3, TRUE);
77 sizeboxLeftCenter.MoveWindow(
78 0,
79 imgYRes * toolsModel.GetZoom() / 2000 + 3 * 3 / 4, 3, 3, TRUE);
80 sizeboxRightCenter.MoveWindow(
81 imgXRes * toolsModel.GetZoom() / 1000 + 3,
82 imgYRes * toolsModel.GetZoom() / 2000 + 3 * 3 / 4, 3, 3, TRUE);
83 sizeboxLeftBottom.MoveWindow(
84 0,
85 imgYRes * toolsModel.GetZoom() / 1000 + 3, 3, 3, TRUE);
86 sizeboxCenterBottom.MoveWindow(
87 imgXRes * toolsModel.GetZoom() / 2000 + 3 * 3 / 4,
88 imgYRes * toolsModel.GetZoom() / 1000 + 3, 3, 3, TRUE);
89 sizeboxRightBottom.MoveWindow(
90 imgXRes * toolsModel.GetZoom() / 1000 + 3,
91 imgYRes * toolsModel.GetZoom() / 1000 + 3, 3, 3, TRUE);
92 UpdateScrollbox();
93 return 0;
94 }
95
96 LRESULT CImgAreaWindow::OnPaint(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
97 {
98 DefWindowProc(WM_PAINT, wParam, lParam);
99 HDC hdc = GetDC();
100 int imgXRes = imageModel.GetWidth();
101 int imgYRes = imageModel.GetHeight();
102 StretchBlt(hdc, 0, 0, imgXRes * toolsModel.GetZoom() / 1000, imgYRes * toolsModel.GetZoom() / 1000, imageModel.GetDC(), 0, 0, imgXRes,
103 imgYRes, SRCCOPY);
104 if (showGrid && (toolsModel.GetZoom() >= 4000))
105 {
106 HPEN oldPen = (HPEN) SelectObject(hdc, CreatePen(PS_SOLID, 1, 0x00a0a0a0));
107 int counter;
108 for(counter = 0; counter <= imgYRes; counter++)
109 {
110 MoveToEx(hdc, 0, counter * toolsModel.GetZoom() / 1000, NULL);
111 LineTo(hdc, imgXRes * toolsModel.GetZoom() / 1000, counter * toolsModel.GetZoom() / 1000);
112 }
113 for(counter = 0; counter <= imgXRes; counter++)
114 {
115 MoveToEx(hdc, counter * toolsModel.GetZoom() / 1000, 0, NULL);
116 LineTo(hdc, counter * toolsModel.GetZoom() / 1000, imgYRes * toolsModel.GetZoom() / 1000);
117 }
118 DeleteObject(SelectObject(hdc, oldPen));
119 }
120 ReleaseDC(hdc);
121 selectionWindow.Invalidate(FALSE);
122 miniature.Invalidate(FALSE);
123 return 0;
124 }
125
126 LRESULT CImgAreaWindow::OnSetCursor(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
127 {
128 switch (toolsModel.GetActiveTool())
129 {
130 case TOOL_FILL:
131 SetCursor(hCurFill);
132 break;
133 case TOOL_COLOR:
134 SetCursor(hCurColor);
135 break;
136 case TOOL_ZOOM:
137 SetCursor(hCurZoom);
138 break;
139 case TOOL_PEN:
140 SetCursor(hCurPen);
141 break;
142 case TOOL_AIRBRUSH:
143 SetCursor(hCurAirbrush);
144 break;
145 default:
146 SetCursor(LoadCursor(NULL, IDC_CROSS));
147 }
148 return 0;
149 }
150
151 LRESULT CImgAreaWindow::OnLButtonDown(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
152 {
153 if ((!drawing) || (toolsModel.GetActiveTool() == TOOL_COLOR))
154 {
155 SetCapture();
156 drawing = TRUE;
157 startPaintingL(imageModel.GetDC(), GET_X_LPARAM(lParam) * 1000 / toolsModel.GetZoom(), GET_Y_LPARAM(lParam) * 1000 / toolsModel.GetZoom(),
158 paletteModel.GetFgColor(), paletteModel.GetBgColor());
159 }
160 else
161 {
162 SendMessage(WM_LBUTTONUP, wParam, lParam);
163 imageModel.Undo();
164 }
165 Invalidate(FALSE);
166 if ((toolsModel.GetActiveTool() == TOOL_ZOOM) && (toolsModel.GetZoom() < 8000))
167 zoomTo(toolsModel.GetZoom() * 2, GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam));
168 return 0;
169 }
170
171 LRESULT CImgAreaWindow::OnRButtonDown(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
172 {
173 if ((!drawing) || (toolsModel.GetActiveTool() == TOOL_COLOR))
174 {
175 SetCapture();
176 drawing = TRUE;
177 startPaintingR(imageModel.GetDC(), GET_X_LPARAM(lParam) * 1000 / toolsModel.GetZoom(), GET_Y_LPARAM(lParam) * 1000 / toolsModel.GetZoom(),
178 paletteModel.GetFgColor(), paletteModel.GetBgColor());
179 }
180 else
181 {
182 SendMessage(WM_RBUTTONUP, wParam, lParam);
183 imageModel.Undo();
184 }
185 Invalidate(FALSE);
186 if ((toolsModel.GetActiveTool() == TOOL_ZOOM) && (toolsModel.GetZoom() > 125))
187 zoomTo(toolsModel.GetZoom() / 2, GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam));
188 return 0;
189 }
190
191 LRESULT CImgAreaWindow::OnLButtonUp(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
192 {
193 if (drawing)
194 {
195 endPaintingL(imageModel.GetDC(), GET_X_LPARAM(lParam) * 1000 / toolsModel.GetZoom(), GET_Y_LPARAM(lParam) * 1000 / toolsModel.GetZoom(), paletteModel.GetFgColor(),
196 paletteModel.GetBgColor());
197 Invalidate(FALSE);
198 if (toolsModel.GetActiveTool() == TOOL_COLOR)
199 {
200 COLORREF tempColor =
201 GetPixel(imageModel.GetDC(), GET_X_LPARAM(lParam) * 1000 / toolsModel.GetZoom(), GET_Y_LPARAM(lParam) * 1000 / toolsModel.GetZoom());
202 if (tempColor != CLR_INVALID)
203 paletteModel.SetFgColor(tempColor);
204 }
205 SendMessage(hStatusBar, SB_SETTEXT, 2, (LPARAM) "");
206 }
207 drawing = FALSE;
208 ReleaseCapture();
209 return 0;
210 }
211
212 void CImgAreaWindow::cancelDrawing()
213 {
214 POINT pt;
215 switch (toolsModel.GetActiveTool())
216 {
217 case TOOL_FREESEL: case TOOL_RECTSEL:
218 case TOOL_TEXT: case TOOL_ZOOM: case TOOL_SHAPE:
219 imageModel.ResetToPrevious();
220 selectionModel.ResetPtStack();
221 pointSP = 0;
222 Invalidate(FALSE);
223 break;
224 default:
225 GetCursorPos(&pt);
226 ScreenToClient(&pt);
227 // FIXME: dirty hack
228 if (GetKeyState(VK_LBUTTON) < 0)
229 {
230 endPaintingL(imageModel.GetDC(), pt.x * 1000 / toolsModel.GetZoom(), pt.y * 1000 / toolsModel.GetZoom(), paletteModel.GetFgColor(),
231 paletteModel.GetBgColor());
232 }
233 else if (GetKeyState(VK_RBUTTON) < 0)
234 {
235 endPaintingR(imageModel.GetDC(), pt.x * 1000 / toolsModel.GetZoom(), pt.y * 1000 / toolsModel.GetZoom(), paletteModel.GetFgColor(),
236 paletteModel.GetBgColor());
237 }
238 imageModel.Undo();
239 pointSP = 0;
240 selectionModel.ResetPtStack();
241 }
242 }
243
244 LRESULT CImgAreaWindow::OnCaptureChanged(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
245 {
246 if (drawing)
247 {
248 cancelDrawing();
249 drawing = FALSE;
250 }
251 return 0;
252 }
253
254 LRESULT CImgAreaWindow::OnKeyDown(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
255 {
256 if (wParam == VK_ESCAPE)
257 {
258 if (GetCapture() == m_hWnd)
259 {
260 ReleaseCapture();
261 }
262 else
263 {
264 switch (toolsModel.GetActiveTool())
265 {
266 case TOOL_SHAPE: case TOOL_BEZIER:
267 cancelDrawing();
268 break;
269 }
270 }
271 }
272 return 0;
273 }
274
275 LRESULT CImgAreaWindow::OnRButtonUp(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
276 {
277 if (drawing)
278 {
279 endPaintingR(imageModel.GetDC(), GET_X_LPARAM(lParam) * 1000 / toolsModel.GetZoom(), GET_Y_LPARAM(lParam) * 1000 / toolsModel.GetZoom(), paletteModel.GetFgColor(),
280 paletteModel.GetBgColor());
281 Invalidate(FALSE);
282 if (toolsModel.GetActiveTool() == TOOL_COLOR)
283 {
284 COLORREF tempColor =
285 GetPixel(imageModel.GetDC(), GET_X_LPARAM(lParam) * 1000 / toolsModel.GetZoom(), GET_Y_LPARAM(lParam) * 1000 / toolsModel.GetZoom());
286 if (tempColor != CLR_INVALID)
287 paletteModel.SetBgColor(tempColor);
288 }
289 SendMessage(hStatusBar, SB_SETTEXT, 2, (LPARAM) "");
290 }
291 ReleaseCapture();
292 drawing = FALSE;
293 return 0;
294 }
295
296 LRESULT CImgAreaWindow::OnMouseMove(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
297 {
298 LONG xNow = GET_X_LPARAM(lParam) * 1000 / toolsModel.GetZoom();
299 LONG yNow = GET_Y_LPARAM(lParam) * 1000 / toolsModel.GetZoom();
300 if ((!drawing) || (toolsModel.GetActiveTool() <= TOOL_AIRBRUSH))
301 {
302 TRACKMOUSEEVENT tme;
303
304 if (toolsModel.GetActiveTool() == TOOL_ZOOM)
305 {
306 Invalidate(FALSE);
307 UpdateWindow();
308 drawZoomFrame(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam));
309 }
310
311 tme.cbSize = sizeof(TRACKMOUSEEVENT);
312 tme.dwFlags = TME_LEAVE;
313 tme.hwndTrack = m_hWnd;
314 tme.dwHoverTime = 0;
315 TrackMouseEvent(&tme);
316
317 if (!drawing)
318 {
319 CString strCoord;
320 strCoord.Format(_T("%ld, %ld"), xNow, yNow);
321 SendMessage(hStatusBar, SB_SETTEXT, 1, (LPARAM) (LPCTSTR) strCoord);
322 }
323 }
324 if (drawing)
325 {
326 /* values displayed in statusbar */
327 LONG xRel = xNow - start.x;
328 LONG yRel = yNow - start.y;
329 /* freesel, rectsel and text tools always show numbers limited to fit into image area */
330 if ((toolsModel.GetActiveTool() == TOOL_FREESEL) || (toolsModel.GetActiveTool() == TOOL_RECTSEL) || (toolsModel.GetActiveTool() == TOOL_TEXT))
331 {
332 if (xRel < 0)
333 xRel = (xNow < 0) ? -start.x : xRel;
334 else if (xNow > imageModel.GetWidth())
335 xRel = imageModel.GetWidth() - start.x;
336 if (yRel < 0)
337 yRel = (yNow < 0) ? -start.y : yRel;
338 else if (yNow > imageModel.GetHeight())
339 yRel = imageModel.GetHeight() - start.y;
340 }
341 /* rectsel and shape tools always show non-negative numbers when drawing */
342 if ((toolsModel.GetActiveTool() == TOOL_RECTSEL) || (toolsModel.GetActiveTool() == TOOL_SHAPE))
343 {
344 if (xRel < 0)
345 xRel = -xRel;
346 if (yRel < 0)
347 yRel = -yRel;
348 }
349 /* while drawing, update cursor coordinates only for tools 3, 7, 8, 9, 14 */
350 switch(toolsModel.GetActiveTool())
351 {
352 case TOOL_RUBBER:
353 case TOOL_PEN:
354 case TOOL_BRUSH:
355 case TOOL_AIRBRUSH:
356 case TOOL_SHAPE:
357 {
358 CString strCoord;
359 strCoord.Format(_T("%ld, %ld"), xNow, yNow);
360 SendMessage(hStatusBar, SB_SETTEXT, 1, (LPARAM) (LPCTSTR) strCoord);
361 break;
362 }
363 }
364 if ((wParam & MK_LBUTTON) != 0)
365 {
366 whilePaintingL(imageModel.GetDC(), xNow, yNow, paletteModel.GetFgColor(), paletteModel.GetBgColor());
367 Invalidate(FALSE);
368 if ((toolsModel.GetActiveTool() >= TOOL_TEXT) || (toolsModel.GetActiveTool() == TOOL_RECTSEL) || (toolsModel.GetActiveTool() == TOOL_FREESEL))
369 {
370 CString strSize;
371 if ((toolsModel.GetActiveTool() >= TOOL_LINE) && (GetAsyncKeyState(VK_SHIFT) < 0))
372 yRel = xRel;
373 strSize.Format(_T("%ld x %ld"), xRel, yRel);
374 SendMessage(hStatusBar, SB_SETTEXT, 2, (LPARAM) (LPCTSTR) strSize);
375 }
376 }
377 if ((wParam & MK_RBUTTON) != 0)
378 {
379 whilePaintingR(imageModel.GetDC(), xNow, yNow, paletteModel.GetFgColor(), paletteModel.GetBgColor());
380 Invalidate(FALSE);
381 if (toolsModel.GetActiveTool() >= TOOL_TEXT)
382 {
383 CString strSize;
384 if ((toolsModel.GetActiveTool() >= TOOL_LINE) && (GetAsyncKeyState(VK_SHIFT) < 0))
385 yRel = xRel;
386 strSize.Format(_T("%ld x %ld"), xRel, yRel);
387 SendMessage(hStatusBar, SB_SETTEXT, 2, (LPARAM) (LPCTSTR) strSize);
388 }
389 }
390 }
391 return 0;
392 }
393
394 LRESULT CImgAreaWindow::OnMouseLeave(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
395 {
396 SendMessage(hStatusBar, SB_SETTEXT, 1, (LPARAM) _T(""));
397 if (toolsModel.GetActiveTool() == TOOL_ZOOM)
398 Invalidate(FALSE);
399 return 0;
400 }
401
402 LRESULT CImgAreaWindow::OnImageModelDimensionsChanged(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
403 {
404 updateCanvasAndScrollbars();
405 return 0;
406 }
407
408 LRESULT CImgAreaWindow::OnImageModelImageChanged(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
409 {
410 Invalidate(FALSE);
411 return 0;
412 }