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