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