Synchronize with trunk r58457.
[reactos.git] / dll / win32 / shimgvw / shimgvw.c
1 /*
2 *
3 * PROJECT: ReactOS Picture and Fax Viewer
4 * FILE: dll/win32/shimgvw/shimgvw.c
5 * PURPOSE: shimgvw.dll
6 * PROGRAMMER: Dmitry Chapyshev (dmitry@reactos.org)
7 *
8 * UPDATE HISTORY:
9 * 28/05/2008 Created
10 */
11
12 #define WIN32_NO_STATUS
13 #define _INC_WINDOWS
14 #define COM_NO_WINDOWS_H
15
16 #include <stdarg.h>
17
18 #include <windef.h>
19 #include <winbase.h>
20 #include <winnls.h>
21 #include <winreg.h>
22 #include <wingdi.h>
23 #include <objbase.h>
24 #include <commctrl.h>
25 #include <gdiplus.h>
26 #include <tchar.h>
27
28 #define NDEBUG
29 #include <debug.h>
30
31 #include "shimgvw.h"
32
33
34 HINSTANCE hInstance;
35 SHIMGVW_SETTINGS shiSettings;
36 GpImage *image;
37 WNDPROC PrevProc = NULL;
38
39 HWND hDispWnd, hToolBar;
40
41 /* ToolBar Buttons */
42 static const TBBUTTON Buttons [] =
43 { /* iBitmap, idCommand, fsState, fsStyle, bReserved[2], dwData, iString */
44 {TBICON_PREV, IDC_PREV, TBSTATE_ENABLED, BTNS_BUTTON, {0}, 0, 0},
45 {TBICON_NEXT, IDC_NEXT, TBSTATE_ENABLED, BTNS_BUTTON, {0}, 0, 0},
46 {15, 0, TBSTATE_ENABLED, BTNS_SEP, {0}, 0, 0},
47 {TBICON_ZOOMP, IDC_ZOOMP, TBSTATE_ENABLED, BTNS_BUTTON, {0}, 0, 0},
48 {TBICON_ZOOMM, IDC_ZOOMM, TBSTATE_ENABLED, BTNS_BUTTON, {0}, 0, 0},
49 {15, 0, TBSTATE_ENABLED, BTNS_SEP, {0}, 0, 0},
50 {TBICON_ROT1, IDC_ROT1, TBSTATE_ENABLED, BTNS_BUTTON, {0}, 0, 0},
51 {TBICON_ROT2, IDC_ROT2, TBSTATE_ENABLED, BTNS_BUTTON, {0}, 0, 0},
52 {15, 0, TBSTATE_ENABLED, BTNS_SEP, {0}, 0, 0},
53 {TBICON_SAVE, IDC_SAVE, TBSTATE_ENABLED, BTNS_BUTTON, {0}, 0, 0},
54 {TBICON_PRINT, IDC_PRINT, TBSTATE_ENABLED, BTNS_BUTTON, {0}, 0, 0},
55 };
56
57 static void pLoadImage(LPWSTR szOpenFileName)
58 {
59 if (GetFileAttributesW(szOpenFileName) == 0xFFFFFFFF)
60 {
61 DPRINT1("File %s not found!\n", szOpenFileName);
62 return;
63 }
64
65 GdipLoadImageFromFile(szOpenFileName, &image);
66 if (!image)
67 {
68 DPRINT1("GdipLoadImageFromFile() failed\n");
69 }
70 }
71
72 static VOID
73 ImageView_DrawImage(HWND hwnd)
74 {
75 GpGraphics *graphics;
76 UINT uImgWidth, uImgHeight;
77 UINT height = 0, width = 0, x = 0, y = 0;
78 PAINTSTRUCT ps;
79 RECT rect;
80 HDC hdc;
81
82 hdc = BeginPaint(hwnd, &ps);
83 if (!hdc)
84 {
85 DPRINT1("BeginPaint() failed\n");
86 return;
87 }
88
89 GdipCreateFromHDC(hdc, &graphics);
90 if (!graphics)
91 {
92 DPRINT1("GdipCreateFromHDC() failed\n");
93 return;
94 }
95
96 GdipGetImageWidth(image, &uImgWidth);
97 GdipGetImageHeight(image, &uImgHeight);
98
99 if (GetClientRect(hwnd, &rect))
100 {
101 FillRect(hdc, &rect, (HBRUSH)GetStockObject(WHITE_BRUSH));
102
103 if ((rect.right == uImgWidth)&&(rect.bottom == uImgHeight))
104 {
105 x = 0, y = 0, width = rect.right, height = rect.bottom;
106 }
107 else if ((rect.right >= uImgWidth)&&(rect.bottom >= uImgHeight))
108 {
109 x = (rect.right/2)-(uImgWidth/2);
110 y = (rect.bottom/2)-(uImgHeight/2);
111 width = uImgWidth;
112 height = uImgHeight;
113 }
114 else if ((rect.right < uImgWidth)||(rect.bottom < uImgHeight))
115 {
116 if (rect.bottom < uImgHeight)
117 {
118 height = rect.bottom;
119 width = uImgWidth*(UINT)rect.bottom/uImgHeight;
120 x = (rect.right/2)-(width/2);
121 y = (rect.bottom/2)-(height/2);
122 }
123 if (rect.right < uImgWidth)
124 {
125 width = rect.right;
126 height = uImgHeight*(UINT)rect.right/uImgWidth;
127 x = (rect.right/2)-(width/2);
128 y = (rect.bottom/2)-(height/2);
129 }
130 if ((height > rect.bottom)||(width > rect.right))
131 {
132 for (;;)
133 {
134 if (((int)width - 1 < 0)||((int)height - 1 < 0)) break;
135 width -= 1;
136 height -= 1;
137 y = (rect.bottom/2)-(height/2);
138 x = (rect.right/2)-(width/2);
139 if ((height < rect.bottom)&&(width < rect.right)) break;
140 }
141 }
142 }
143 else if ((rect.right <= uImgWidth)&&(rect.bottom <= uImgHeight))
144 {
145 height = uImgHeight*(UINT)rect.right/uImgWidth;
146 y = (rect.bottom/2)-(height/2);
147 width = rect.right;
148
149 if ((height > rect.bottom)||(width > rect.right))
150 {
151 for (;;)
152 {
153 if (((int)width - 1 < 0)||((int)height - 1 < 0)) break;
154 width -= 1;
155 height -= 1;
156 y = (rect.bottom/2)-(height/2);
157 x = (rect.right/2)-(width/2);
158 if ((height < rect.bottom)&&(width < rect.right)) break;
159 }
160 }
161 }
162
163 DPRINT("x = %d\ny = %d\nWidth = %d\nHeight = %d\n\nrect.right = %d\nrect.bottom = %d\n\nuImgWidth = %d\nuImgHeight = %d\n", x, y, width, height, rect.right, rect.bottom, uImgWidth, uImgHeight);
164 Rectangle(hdc, x - 1, y - 1, x + width + 1, y + height + 1);
165 GdipDrawImageRect(graphics, image, x, y, width, height);
166 }
167 GdipDeleteGraphics(graphics);
168 EndPaint(hwnd, &ps);
169 }
170
171 static BOOL
172 ImageView_LoadSettings()
173 {
174 HKEY hKey;
175 DWORD dwSize;
176
177 if (RegOpenKeyEx(HKEY_CURRENT_USER, _T("Software\\ReactOS\\shimgvw"), 0, KEY_READ, &hKey) == ERROR_SUCCESS)
178 {
179 dwSize = sizeof(SHIMGVW_SETTINGS);
180 if (RegQueryValueEx(hKey, _T("Settings"), NULL, NULL, (LPBYTE)&shiSettings, &dwSize) == ERROR_SUCCESS)
181 {
182 RegCloseKey(hKey);
183 return TRUE;
184 }
185
186 RegCloseKey(hKey);
187 }
188
189 return FALSE;
190 }
191
192 static VOID
193 ImageView_SaveSettings(HWND hwnd)
194 {
195 WINDOWPLACEMENT wp;
196 HKEY hKey;
197
198 ShowWindow(hwnd, SW_HIDE);
199 wp.length = sizeof(WINDOWPLACEMENT);
200 GetWindowPlacement(hwnd, &wp);
201
202 shiSettings.Left = wp.rcNormalPosition.left;
203 shiSettings.Top = wp.rcNormalPosition.top;
204 shiSettings.Right = wp.rcNormalPosition.right;
205 shiSettings.Bottom = wp.rcNormalPosition.bottom;
206 shiSettings.Maximized = (IsZoomed(hwnd) || (wp.flags & WPF_RESTORETOMAXIMIZED));
207
208 if (RegCreateKeyEx(HKEY_CURRENT_USER, _T("Software\\ReactOS\\shimgvw"), 0, NULL,
209 REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL, &hKey, NULL) == ERROR_SUCCESS)
210 {
211 RegSetValueEx(hKey, _T("Settings"), 0, REG_BINARY, (LPBYTE)&shiSettings, sizeof(SHIMGVW_SETTINGS));
212 RegCloseKey(hKey);
213 }
214 }
215
216 static BOOL
217 ImageView_CreateToolBar(HWND hwnd)
218 {
219 INT numButtons = sizeof(Buttons) / sizeof(Buttons[0]);
220
221 hToolBar = CreateWindowEx(0, TOOLBARCLASSNAME, NULL,
222 WS_CHILD | WS_VISIBLE | TBSTYLE_FLAT | CCS_BOTTOM | TBSTYLE_TOOLTIPS,
223 0, 0, 0, 0, hwnd,
224 0, hInstance, NULL);
225 if(hToolBar != NULL)
226 {
227 HIMAGELIST hImageList;
228
229 SendMessage(hToolBar, TB_SETEXTENDEDSTYLE,
230 0, TBSTYLE_EX_HIDECLIPPEDBUTTONS);
231
232 SendMessage(hToolBar, TB_BUTTONSTRUCTSIZE,
233 sizeof(Buttons[0]), 0);
234
235 hImageList = ImageList_Create(TB_IMAGE_WIDTH, TB_IMAGE_HEIGHT, ILC_MASK | ILC_COLOR24, 1, 1);
236
237 ImageList_AddMasked(hImageList, LoadImage(hInstance, MAKEINTRESOURCE(IDB_PREVICON), IMAGE_BITMAP,
238 TB_IMAGE_WIDTH, TB_IMAGE_HEIGHT, LR_DEFAULTCOLOR), RGB(255, 255, 255));
239
240 ImageList_AddMasked(hImageList, LoadImage(hInstance, MAKEINTRESOURCE(IDB_NEXTICON), IMAGE_BITMAP,
241 TB_IMAGE_WIDTH, TB_IMAGE_HEIGHT, LR_DEFAULTCOLOR), RGB(255, 255, 255));
242
243 ImageList_AddMasked(hImageList, LoadImage(hInstance, MAKEINTRESOURCE(IDB_ZOOMPICON), IMAGE_BITMAP,
244 TB_IMAGE_WIDTH, TB_IMAGE_HEIGHT, LR_DEFAULTCOLOR), RGB(255, 255, 255));
245
246 ImageList_AddMasked(hImageList, LoadImage(hInstance, MAKEINTRESOURCE(IDB_ZOOMMICON), IMAGE_BITMAP,
247 TB_IMAGE_WIDTH, TB_IMAGE_HEIGHT, LR_DEFAULTCOLOR), RGB(255, 255, 255));
248
249 ImageList_AddMasked(hImageList, LoadImage(hInstance, MAKEINTRESOURCE(IDB_SAVEICON), IMAGE_BITMAP,
250 TB_IMAGE_WIDTH, TB_IMAGE_HEIGHT, LR_DEFAULTCOLOR), RGB(255, 255, 255));
251
252 ImageList_AddMasked(hImageList, LoadImage(hInstance, MAKEINTRESOURCE(IDB_PRINTICON), IMAGE_BITMAP,
253 TB_IMAGE_WIDTH, TB_IMAGE_HEIGHT, LR_DEFAULTCOLOR), RGB(255, 255, 255));
254
255 ImageList_AddMasked(hImageList, LoadImage(hInstance, MAKEINTRESOURCE(IDB_ROT1ICON), IMAGE_BITMAP,
256 TB_IMAGE_WIDTH, TB_IMAGE_HEIGHT, LR_DEFAULTCOLOR), RGB(255, 255, 255));
257
258 ImageList_AddMasked(hImageList, LoadImage(hInstance, MAKEINTRESOURCE(IDB_ROT2ICON), IMAGE_BITMAP,
259 TB_IMAGE_WIDTH, TB_IMAGE_HEIGHT, LR_DEFAULTCOLOR), RGB(255, 255, 255));
260
261 if (hImageList == NULL) return FALSE;
262
263 ImageList_Destroy((HIMAGELIST)SendMessage(hToolBar, TB_SETIMAGELIST,
264 0, (LPARAM)hImageList));
265
266 SendMessage(hToolBar, TB_ADDBUTTONS,
267 numButtons, (LPARAM)Buttons);
268
269 return TRUE;
270 }
271
272 return FALSE;
273 }
274
275 LRESULT CALLBACK
276 ImageView_DispWndProc(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lParam)
277 {
278 switch (Message)
279 {
280 case WM_PAINT:
281 {
282 ImageView_DrawImage(hwnd);
283 return 0L;
284 }
285 }
286 return CallWindowProc(PrevProc, hwnd, Message, wParam, lParam);
287 }
288
289 static VOID
290 ImageView_InitControls(HWND hwnd)
291 {
292 MoveWindow(hwnd, shiSettings.Left, shiSettings.Top,
293 shiSettings.Right - shiSettings.Left,
294 shiSettings.Bottom - shiSettings.Top, TRUE);
295
296 if (shiSettings.Maximized) ShowWindow(hwnd, SW_MAXIMIZE);
297
298 hDispWnd = CreateWindowEx(0, _T("STATIC"), _T(""),
299 WS_CHILD | WS_VISIBLE,
300 0, 0, 0, 0, hwnd, NULL, hInstance, NULL);
301
302 SetClassLongPtr(hDispWnd, GCL_STYLE, CS_HREDRAW | CS_VREDRAW);
303 PrevProc = (WNDPROC) SetWindowLongPtr(hDispWnd, GWL_WNDPROC, (LPARAM) ImageView_DispWndProc);
304
305 ImageView_CreateToolBar(hwnd);
306 }
307
308 LRESULT CALLBACK
309 ImageView_WndProc(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lParam)
310 {
311 switch (Message)
312 {
313 case WM_CREATE:
314 {
315 ImageView_InitControls(hwnd);
316 return 0L;
317 }
318 case WM_COMMAND:
319 {
320 switch (wParam)
321 {
322 case IDC_PREV:
323
324 break;
325 case IDC_NEXT:
326
327 break;
328 case IDC_ZOOMP:
329
330 break;
331 case IDC_ZOOMM:
332
333 break;
334 case IDC_SAVE:
335
336 break;
337 case IDC_PRINT:
338
339 break;
340 case IDC_ROT1:
341
342 break;
343 case IDC_ROT2:
344
345 break;
346 }
347 }
348 break;
349
350 case WM_NOTIFY:
351 {
352 LPNMHDR pnmhdr = (LPNMHDR)lParam;
353
354 switch (pnmhdr->code)
355 {
356 case TTN_GETDISPINFO:
357 {
358 LPTOOLTIPTEXT lpttt;
359 UINT idButton;
360
361 lpttt = (LPTOOLTIPTEXT)lParam;
362 idButton = (UINT)lpttt->hdr.idFrom;
363
364 switch (idButton)
365 {
366 case IDC_PREV:
367 lpttt->lpszText = MAKEINTRESOURCE(IDS_TOOLTIP_PREV_PIC);
368 break;
369 case IDC_NEXT:
370 lpttt->lpszText = MAKEINTRESOURCE(IDS_TOOLTIP_NEXT_PIC);
371 break;
372 case IDC_ZOOMP:
373 lpttt->lpszText = MAKEINTRESOURCE(IDS_TOOLTIP_ZOOM_IN);
374 break;
375 case IDC_ZOOMM:
376 lpttt->lpszText = MAKEINTRESOURCE(IDS_TOOLTIP_ZOOM_OUT);
377 break;
378 case IDC_SAVE:
379 lpttt->lpszText = MAKEINTRESOURCE(IDS_TOOLTIP_SAVEAS);
380 break;
381 case IDC_PRINT:
382 lpttt->lpszText = MAKEINTRESOURCE(IDS_TOOLTIP_PRINT);
383 break;
384 case IDC_ROT1:
385 lpttt->lpszText = MAKEINTRESOURCE(IDS_TOOLTIP_ROT_COUNCW);
386 break;
387 case IDC_ROT2:
388 lpttt->lpszText = MAKEINTRESOURCE(IDS_TOOLTIP_ROT_CLOCKW);
389 break;
390 }
391 return TRUE;
392 }
393 }
394 break;
395 }
396 case WM_SIZING:
397 {
398 LPRECT pRect = (LPRECT)lParam;
399 if (pRect->right-pRect->left < 350)
400 pRect->right = pRect->left + 350;
401
402 if (pRect->bottom-pRect->top < 290)
403 pRect->bottom = pRect->top + 290;
404 return TRUE;
405 }
406 case WM_SIZE:
407 {
408 RECT rc;
409 SendMessage(hToolBar, TB_AUTOSIZE, 0, 0);
410 SendMessage(hToolBar, TB_GETITEMRECT, 1, (LPARAM)&rc);
411 MoveWindow(hDispWnd, 1, 1, LOWORD(lParam)-1, HIWORD(lParam)-rc.bottom, TRUE);
412 return 0L;
413 }
414 case WM_DESTROY:
415 {
416 ImageView_SaveSettings(hwnd);
417 SetWindowLongPtr(hDispWnd, GWL_WNDPROC, (LPARAM) PrevProc);
418 PostQuitMessage(0);
419 break;
420 }
421 }
422
423 return DefWindowProc(hwnd, Message, wParam, lParam);
424 }
425
426 LONG WINAPI
427 ImageView_CreateWindow(HWND hwnd, LPWSTR szFileName)
428 {
429 struct GdiplusStartupInput gdiplusStartupInput;
430 ULONG_PTR gdiplusToken;
431 WNDCLASS WndClass = {0};
432 TCHAR szBuf[512];
433 HWND hMainWnd;
434 MSG msg;
435
436 if (!ImageView_LoadSettings())
437 {
438 shiSettings.Maximized = FALSE;
439 shiSettings.Left = 0;
440 shiSettings.Top = 0;
441 shiSettings.Right = 520;
442 shiSettings.Bottom = 400;
443 }
444
445 // Initialize GDI+
446 gdiplusStartupInput.GdiplusVersion = 1;
447 gdiplusStartupInput.DebugEventCallback = NULL;
448 gdiplusStartupInput.SuppressBackgroundThread = FALSE;
449 gdiplusStartupInput.SuppressExternalCodecs = FALSE;
450
451 GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL);
452 pLoadImage(szFileName);
453
454 // Create the window
455 WndClass.lpszClassName = _T("shimgvw_window");
456 WndClass.lpfnWndProc = (WNDPROC)ImageView_WndProc;
457 WndClass.hInstance = hInstance;
458 WndClass.style = CS_HREDRAW | CS_VREDRAW;
459 WndClass.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_APPICON));
460 WndClass.hCursor = LoadCursor(hInstance, IDC_ARROW);
461 WndClass.hbrBackground = (HBRUSH)COLOR_WINDOW;
462
463 if (!RegisterClass(&WndClass)) return -1;
464
465 LoadString(hInstance, IDS_APPTITLE, szBuf, sizeof(szBuf) / sizeof(TCHAR));
466 hMainWnd = CreateWindow(_T("shimgvw_window"), szBuf,
467 WS_OVERLAPPEDWINDOW | WS_VISIBLE | WS_CAPTION,
468 CW_USEDEFAULT, CW_USEDEFAULT,
469 0, 0, NULL, NULL, hInstance, NULL);
470
471 // Show it
472 ShowWindow(hMainWnd, SW_SHOW);
473 UpdateWindow(hMainWnd);
474
475 // Message Loop
476 while(GetMessage(&msg,NULL,0,0))
477 {
478 TranslateMessage(&msg);
479 DispatchMessageW(&msg);
480 }
481
482 if (image)
483 GdipDisposeImage(image);
484 GdiplusShutdown(gdiplusToken);
485 return -1;
486 }
487
488 VOID WINAPI
489 ImageView_FullscreenW(HWND hwnd, HINSTANCE hInst, LPCWSTR path, int nShow)
490 {
491 ImageView_CreateWindow(hwnd, (LPWSTR)path);
492 }
493
494 VOID WINAPI
495 ImageView_Fullscreen(HWND hwnd, HINSTANCE hInst, LPCWSTR path, int nShow)
496 {
497 ImageView_CreateWindow(hwnd, (LPWSTR)path);
498 }
499
500 VOID WINAPI
501 ImageView_FullscreenA(HWND hwnd, HINSTANCE hInst, LPCSTR path, int nShow)
502 {
503 WCHAR szFile[MAX_PATH];
504
505 if (MultiByteToWideChar(CP_ACP, 0, (char*)path, strlen((char*)path)+1, szFile, MAX_PATH))
506 {
507 ImageView_CreateWindow(hwnd, (LPWSTR)szFile);
508 }
509 }
510
511 VOID WINAPI
512 ImageView_PrintTo(HWND hwnd, HINSTANCE hInst, LPCWSTR path, int nShow)
513 {
514 DPRINT("ImageView_PrintTo() not implemented\n");
515 }
516
517 VOID WINAPI
518 ImageView_PrintToA(HWND hwnd, HINSTANCE hInst, LPCSTR path, int nShow)
519 {
520 DPRINT("ImageView_PrintToA() not implemented\n");
521 }
522
523 VOID WINAPI
524 ImageView_PrintToW(HWND hwnd, HINSTANCE hInst, LPCWSTR path, int nShow)
525 {
526 DPRINT("ImageView_PrintToW() not implemented\n");
527 }
528
529 BOOL WINAPI
530 DllMain(IN HINSTANCE hinstDLL,
531 IN DWORD dwReason,
532 IN LPVOID lpvReserved)
533 {
534 switch (dwReason)
535 {
536 case DLL_PROCESS_ATTACH:
537 case DLL_THREAD_ATTACH:
538 hInstance = hinstDLL;
539 break;
540 }
541
542 return TRUE;
543 }
544