8184302013f747859b4cba4fd8c68b8591016c2f
[reactos.git] / base / applications / mspaint / winproc.c
1 /*
2 * PROJECT: PAINT for ReactOS
3 * LICENSE: LGPL
4 * FILE: base/applications/paint/winproc.c
5 * PURPOSE: Window procedure of the main window and all children apart from
6 * hPalWin, hToolSettings and hSelection
7 * PROGRAMMERS: Benedikt Freisen
8 */
9
10 /* INCLUDES *********************************************************/
11
12 #include <windows.h>
13 #include <commctrl.h>
14 //#include <htmlhelp.h>
15 #include <stdio.h>
16 #include <tchar.h>
17 #include "definitions.h"
18 #include "globalvar.h"
19 #include "dialogs.h"
20 #include "dib.h"
21 #include "drawing.h"
22 #include "history.h"
23 #include "mouse.h"
24 #include "registry.h"
25
26 /* FUNCTIONS ********************************************************/
27
28 void
29 selectTool(int tool)
30 {
31 ShowWindow(hSelection, SW_HIDE);
32 activeTool = tool;
33 pointSP = 0; // resets the point-buffer of the polygon and bezier functions
34 SendMessage(hToolSettings, WM_PAINT, 0, 0);
35 ShowWindow(hTrackbarZoom, (tool == 6) ? SW_SHOW : SW_HIDE);
36 }
37
38 void
39 updateCanvasAndScrollbars()
40 {
41 ShowWindow(hSelection, SW_HIDE);
42 MoveWindow(hImageArea, 3, 3, imgXRes * zoom / 1000, imgYRes * zoom / 1000, FALSE);
43 InvalidateRect(hScrollbox, NULL, TRUE);
44 InvalidateRect(hImageArea, NULL, FALSE);
45
46 SetScrollPos(hScrollbox, SB_HORZ, 0, TRUE);
47 SetScrollPos(hScrollbox, SB_VERT, 0, TRUE);
48 }
49
50 void
51 zoomTo(int newZoom, int mouseX, int mouseY)
52 {
53 int tbPos = 0;
54 int tempZoom = newZoom;
55
56 long clientRectScrollbox[4];
57 long clientRectImageArea[4];
58 int x, y, w, h;
59 GetClientRect(hScrollbox, (LPRECT) &clientRectScrollbox);
60 GetClientRect(hImageArea, (LPRECT) &clientRectImageArea);
61 w = clientRectImageArea[2] * clientRectScrollbox[2] / (clientRectImageArea[2] * newZoom / zoom);
62 h = clientRectImageArea[3] * clientRectScrollbox[3] / (clientRectImageArea[3] * newZoom / zoom);
63 x = max(0, min(clientRectImageArea[2] - w, mouseX - w / 2)) * newZoom / zoom;
64 y = max(0, min(clientRectImageArea[3] - h, mouseY - h / 2)) * newZoom / zoom;
65
66 zoom = newZoom;
67
68 ShowWindow(hSelection, SW_HIDE);
69 MoveWindow(hImageArea, 3, 3, imgXRes * zoom / 1000, imgYRes * zoom / 1000, FALSE);
70 InvalidateRect(hScrollbox, NULL, TRUE);
71 InvalidateRect(hImageArea, NULL, FALSE);
72
73 SendMessage(hScrollbox, WM_HSCROLL, SB_THUMBPOSITION | (x << 16), 0);
74 SendMessage(hScrollbox, WM_VSCROLL, SB_THUMBPOSITION | (y << 16), 0);
75
76 while (tempZoom > 125)
77 {
78 tbPos++;
79 tempZoom = tempZoom >> 1;
80 }
81 SendMessage(hTrackbarZoom, TBM_SETPOS, (WPARAM) TRUE, (LPARAM) tbPos);
82 }
83
84 void
85 drawZoomFrame(int mouseX, int mouseY)
86 {
87 HDC hdc;
88 HPEN oldPen;
89 HBRUSH oldBrush;
90 LOGBRUSH logbrush;
91 int rop;
92
93 long clientRectScrollbox[4];
94 long clientRectImageArea[4];
95 int x, y, w, h;
96 GetClientRect(hScrollbox, (LPRECT) &clientRectScrollbox);
97 GetClientRect(hImageArea, (LPRECT) &clientRectImageArea);
98 w = clientRectImageArea[2] * clientRectScrollbox[2] / (clientRectImageArea[2] * 2);
99 h = clientRectImageArea[3] * clientRectScrollbox[3] / (clientRectImageArea[3] * 2);
100 x = max(0, min(clientRectImageArea[2] - w, mouseX - w / 2));
101 y = max(0, min(clientRectImageArea[3] - h, mouseY - h / 2));
102
103 hdc = GetDC(hImageArea);
104 oldPen = SelectObject(hdc, CreatePen(PS_SOLID, 0, 0));
105 logbrush.lbStyle = BS_HOLLOW;
106 oldBrush = SelectObject(hdc, CreateBrushIndirect(&logbrush));
107 rop = SetROP2(hdc, R2_NOT);
108 Rectangle(hdc, x, y, x + w, y + h);
109 SetROP2(hdc, rop);
110 DeleteObject(SelectObject(hdc, oldBrush));
111 DeleteObject(SelectObject(hdc, oldPen));
112 ReleaseDC(hImageArea, hdc);
113 }
114
115 void
116 alignChildrenToMainWindow()
117 {
118 int x, y, w, h;
119 RECT clientRect;
120 GetClientRect(hMainWnd, &clientRect);
121
122 if (IsWindowVisible(hToolBoxContainer))
123 {
124 x = 56;
125 w = clientRect.right - 56;
126 }
127 else
128 {
129 x = 0;
130 w = clientRect.right;
131 }
132 if (IsWindowVisible(hPalWin))
133 {
134 y = 49;
135 h = clientRect.bottom - 49;
136 }
137 else
138 {
139 y = 3;
140 h = clientRect.bottom - 3;
141 }
142
143 MoveWindow(hScrollbox, x, y, w, IsWindowVisible(hStatusBar) ? h - 23 : h, TRUE);
144 MoveWindow(hPalWin, x, 9, 255, 32, TRUE);
145 }
146
147 BOOL drawing;
148
149 LRESULT CALLBACK
150 WindowProcedure(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
151 {
152 switch (message) /* handle the messages */
153 {
154 case WM_CREATE:
155 ptStack = NULL;
156 ptSP = 0;
157 break;
158
159 case WM_DESTROY:
160 PostQuitMessage(0); /* send a WM_QUIT to the message queue */
161 break;
162
163 case WM_CLOSE:
164 if (hwnd == hwndMiniature)
165 {
166 ShowWindow(hwndMiniature, SW_HIDE);
167 showMiniature = FALSE;
168 break;
169 }
170 if (!imageSaved)
171 {
172 TCHAR programname[20];
173 TCHAR saveprompttext[100];
174 TCHAR temptext[500];
175 LoadString(hProgInstance, IDS_PROGRAMNAME, programname, SIZEOF(programname));
176 LoadString(hProgInstance, IDS_SAVEPROMPTTEXT, saveprompttext, SIZEOF(saveprompttext));
177 _stprintf(temptext, saveprompttext, filename);
178 switch (MessageBox(hwnd, temptext, programname, MB_YESNOCANCEL | MB_ICONQUESTION))
179 {
180 case IDNO:
181 DestroyWindow(hwnd);
182 break;
183 case IDYES:
184 SendMessage(hwnd, WM_COMMAND, IDM_FILESAVEAS, 0);
185 DestroyWindow(hwnd);
186 break;
187 }
188 }
189 else
190 {
191 DestroyWindow(hwnd);
192 }
193 break;
194
195 case WM_INITMENUPOPUP:
196 switch (lParam)
197 {
198 case 0:
199 if (isAFile)
200 {
201 EnableMenuItem(GetMenu(hMainWnd), IDM_FILEASWALLPAPERPLANE,
202 MF_ENABLED | MF_BYCOMMAND);
203 EnableMenuItem(GetMenu(hMainWnd), IDM_FILEASWALLPAPERCENTERED,
204 MF_ENABLED | MF_BYCOMMAND);
205 EnableMenuItem(GetMenu(hMainWnd), IDM_FILEASWALLPAPERSTRETCHED,
206 MF_ENABLED | MF_BYCOMMAND);
207 }
208 else
209 {
210 EnableMenuItem(GetMenu(hMainWnd), IDM_FILEASWALLPAPERPLANE,
211 MF_GRAYED | MF_BYCOMMAND);
212 EnableMenuItem(GetMenu(hMainWnd), IDM_FILEASWALLPAPERCENTERED,
213 MF_GRAYED | MF_BYCOMMAND);
214 EnableMenuItem(GetMenu(hMainWnd), IDM_FILEASWALLPAPERSTRETCHED,
215 MF_GRAYED | MF_BYCOMMAND);
216 }
217 break;
218 case 1:
219 EnableMenuItem(GetMenu(hMainWnd), IDM_EDITUNDO,
220 (undoSteps > 0) ? (MF_ENABLED | MF_BYCOMMAND) : (MF_GRAYED | MF_BYCOMMAND));
221 EnableMenuItem(GetMenu(hMainWnd), IDM_EDITREDO,
222 (redoSteps > 0) ? (MF_ENABLED | MF_BYCOMMAND) : (MF_GRAYED | MF_BYCOMMAND));
223 if (IsWindowVisible(hSelection))
224 {
225 EnableMenuItem(GetMenu(hMainWnd), IDM_EDITCUT, MF_ENABLED | MF_BYCOMMAND);
226 EnableMenuItem(GetMenu(hMainWnd), IDM_EDITCOPY, MF_ENABLED | MF_BYCOMMAND);
227 EnableMenuItem(GetMenu(hMainWnd), IDM_EDITDELETESELECTION, MF_ENABLED | MF_BYCOMMAND);
228 EnableMenuItem(GetMenu(hMainWnd), IDM_EDITINVERTSELECTION, MF_ENABLED | MF_BYCOMMAND);
229 EnableMenuItem(GetMenu(hMainWnd), IDM_EDITCOPYTO, MF_ENABLED | MF_BYCOMMAND);
230 }
231 else
232 {
233 EnableMenuItem(GetMenu(hMainWnd), IDM_EDITCUT, MF_GRAYED | MF_BYCOMMAND);
234 EnableMenuItem(GetMenu(hMainWnd), IDM_EDITCOPY, MF_GRAYED | MF_BYCOMMAND);
235 EnableMenuItem(GetMenu(hMainWnd), IDM_EDITDELETESELECTION, MF_GRAYED | MF_BYCOMMAND);
236 EnableMenuItem(GetMenu(hMainWnd), IDM_EDITINVERTSELECTION, MF_GRAYED | MF_BYCOMMAND);
237 EnableMenuItem(GetMenu(hMainWnd), IDM_EDITCOPYTO, MF_GRAYED | MF_BYCOMMAND);
238 }
239 OpenClipboard(hMainWnd);
240 if (GetClipboardData(CF_BITMAP) != NULL)
241 EnableMenuItem(GetMenu(hMainWnd), IDM_EDITPASTE, MF_ENABLED | MF_BYCOMMAND);
242 else
243 EnableMenuItem(GetMenu(hMainWnd), IDM_EDITPASTE, MF_GRAYED | MF_BYCOMMAND);
244 CloseClipboard();
245 break;
246 case 3:
247 if (IsWindowVisible(hSelection))
248 EnableMenuItem(GetMenu(hMainWnd), IDM_IMAGECROP, MF_ENABLED | MF_BYCOMMAND);
249 else
250 EnableMenuItem(GetMenu(hMainWnd), IDM_IMAGECROP, MF_GRAYED | MF_BYCOMMAND);
251 CheckMenuItem(GetMenu(hMainWnd), IDM_IMAGEDRAWOPAQUE, (transpBg == 0) ?
252 (MF_CHECKED | MF_BYCOMMAND) : (MF_UNCHECKED | MF_BYCOMMAND));
253 break;
254 }
255 CheckMenuItem(GetMenu(hMainWnd), IDM_VIEWTOOLBOX,
256 IsWindowVisible(hToolBoxContainer) ?
257 (MF_CHECKED | MF_BYCOMMAND) : (MF_UNCHECKED | MF_BYCOMMAND));
258 CheckMenuItem(GetMenu(hMainWnd), IDM_VIEWCOLORPALETTE,
259 IsWindowVisible(hPalWin) ?
260 (MF_CHECKED | MF_BYCOMMAND) : (MF_UNCHECKED | MF_BYCOMMAND));
261 CheckMenuItem(GetMenu(hMainWnd), IDM_VIEWSTATUSBAR,
262 IsWindowVisible(hStatusBar) ?
263 (MF_CHECKED | MF_BYCOMMAND) : (MF_UNCHECKED | MF_BYCOMMAND));
264
265 CheckMenuItem(GetMenu(hMainWnd), IDM_VIEWSHOWGRID,
266 showGrid ? (MF_CHECKED | MF_BYCOMMAND) : (MF_UNCHECKED | MF_BYCOMMAND));
267 CheckMenuItem(GetMenu(hMainWnd), IDM_VIEWSHOWMINIATURE,
268 showMiniature ? (MF_CHECKED | MF_BYCOMMAND) : (MF_UNCHECKED | MF_BYCOMMAND));
269
270 CheckMenuItem(GetMenu(hMainWnd), IDM_VIEWZOOM125,
271 (zoom == 125) ? (MF_CHECKED | MF_BYCOMMAND) : (MF_UNCHECKED | MF_BYCOMMAND));
272 CheckMenuItem(GetMenu(hMainWnd), IDM_VIEWZOOM25,
273 (zoom == 250) ? (MF_CHECKED | MF_BYCOMMAND) : (MF_UNCHECKED | MF_BYCOMMAND));
274 CheckMenuItem(GetMenu(hMainWnd), IDM_VIEWZOOM50,
275 (zoom == 500) ? (MF_CHECKED | MF_BYCOMMAND) : (MF_UNCHECKED | MF_BYCOMMAND));
276 CheckMenuItem(GetMenu(hMainWnd), IDM_VIEWZOOM100,
277 (zoom == 1000) ? (MF_CHECKED | MF_BYCOMMAND) : (MF_UNCHECKED | MF_BYCOMMAND));
278 CheckMenuItem(GetMenu(hMainWnd), IDM_VIEWZOOM200,
279 (zoom == 2000) ? (MF_CHECKED | MF_BYCOMMAND) : (MF_UNCHECKED | MF_BYCOMMAND));
280 CheckMenuItem(GetMenu(hMainWnd), IDM_VIEWZOOM400,
281 (zoom == 4000) ? (MF_CHECKED | MF_BYCOMMAND) : (MF_UNCHECKED | MF_BYCOMMAND));
282 CheckMenuItem(GetMenu(hMainWnd), IDM_VIEWZOOM800,
283 (zoom == 8000) ? (MF_CHECKED | MF_BYCOMMAND) : (MF_UNCHECKED | MF_BYCOMMAND));
284
285 break;
286
287 case WM_SIZE:
288 if (hwnd == hMainWnd)
289 {
290 int test[] = { LOWORD(lParam) - 260, LOWORD(lParam) - 140, LOWORD(lParam) - 20 };
291 SendMessage(hStatusBar, WM_SIZE, wParam, lParam);
292 SendMessage(hStatusBar, SB_SETPARTS, 3, (LPARAM)&test);
293 alignChildrenToMainWindow();
294 }
295 if (hwnd == hImageArea)
296 {
297 MoveWindow(hSizeboxLeftTop,
298 0,
299 0, 3, 3, TRUE);
300 MoveWindow(hSizeboxCenterTop,
301 imgXRes * zoom / 2000 + 3 * 3 / 4,
302 0, 3, 3, TRUE);
303 MoveWindow(hSizeboxRightTop,
304 imgXRes * zoom / 1000 + 3,
305 0, 3, 3, TRUE);
306 MoveWindow(hSizeboxLeftCenter,
307 0,
308 imgYRes * zoom / 2000 + 3 * 3 / 4, 3, 3, TRUE);
309 MoveWindow(hSizeboxRightCenter,
310 imgXRes * zoom / 1000 + 3,
311 imgYRes * zoom / 2000 + 3 * 3 / 4, 3, 3, TRUE);
312 MoveWindow(hSizeboxLeftBottom,
313 0,
314 imgYRes * zoom / 1000 + 3, 3, 3, TRUE);
315 MoveWindow(hSizeboxCenterBottom,
316 imgXRes * zoom / 2000 + 3 * 3 / 4,
317 imgYRes * zoom / 1000 + 3, 3, 3, TRUE);
318 MoveWindow(hSizeboxRightBottom,
319 imgXRes * zoom / 1000 + 3,
320 imgYRes * zoom / 1000 + 3, 3, 3, TRUE);
321 }
322 if ((hwnd == hImageArea) || (hwnd == hScrollbox))
323 {
324 long clientRectScrollbox[4];
325 long clientRectImageArea[4];
326 SCROLLINFO si;
327 GetClientRect(hScrollbox, (LPRECT) &clientRectScrollbox);
328 GetClientRect(hImageArea, (LPRECT) &clientRectImageArea);
329 si.cbSize = sizeof(SCROLLINFO);
330 si.fMask = SIF_PAGE | SIF_RANGE;
331 si.nMax = clientRectImageArea[2] + 6 - 1;
332 si.nMin = 0;
333 si.nPage = clientRectScrollbox[2];
334 SetScrollInfo(hScrollbox, SB_HORZ, &si, TRUE);
335 GetClientRect(hScrollbox, (LPRECT) clientRectScrollbox);
336 si.nMax = clientRectImageArea[3] + 6 - 1;
337 si.nPage = clientRectScrollbox[3];
338 SetScrollInfo(hScrollbox, SB_VERT, &si, TRUE);
339 MoveWindow(hScrlClient,
340 -GetScrollPos(hScrollbox, SB_HORZ), -GetScrollPos(hScrollbox, SB_VERT),
341 max(clientRectImageArea[2] + 6, clientRectScrollbox[2]),
342 max(clientRectImageArea[3] + 6, clientRectScrollbox[3]), TRUE);
343 }
344 break;
345
346 case WM_HSCROLL:
347 if (hwnd == hScrollbox)
348 {
349 SCROLLINFO si;
350 si.cbSize = sizeof(SCROLLINFO);
351 si.fMask = SIF_ALL;
352 GetScrollInfo(hScrollbox, SB_HORZ, &si);
353 switch (LOWORD(wParam))
354 {
355 case SB_THUMBTRACK:
356 case SB_THUMBPOSITION:
357 si.nPos = HIWORD(wParam);
358 break;
359 case SB_LINELEFT:
360 si.nPos -= 5;
361 break;
362 case SB_LINERIGHT:
363 si.nPos += 5;
364 break;
365 case SB_PAGELEFT:
366 si.nPos -= si.nPage;
367 break;
368 case SB_PAGERIGHT:
369 si.nPos += si.nPage;
370 break;
371 }
372 SetScrollInfo(hScrollbox, SB_HORZ, &si, TRUE);
373 MoveWindow(hScrlClient, -GetScrollPos(hScrollbox, SB_HORZ),
374 -GetScrollPos(hScrollbox, SB_VERT), imgXRes * zoom / 1000 + 6,
375 imgYRes * zoom / 1000 + 6, TRUE);
376 }
377 break;
378
379 case WM_VSCROLL:
380 if (hwnd == hScrollbox)
381 {
382 SCROLLINFO si;
383 si.cbSize = sizeof(SCROLLINFO);
384 si.fMask = SIF_ALL;
385 GetScrollInfo(hScrollbox, SB_VERT, &si);
386 switch (LOWORD(wParam))
387 {
388 case SB_THUMBTRACK:
389 case SB_THUMBPOSITION:
390 si.nPos = HIWORD(wParam);
391 break;
392 case SB_LINEUP:
393 si.nPos -= 5;
394 break;
395 case SB_LINEDOWN:
396 si.nPos += 5;
397 break;
398 case SB_PAGEUP:
399 si.nPos -= si.nPage;
400 break;
401 case SB_PAGEDOWN:
402 si.nPos += si.nPage;
403 break;
404 }
405 SetScrollInfo(hScrollbox, SB_VERT, &si, TRUE);
406 MoveWindow(hScrlClient, -GetScrollPos(hScrollbox, SB_HORZ),
407 -GetScrollPos(hScrollbox, SB_VERT), imgXRes * zoom / 1000 + 6,
408 imgYRes * zoom / 1000 + 6, TRUE);
409 }
410 break;
411
412 case WM_GETMINMAXINFO:
413 if (hwnd == hMainWnd)
414 {
415 MINMAXINFO *mm = (LPMINMAXINFO) lParam;
416 (*mm).ptMinTrackSize.x = 330;
417 (*mm).ptMinTrackSize.y = 430;
418 }
419 break;
420
421 case WM_PAINT:
422 DefWindowProc(hwnd, message, wParam, lParam);
423 if (hwnd == hImageArea)
424 {
425 HDC hdc = GetDC(hImageArea);
426 StretchBlt(hdc, 0, 0, imgXRes * zoom / 1000, imgYRes * zoom / 1000, hDrawingDC, 0, 0, imgXRes,
427 imgYRes, SRCCOPY);
428 if (showGrid && (zoom >= 4000))
429 {
430 HPEN oldPen = SelectObject(hdc, CreatePen(PS_SOLID, 1, 0x00a0a0a0));
431 int counter;
432 for(counter = 0; counter <= imgYRes; counter++)
433 {
434 MoveToEx(hdc, 0, counter * zoom / 1000, NULL);
435 LineTo(hdc, imgXRes * zoom / 1000, counter * zoom / 1000);
436 }
437 for(counter = 0; counter <= imgXRes; counter++)
438 {
439 MoveToEx(hdc, counter * zoom / 1000, 0, NULL);
440 LineTo(hdc, counter * zoom / 1000, imgYRes * zoom / 1000);
441 }
442 DeleteObject(SelectObject(hdc, oldPen));
443 }
444 ReleaseDC(hImageArea, hdc);
445 SendMessage(hSelection, WM_PAINT, 0, 0);
446 SendMessage(hwndMiniature, WM_PAINT, 0, 0);
447 }
448 else if (hwnd == hwndMiniature)
449 {
450 RECT mclient;
451 HDC hdc;
452 GetClientRect(hwndMiniature, &mclient);
453 hdc = GetDC(hwndMiniature);
454 StretchBlt(hdc, 0, 0, mclient.right, mclient.bottom, hDrawingDC, 0, 0, imgXRes, imgYRes, SRCCOPY);
455 ReleaseDC(hwndMiniature, hdc);
456 }
457 break;
458
459 // mouse events used for drawing
460
461 case WM_SETCURSOR:
462 if (hwnd == hImageArea)
463 {
464 switch (activeTool)
465 {
466 case TOOL_FILL:
467 SetCursor(hCurFill);
468 break;
469 case TOOL_COLOR:
470 SetCursor(hCurColor);
471 break;
472 case TOOL_ZOOM:
473 SetCursor(hCurZoom);
474 break;
475 case TOOL_PEN:
476 SetCursor(hCurPen);
477 break;
478 case TOOL_AIRBRUSH:
479 SetCursor(hCurAirbrush);
480 break;
481 default:
482 SetCursor(LoadCursor(NULL, IDC_CROSS));
483 }
484 }
485 else
486 DefWindowProc(hwnd, message, wParam, lParam);
487 break;
488
489 case WM_LBUTTONDOWN:
490 if (hwnd == hImageArea)
491 {
492 if ((!drawing) || (activeTool == TOOL_COLOR))
493 {
494 SetCapture(hImageArea);
495 drawing = TRUE;
496 startPaintingL(hDrawingDC, LOWORD(lParam) * 1000 / zoom, HIWORD(lParam) * 1000 / zoom,
497 fgColor, bgColor);
498 }
499 else
500 {
501 SendMessage(hwnd, WM_LBUTTONUP, wParam, lParam);
502 undo();
503 }
504 SendMessage(hImageArea, WM_PAINT, 0, 0);
505 if ((activeTool == TOOL_ZOOM) && (zoom < 8000))
506 zoomTo(zoom * 2, LOWORD(lParam), HIWORD(lParam));
507 }
508 break;
509
510 case WM_RBUTTONDOWN:
511 if (hwnd == hImageArea)
512 {
513 if ((!drawing) || (activeTool == TOOL_COLOR))
514 {
515 SetCapture(hImageArea);
516 drawing = TRUE;
517 startPaintingR(hDrawingDC, LOWORD(lParam) * 1000 / zoom, HIWORD(lParam) * 1000 / zoom,
518 fgColor, bgColor);
519 }
520 else
521 {
522 SendMessage(hwnd, WM_RBUTTONUP, wParam, lParam);
523 undo();
524 }
525 SendMessage(hImageArea, WM_PAINT, 0, 0);
526 if ((activeTool == TOOL_ZOOM) && (zoom > 125))
527 zoomTo(zoom / 2, LOWORD(lParam), HIWORD(lParam));
528 }
529 break;
530
531 case WM_LBUTTONUP:
532 if ((hwnd == hImageArea) && drawing)
533 {
534 ReleaseCapture();
535 drawing = FALSE;
536 endPaintingL(hDrawingDC, LOWORD(lParam) * 1000 / zoom, HIWORD(lParam) * 1000 / zoom, fgColor,
537 bgColor);
538 SendMessage(hImageArea, WM_PAINT, 0, 0);
539 if (activeTool == TOOL_COLOR)
540 {
541 int tempColor =
542 GetPixel(hDrawingDC, LOWORD(lParam) * 1000 / zoom, HIWORD(lParam) * 1000 / zoom);
543 if (tempColor != CLR_INVALID)
544 fgColor = tempColor;
545 SendMessage(hPalWin, WM_PAINT, 0, 0);
546 }
547 SendMessage(hStatusBar, SB_SETTEXT, 2, (LPARAM) "");
548 }
549 break;
550
551 case WM_RBUTTONUP:
552 if ((hwnd == hImageArea) && drawing)
553 {
554 ReleaseCapture();
555 drawing = FALSE;
556 endPaintingR(hDrawingDC, LOWORD(lParam) * 1000 / zoom, HIWORD(lParam) * 1000 / zoom, fgColor,
557 bgColor);
558 SendMessage(hImageArea, WM_PAINT, 0, 0);
559 if (activeTool == TOOL_COLOR)
560 {
561 int tempColor =
562 GetPixel(hDrawingDC, LOWORD(lParam) * 1000 / zoom, HIWORD(lParam) * 1000 / zoom);
563 if (tempColor != CLR_INVALID)
564 bgColor = tempColor;
565 SendMessage(hPalWin, WM_PAINT, 0, 0);
566 }
567 SendMessage(hStatusBar, SB_SETTEXT, 2, (LPARAM) "");
568 }
569 break;
570
571 case WM_KEYDOWN:
572 if (wParam == VK_ESCAPE)
573 {
574 if (!drawing)
575 {
576 /* Deselect */
577 if ((activeTool == TOOL_RECTSEL) || (activeTool == TOOL_FREESEL))
578 {
579 startPaintingL(hDrawingDC, 0, 0, fgColor, bgColor);
580 whilePaintingL(hDrawingDC, 0, 0, fgColor, bgColor);
581 endPaintingL(hDrawingDC, 0, 0, fgColor, bgColor);
582 ShowWindow(hSelection, SW_HIDE);
583 }
584 }
585 /* FIXME: also cancel current drawing underway */
586 }
587 break;
588
589 case WM_MOUSEMOVE:
590 if (hwnd == hImageArea)
591 {
592 LONG xNow = LOWORD(lParam) * 1000 / zoom;
593 LONG yNow = HIWORD(lParam) * 1000 / zoom;
594 if ((!drawing) || (activeTool <= TOOL_AIRBRUSH))
595 {
596 TRACKMOUSEEVENT tme;
597
598 if (activeTool == TOOL_ZOOM)
599 {
600 SendMessage(hImageArea, WM_PAINT, 0, 0);
601 drawZoomFrame(LOWORD(lParam), HIWORD(lParam));
602 }
603
604 tme.cbSize = sizeof(TRACKMOUSEEVENT);
605 tme.dwFlags = TME_LEAVE;
606 tme.hwndTrack = hImageArea;
607 tme.dwHoverTime = 0;
608 TrackMouseEvent(&tme);
609
610 if (!drawing)
611 {
612 TCHAR coordStr[100];
613 _stprintf(coordStr, _T("%d, %d"), xNow, yNow);
614 SendMessage(hStatusBar, SB_SETTEXT, 1, (LPARAM) coordStr);
615 }
616 }
617 if (drawing)
618 {
619 /* values displayed in statusbar */
620 LONG xRel = xNow - startX;
621 LONG yRel = yNow - startY;
622 /* freesel, rectsel and text tools always show numbers limited to fit into image area */
623 if ((activeTool == TOOL_FREESEL) || (activeTool == TOOL_RECTSEL) || (activeTool == TOOL_TEXT))
624 {
625 if (xRel < 0)
626 xRel = (xNow < 0) ? -startX : xRel;
627 else if (xNow > imgXRes)
628 xRel = imgXRes-startX;
629 if (yRel < 0)
630 yRel = (yNow < 0) ? -startY : yRel;
631 else if (yNow > imgYRes)
632 yRel = imgYRes-startY;
633 }
634 /* rectsel and shape tools always show non-negative numbers when drawing */
635 if ((activeTool == TOOL_RECTSEL) || (activeTool == TOOL_SHAPE))
636 {
637 if (xRel < 0)
638 xRel = -xRel;
639 if (yRel < 0)
640 yRel = -yRel;
641 }
642 /* while drawing, update cursor coordinates only for tools 3, 7, 8, 9, 14 */
643 switch(activeTool)
644 {
645 case TOOL_RUBBER:
646 case TOOL_PEN:
647 case TOOL_BRUSH:
648 case TOOL_AIRBRUSH:
649 case TOOL_SHAPE:
650 {
651 TCHAR coordStr[100];
652 _stprintf(coordStr, _T("%d, %d"), xNow, yNow);
653 SendMessage(hStatusBar, SB_SETTEXT, 1, (LPARAM) coordStr);
654 break;
655 }
656 }
657 if ((wParam & MK_LBUTTON) != 0)
658 {
659 whilePaintingL(hDrawingDC, xNow, yNow, fgColor, bgColor);
660 SendMessage(hImageArea, WM_PAINT, 0, 0);
661 if ((activeTool >= TOOL_TEXT) || (activeTool == TOOL_RECTSEL) || (activeTool == TOOL_FREESEL))
662 {
663 TCHAR sizeStr[100];
664 if ((activeTool >= TOOL_LINE) && (GetAsyncKeyState(VK_SHIFT) < 0))
665 yRel = xRel;
666 _stprintf(sizeStr, _T("%d x %d"), xRel, yRel);
667 SendMessage(hStatusBar, SB_SETTEXT, 2, (LPARAM) sizeStr);
668 }
669 }
670 if ((wParam & MK_RBUTTON) != 0)
671 {
672 whilePaintingR(hDrawingDC, xNow, yNow, fgColor, bgColor);
673 SendMessage(hImageArea, WM_PAINT, 0, 0);
674 if (activeTool >= TOOL_TEXT)
675 {
676 TCHAR sizeStr[100];
677 if ((activeTool >= TOOL_LINE) && (GetAsyncKeyState(VK_SHIFT) < 0))
678 yRel = xRel;
679 _stprintf(sizeStr, _T("%d x %d"), xRel, yRel);
680 SendMessage(hStatusBar, SB_SETTEXT, 2, (LPARAM) sizeStr);
681 }
682 }
683 }
684 }
685 break;
686
687 case WM_MOUSELEAVE:
688 SendMessage(hStatusBar, SB_SETTEXT, 1, (LPARAM) _T(""));
689 if (activeTool == TOOL_ZOOM)
690 SendMessage(hImageArea, WM_PAINT, 0, 0);
691 break;
692
693 // menu and button events
694
695 case WM_SYSCOLORCHANGE:
696 {
697 /* Redirect message to common controls */
698 HWND hToolbar = FindWindowEx(hToolBoxContainer, NULL, TOOLBARCLASSNAME, NULL);
699 SendMessage(hToolbar, WM_SYSCOLORCHANGE, 0, 0);
700 break;
701 }
702
703 case WM_COMMAND:
704 switch (LOWORD(wParam))
705 {
706 case IDM_HELPINFO:
707 {
708 HICON paintIcon = LoadIcon(hProgInstance, MAKEINTRESOURCE(IDI_APPICON));
709 TCHAR infotitle[100];
710 TCHAR infotext[200];
711 LoadString(hProgInstance, IDS_INFOTITLE, infotitle, SIZEOF(infotitle));
712 LoadString(hProgInstance, IDS_INFOTEXT, infotext, SIZEOF(infotext));
713 ShellAbout(hMainWnd, infotitle, infotext, paintIcon);
714 DeleteObject(paintIcon);
715 break;
716 }
717 case IDM_HELPHELPTOPICS:
718 //HtmlHelp(hMainWnd, "help\\Paint.chm", 0, 0);
719 break;
720 case IDM_FILEEXIT:
721 SendMessage(hwnd, WM_CLOSE, wParam, lParam);
722 break;
723 case IDM_FILENEW:
724 ShowWindow(hSelection, SW_HIDE);
725 clearHistory();
726
727 Rectangle(hDrawingDC, 0 - 1, 0 - 1, imgXRes + 1, imgYRes + 1);
728 SendMessage(hImageArea, WM_PAINT, 0, 0);
729 break;
730 case IDM_FILEOPEN:
731 if (GetOpenFileName(&ofn) != 0)
732 {
733 HBITMAP bmNew = NULL;
734 LoadDIBFromFile(&bmNew, ofn.lpstrFile, &fileTime, &fileSize, &fileHPPM, &fileVPPM);
735 if (bmNew != NULL)
736 {
737 TCHAR tempstr[1000];
738 TCHAR resstr[100];
739 insertReversible(bmNew);
740 updateCanvasAndScrollbars();
741 CopyMemory(filename, ofn.lpstrFileTitle, sizeof(filename));
742 CopyMemory(filepathname, ofn.lpstrFileTitle, sizeof(filepathname));
743 LoadString(hProgInstance, IDS_WINDOWTITLE, resstr, SIZEOF(resstr));
744 _stprintf(tempstr, resstr, filename);
745 SetWindowText(hMainWnd, tempstr);
746 clearHistory();
747 isAFile = TRUE;
748 }
749 }
750 break;
751 case IDM_FILESAVE:
752 if (isAFile)
753 {
754 SaveDIBToFile(hBms[currInd], filepathname, hDrawingDC, &fileTime, &fileSize, fileHPPM,
755 fileVPPM);
756 imageSaved = TRUE;
757 }
758 else
759 SendMessage(hwnd, WM_COMMAND, IDM_FILESAVEAS, 0);
760 break;
761 case IDM_FILESAVEAS:
762 if (GetSaveFileName(&sfn) != 0)
763 {
764 TCHAR tempstr[1000];
765 TCHAR resstr[100];
766 SaveDIBToFile(hBms[currInd], sfn.lpstrFile, hDrawingDC, &fileTime, &fileSize,
767 fileHPPM, fileVPPM);
768 CopyMemory(filename, sfn.lpstrFileTitle, sizeof(filename));
769 CopyMemory(filepathname, sfn.lpstrFile, sizeof(filepathname));
770 LoadString(hProgInstance, IDS_WINDOWTITLE, resstr, SIZEOF(resstr));
771 _stprintf(tempstr, resstr, filename);
772 SetWindowText(hMainWnd, tempstr);
773 isAFile = TRUE;
774 imageSaved = TRUE;
775 }
776 break;
777 case IDM_FILEASWALLPAPERPLANE:
778 SetWallpaper(filepathname, 1, 1);
779 break;
780 case IDM_FILEASWALLPAPERCENTERED:
781 SetWallpaper(filepathname, 1, 0);
782 break;
783 case IDM_FILEASWALLPAPERSTRETCHED:
784 SetWallpaper(filepathname, 2, 0);
785 break;
786 case IDM_EDITUNDO:
787 undo();
788 SendMessage(hImageArea, WM_PAINT, 0, 0);
789 break;
790 case IDM_EDITREDO:
791 redo();
792 SendMessage(hImageArea, WM_PAINT, 0, 0);
793 break;
794 case IDM_EDITCOPY:
795 OpenClipboard(hMainWnd);
796 EmptyClipboard();
797 SetClipboardData(CF_BITMAP, CopyImage(hSelBm, IMAGE_BITMAP, 0, 0, LR_COPYRETURNORG));
798 CloseClipboard();
799 break;
800 case IDM_EDITCUT:
801 /* Copy */
802 SendMessage(hwnd, WM_COMMAND, IDM_EDITCOPY, 0);
803 /* Delete selection */
804 SendMessage(hwnd, WM_COMMAND, IDM_EDITDELETESELECTION, 0);
805 break;
806 case IDM_EDITPASTE:
807 OpenClipboard(hMainWnd);
808 if (GetClipboardData(CF_BITMAP) != NULL)
809 {
810 HWND hToolbar = FindWindowEx(hToolBoxContainer, NULL, TOOLBARCLASSNAME, NULL);
811 SendMessage(hToolbar, TB_CHECKBUTTON, ID_RECTSEL, MAKELONG(TRUE, 0));
812 SendMessage(hwnd, WM_COMMAND, ID_RECTSEL, 0);
813
814 DeleteObject(SelectObject(hSelDC, hSelBm = CopyImage(GetClipboardData(CF_BITMAP),
815 IMAGE_BITMAP, 0, 0,
816 LR_COPYRETURNORG)));
817 newReversible();
818 rectSel_src[0] = rectSel_src[1] = rectSel_src[2] = rectSel_src[3] = 0;
819 rectSel_dest[0] = rectSel_dest[1] = 0;
820 rectSel_dest[2] = GetDIBWidth(hSelBm);
821 rectSel_dest[3] = GetDIBHeight(hSelBm);
822 BitBlt(hDrawingDC, rectSel_dest[0], rectSel_dest[1], rectSel_dest[2], rectSel_dest[3],
823 hSelDC, 0, 0, SRCCOPY);
824 placeSelWin();
825 ShowWindow(hSelection, SW_SHOW);
826 }
827 CloseClipboard();
828 break;
829 case IDM_EDITDELETESELECTION:
830 {
831 /* remove selection window and already painted content using undo(),
832 paint Rect for rectangular selections and Poly for freeform selections */
833 undo();
834 if (activeTool == TOOL_RECTSEL)
835 {
836 newReversible();
837 Rect(hDrawingDC, rectSel_dest[0], rectSel_dest[1], rectSel_dest[2] + rectSel_dest[0],
838 rectSel_dest[3] + rectSel_dest[1], bgColor, bgColor, 0, TRUE);
839 }
840 if (activeTool == TOOL_FREESEL)
841 {
842 newReversible();
843 Poly(hDrawingDC, ptStack, ptSP + 1, 0, 0, 2, 0, FALSE);
844 }
845 break;
846 }
847 case IDM_EDITSELECTALL:
848 {
849 HWND hToolbar = FindWindowEx(hToolBoxContainer, NULL, TOOLBARCLASSNAME, NULL);
850 SendMessage(hToolbar, TB_CHECKBUTTON, ID_RECTSEL, MAKELONG(TRUE, 0));
851 SendMessage(hwnd, WM_COMMAND, ID_RECTSEL, 0);
852 startPaintingL(hDrawingDC, 0, 0, fgColor, bgColor);
853 whilePaintingL(hDrawingDC, imgXRes, imgYRes, fgColor, bgColor);
854 endPaintingL(hDrawingDC, imgXRes, imgYRes, fgColor, bgColor);
855 break;
856 }
857 case IDM_EDITCOPYTO:
858 if (GetSaveFileName(&ofn) != 0)
859 SaveDIBToFile(hSelBm, ofn.lpstrFile, hDrawingDC, NULL, NULL, fileHPPM, fileVPPM);
860 break;
861 case IDM_COLORSEDITPALETTE:
862 if (ChooseColor(&choosecolor))
863 {
864 fgColor = choosecolor.rgbResult;
865 SendMessage(hPalWin, WM_PAINT, 0, 0);
866 }
867 break;
868 case IDM_IMAGEINVERTCOLORS:
869 {
870 RECT tempRect;
871 newReversible();
872 SetRect(&tempRect, 0, 0, imgXRes, imgYRes);
873 InvertRect(hDrawingDC, &tempRect);
874 SendMessage(hImageArea, WM_PAINT, 0, 0);
875 break;
876 }
877 case IDM_IMAGEDELETEIMAGE:
878 newReversible();
879 Rect(hDrawingDC, 0, 0, imgXRes, imgYRes, bgColor, bgColor, 0, TRUE);
880 SendMessage(hImageArea, WM_PAINT, 0, 0);
881 break;
882 case IDM_IMAGEROTATEMIRROR:
883 switch (mirrorRotateDlg())
884 {
885 case 1: /* flip horizontally */
886 if (IsWindowVisible(hSelection))
887 {
888 SelectObject(hSelDC, hSelMask);
889 StretchBlt(hSelDC, rectSel_dest[2] - 1, 0, -rectSel_dest[2], rectSel_dest[3], hSelDC,
890 0, 0, rectSel_dest[2], rectSel_dest[3], SRCCOPY);
891 SelectObject(hSelDC, hSelBm);
892 StretchBlt(hSelDC, rectSel_dest[2] - 1, 0, -rectSel_dest[2], rectSel_dest[3], hSelDC,
893 0, 0, rectSel_dest[2], rectSel_dest[3], SRCCOPY);
894 /* force refresh of selection contents, used also in case 2 and case 4 */
895 SendMessage(hSelection, WM_LBUTTONDOWN, 0, 0);
896 SendMessage(hSelection, WM_MOUSEMOVE, 0, 0);
897 SendMessage(hSelection, WM_LBUTTONUP, 0, 0);
898 }
899 else
900 {
901 newReversible();
902 StretchBlt(hDrawingDC, imgXRes - 1, 0, -imgXRes, imgYRes, hDrawingDC, 0, 0,
903 imgXRes, imgYRes, SRCCOPY);
904 SendMessage(hImageArea, WM_PAINT, 0, 0);
905 }
906 break;
907 case 2: /* flip vertically */
908 if (IsWindowVisible(hSelection))
909 {
910 SelectObject(hSelDC, hSelMask);
911 StretchBlt(hSelDC, 0, rectSel_dest[3] - 1, rectSel_dest[2], -rectSel_dest[3], hSelDC,
912 0, 0, rectSel_dest[2], rectSel_dest[3], SRCCOPY);
913 SelectObject(hSelDC, hSelBm);
914 StretchBlt(hSelDC, 0, rectSel_dest[3] - 1, rectSel_dest[2], -rectSel_dest[3], hSelDC,
915 0, 0, rectSel_dest[2], rectSel_dest[3], SRCCOPY);
916 SendMessage(hSelection, WM_LBUTTONDOWN, 0, 0);
917 SendMessage(hSelection, WM_MOUSEMOVE, 0, 0);
918 SendMessage(hSelection, WM_LBUTTONUP, 0, 0);
919 }
920 else
921 {
922 newReversible();
923 StretchBlt(hDrawingDC, 0, imgYRes - 1, imgXRes, -imgYRes, hDrawingDC, 0, 0,
924 imgXRes, imgYRes, SRCCOPY);
925 SendMessage(hImageArea, WM_PAINT, 0, 0);
926 }
927 break;
928 case 3: /* rotate 90 degrees */
929 break;
930 case 4: /* rotate 180 degrees */
931 if (IsWindowVisible(hSelection))
932 {
933 SelectObject(hSelDC, hSelMask);
934 StretchBlt(hSelDC, rectSel_dest[2] - 1, rectSel_dest[3] - 1, -rectSel_dest[2], -rectSel_dest[3], hSelDC,
935 0, 0, rectSel_dest[2], rectSel_dest[3], SRCCOPY);
936 SelectObject(hSelDC, hSelBm);
937 StretchBlt(hSelDC, rectSel_dest[2] - 1, rectSel_dest[3] - 1, -rectSel_dest[2], -rectSel_dest[3], hSelDC,
938 0, 0, rectSel_dest[2], rectSel_dest[3], SRCCOPY);
939 SendMessage(hSelection, WM_LBUTTONDOWN, 0, 0);
940 SendMessage(hSelection, WM_MOUSEMOVE, 0, 0);
941 SendMessage(hSelection, WM_LBUTTONUP, 0, 0);
942 }
943 else
944 {
945 newReversible();
946 StretchBlt(hDrawingDC, imgXRes - 1, imgYRes - 1, -imgXRes, -imgYRes, hDrawingDC,
947 0, 0, imgXRes, imgYRes, SRCCOPY);
948 SendMessage(hImageArea, WM_PAINT, 0, 0);
949 }
950 break;
951 case 5: /* rotate 270 degrees */
952 break;
953 }
954 break;
955 case IDM_IMAGEATTRIBUTES:
956 {
957 int retVal = attributesDlg();
958 if ((LOWORD(retVal) != 0) && (HIWORD(retVal) != 0))
959 {
960 cropReversible(LOWORD(retVal), HIWORD(retVal), 0, 0);
961 updateCanvasAndScrollbars();
962 }
963 break;
964 }
965 case IDM_IMAGECHANGESIZE:
966 {
967 int retVal = changeSizeDlg();
968 if ((LOWORD(retVal) != 0) && (HIWORD(retVal) != 0))
969 {
970 insertReversible(CopyImage(hBms[currInd], IMAGE_BITMAP,
971 imgXRes * LOWORD(retVal) / 100,
972 imgYRes * HIWORD(retVal) / 100, 0));
973 updateCanvasAndScrollbars();
974 }
975 break;
976 }
977 case IDM_IMAGEDRAWOPAQUE:
978 transpBg = 1 - transpBg;
979 SendMessage(hToolSettings, WM_PAINT, 0, 0);
980 break;
981 case IDM_IMAGECROP:
982 insertReversible(CopyImage(hSelBm, IMAGE_BITMAP, 0, 0, LR_COPYRETURNORG));
983 updateCanvasAndScrollbars();
984 break;
985
986 case IDM_VIEWTOOLBOX:
987 ShowWindow(hToolBoxContainer, IsWindowVisible(hToolBoxContainer) ? SW_HIDE : SW_SHOW);
988 alignChildrenToMainWindow();
989 break;
990 case IDM_VIEWCOLORPALETTE:
991 ShowWindow(hPalWin, IsWindowVisible(hPalWin) ? SW_HIDE : SW_SHOW);
992 alignChildrenToMainWindow();
993 break;
994 case IDM_VIEWSTATUSBAR:
995 ShowWindow(hStatusBar, IsWindowVisible(hStatusBar) ? SW_HIDE : SW_SHOW);
996 alignChildrenToMainWindow();
997 break;
998
999 case IDM_VIEWSHOWGRID:
1000 showGrid = !showGrid;
1001 SendMessage(hImageArea, WM_PAINT, 0, 0);
1002 break;
1003 case IDM_VIEWSHOWMINIATURE:
1004 showMiniature = !showMiniature;
1005 ShowWindow(hwndMiniature, showMiniature ? SW_SHOW : SW_HIDE);
1006 break;
1007
1008 case IDM_VIEWZOOM125:
1009 zoomTo(125, 0, 0);
1010 break;
1011 case IDM_VIEWZOOM25:
1012 zoomTo(250, 0, 0);
1013 break;
1014 case IDM_VIEWZOOM50:
1015 zoomTo(500, 0, 0);
1016 break;
1017 case IDM_VIEWZOOM100:
1018 zoomTo(1000, 0, 0);
1019 break;
1020 case IDM_VIEWZOOM200:
1021 zoomTo(2000, 0, 0);
1022 break;
1023 case IDM_VIEWZOOM400:
1024 zoomTo(4000, 0, 0);
1025 break;
1026 case IDM_VIEWZOOM800:
1027 zoomTo(8000, 0, 0);
1028 break;
1029 case ID_FREESEL:
1030 selectTool(1);
1031 break;
1032 case ID_RECTSEL:
1033 selectTool(2);
1034 break;
1035 case ID_RUBBER:
1036 selectTool(3);
1037 break;
1038 case ID_FILL:
1039 selectTool(4);
1040 break;
1041 case ID_COLOR:
1042 selectTool(5);
1043 break;
1044 case ID_ZOOM:
1045 selectTool(6);
1046 break;
1047 case ID_PEN:
1048 selectTool(7);
1049 break;
1050 case ID_BRUSH:
1051 selectTool(8);
1052 break;
1053 case ID_AIRBRUSH:
1054 selectTool(9);
1055 break;
1056 case ID_TEXT:
1057 selectTool(10);
1058 break;
1059 case ID_LINE:
1060 selectTool(11);
1061 break;
1062 case ID_BEZIER:
1063 selectTool(12);
1064 break;
1065 case ID_RECT:
1066 selectTool(13);
1067 break;
1068 case ID_SHAPE:
1069 selectTool(14);
1070 break;
1071 case ID_ELLIPSE:
1072 selectTool(15);
1073 break;
1074 case ID_RRECT:
1075 selectTool(16);
1076 break;
1077 }
1078 break;
1079 default:
1080 return DefWindowProc(hwnd, message, wParam, lParam);
1081 }
1082
1083 return 0;
1084 }