2 * PROJECT: ReactOS Picture and Fax Viewer
3 * FILE: dll/win32/shimgvw/shimgvw.c
5 * PROGRAMMERS: Dmitry Chapyshev (dmitry@reactos.org)
6 * Katayama Hirofumi MZ (katayama.hirofumi.mz@gmail.com)
9 #define WIN32_NO_STATUS
11 #define COM_NO_WINDOWS_H
36 SHIMGVW_SETTINGS shiSettings
;
37 SHIMGVW_FILENODE
*currentFile
;
39 WNDPROC PrevProc
= NULL
;
41 HWND hDispWnd
, hToolBar
;
46 UINT ZoomPercents
= 100;
47 static const UINT ZoomSteps
[] =
49 10, 25, 50, 100, 200, 400, 800, 1600
53 UINT m_nFrameIndex
= 0;
54 UINT m_nFrameCount
= 0;
55 UINT m_nLoopIndex
= 0;
56 UINT m_nLoopCount
= (UINT
)-1;
57 PropertyItem
*m_pDelayItem
= NULL
;
59 #define ANIME_TIMER_ID 9999
61 static void Anime_FreeInfo(void)
71 m_nLoopCount
= (UINT
)-1;
74 static BOOL
Anime_LoadInfo(void)
83 KillTimer(hDispWnd
, ANIME_TIMER_ID
);
88 GdipImageGetFrameDimensionsCount(image
, &nDimCount
);
91 dims
= (GUID
*)calloc(nDimCount
, sizeof(GUID
));
94 GdipImageGetFrameDimensionsList(image
, dims
, nDimCount
);
95 GdipImageGetFrameCount(image
, dims
, &result
);
96 m_nFrameCount
= result
;
102 GdipGetPropertyItemSize(image
, PropertyTagFrameDelay
, &result
);
106 m_pDelayItem
= (PropertyItem
*)malloc(cbItem
);
107 GdipGetPropertyItem(image
, PropertyTagFrameDelay
, cbItem
, m_pDelayItem
);
111 GdipGetPropertyItemSize(image
, PropertyTagLoopCount
, &result
);
115 pItem
= (PropertyItem
*)malloc(cbItem
);
118 if (GdipGetPropertyItem(image
, PropertyTagLoopCount
, cbItem
, pItem
) == Ok
)
120 m_nLoopCount
= *(WORD
*)pItem
->value
;
128 SetTimer(hDispWnd
, ANIME_TIMER_ID
, 0, NULL
);
131 return m_pDelayItem
!= NULL
;
134 static void Anime_SetFrameIndex(UINT nFrameIndex
)
136 if (nFrameIndex
< m_nFrameCount
)
138 GUID guid
= FrameDimensionTime
;
139 if (Ok
!= GdipImageSelectActiveFrame(image
, &guid
, nFrameIndex
))
141 guid
= FrameDimensionPage
;
142 GdipImageSelectActiveFrame(image
, &guid
, nFrameIndex
);
145 m_nFrameIndex
= nFrameIndex
;
148 DWORD
Anime_GetFrameDelay(UINT nFrameIndex
)
150 if (nFrameIndex
< m_nFrameCount
&& m_pDelayItem
)
152 return ((DWORD
*)m_pDelayItem
->value
)[m_nFrameIndex
] * 10;
157 BOOL
Anime_Step(DWORD
*pdwDelay
)
159 *pdwDelay
= INFINITE
;
160 if (m_nLoopCount
== (UINT
)-1)
163 if (m_nFrameIndex
+ 1 < m_nFrameCount
)
165 *pdwDelay
= Anime_GetFrameDelay(m_nFrameIndex
);
166 Anime_SetFrameIndex(m_nFrameIndex
);
171 if (m_nLoopCount
== 0 || m_nLoopIndex
< m_nLoopCount
)
173 *pdwDelay
= Anime_GetFrameDelay(m_nFrameIndex
);
174 Anime_SetFrameIndex(m_nFrameIndex
);
183 static void ZoomInOrOut(BOOL bZoomIn
)
187 if (bZoomIn
) /* zoom in */
190 for (i
= 0; i
< ARRAYSIZE(ZoomSteps
); ++i
)
192 if (ZoomPercents
< ZoomSteps
[i
])
195 if (i
== ARRAYSIZE(ZoomSteps
))
196 ZoomPercents
= MAX_ZOOM
;
198 ZoomPercents
= ZoomSteps
[i
];
200 /* update tool bar buttons */
201 SendMessage(hToolBar
, TB_ENABLEBUTTON
, IDC_ZOOMM
, TRUE
);
202 if (ZoomPercents
>= MAX_ZOOM
)
203 SendMessage(hToolBar
, TB_ENABLEBUTTON
, IDC_ZOOMP
, FALSE
);
205 SendMessage(hToolBar
, TB_ENABLEBUTTON
, IDC_ZOOMP
, TRUE
);
209 /* find previous step */
210 for (i
= ARRAYSIZE(ZoomSteps
); i
> 0; )
213 if (ZoomSteps
[i
] < ZoomPercents
)
217 ZoomPercents
= MIN_ZOOM
;
219 ZoomPercents
= ZoomSteps
[i
];
221 /* update tool bar buttons */
222 SendMessage(hToolBar
, TB_ENABLEBUTTON
, IDC_ZOOMP
, TRUE
);
223 if (ZoomPercents
<= MIN_ZOOM
)
224 SendMessage(hToolBar
, TB_ENABLEBUTTON
, IDC_ZOOMM
, FALSE
);
226 SendMessage(hToolBar
, TB_ENABLEBUTTON
, IDC_ZOOMM
, TRUE
);
230 InvalidateRect(hDispWnd
, NULL
, TRUE
);
233 static void ResetZoom(void)
236 UINT ImageWidth
, ImageHeight
;
238 /* get disp window size and image size */
239 GetClientRect(hDispWnd
, &Rect
);
240 GdipGetImageWidth(image
, &ImageWidth
);
241 GdipGetImageHeight(image
, &ImageHeight
);
243 /* compare two aspect rates. same as
244 (ImageHeight / ImageWidth < Rect.bottom / Rect.right) in real */
245 if (ImageHeight
* Rect
.right
< Rect
.bottom
* ImageWidth
)
247 if (Rect
.right
< ImageWidth
)
249 /* it's large, shrink it */
250 ZoomPercents
= (Rect
.right
* 100) / ImageWidth
;
254 /* it's small. show as original size */
260 if (Rect
.bottom
< ImageHeight
)
262 /* it's large, shrink it */
263 ZoomPercents
= (Rect
.bottom
* 100) / ImageHeight
;
267 /* it's small. show as original size */
273 /* ToolBar Buttons */
274 static const TBBUTTON Buttons
[] =
275 { /* iBitmap, idCommand, fsState, fsStyle, bReserved[2], dwData, iString */
276 {TBICON_PREV
, IDC_PREV
, TBSTATE_ENABLED
, BTNS_BUTTON
, {0}, 0, 0},
277 {TBICON_NEXT
, IDC_NEXT
, TBSTATE_ENABLED
, BTNS_BUTTON
, {0}, 0, 0},
278 {15, 0, TBSTATE_ENABLED
, BTNS_SEP
, {0}, 0, 0},
279 {TBICON_ZOOMP
, IDC_ZOOMP
, TBSTATE_ENABLED
, BTNS_BUTTON
, {0}, 0, 0},
280 {TBICON_ZOOMM
, IDC_ZOOMM
, TBSTATE_ENABLED
, BTNS_BUTTON
, {0}, 0, 0},
281 {15, 0, TBSTATE_ENABLED
, BTNS_SEP
, {0}, 0, 0},
282 {TBICON_ROT1
, IDC_ROT1
, TBSTATE_ENABLED
, BTNS_BUTTON
, {0}, 0, 0},
283 {TBICON_ROT2
, IDC_ROT2
, TBSTATE_ENABLED
, BTNS_BUTTON
, {0}, 0, 0},
284 {15, 0, TBSTATE_ENABLED
, BTNS_SEP
, {0}, 0, 0},
285 {TBICON_SAVE
, IDC_SAVE
, TBSTATE_ENABLED
, BTNS_BUTTON
, {0}, 0, 0},
286 {TBICON_PRINT
, IDC_PRINT
, TBSTATE_ENABLED
, BTNS_BUTTON
, {0}, 0, 0},
289 static void pLoadImage(LPWSTR szOpenFileName
)
291 /* check file presence */
292 if (GetFileAttributesW(szOpenFileName
) == 0xFFFFFFFF)
294 DPRINT1("File %s not found!\n", szOpenFileName
);
299 GdipLoadImageFromFile(szOpenFileName
, &image
);
302 DPRINT1("GdipLoadImageFromFile() failed\n");
311 InvalidateRect(hDispWnd
, NULL
, TRUE
);
314 static void pSaveImageAs(HWND hwnd
)
317 ImageCodecInfo
*codecInfo
;
318 WCHAR szSaveFileName
[MAX_PATH
];
327 GdipGetImageEncodersSize(&num
, &size
);
328 codecInfo
= malloc(size
);
331 DPRINT1("malloc() failed in pSaveImageAs()\n");
335 GdipGetImageEncoders(num
, size
, codecInfo
);
336 GdipGetImageRawFormat(image
, &rawFormat
);
340 for (j
= 0; j
< num
; ++j
)
342 // Every pair needs space for the Description, twice the Extensions, 1 char for the space, 2 for the braces and 2 for the NULL terminators.
343 sizeRemain
= sizeRemain
+ (((wcslen(codecInfo
[j
].FormatDescription
) + (wcslen(codecInfo
[j
].FilenameExtension
) * 2) + 5) * sizeof(WCHAR
)));
346 /* Add two more chars for the last terminator */
347 sizeRemain
= sizeRemain
+ (sizeof(WCHAR
) * 2);
349 szFilterMask
= malloc(sizeRemain
);
352 DPRINT1("cannot allocate memory for filter mask in pSaveImageAs()");
357 ZeroMemory(szSaveFileName
, sizeof(szSaveFileName
));
358 ZeroMemory(szFilterMask
, sizeRemain
);
359 ZeroMemory(&sfn
, sizeof(sfn
));
360 sfn
.lStructSize
= sizeof(sfn
);
361 sfn
.hwndOwner
= hwnd
;
362 sfn
.hInstance
= hInstance
;
363 sfn
.lpstrFile
= szSaveFileName
;
364 sfn
.lpstrFilter
= szFilterMask
;
365 sfn
.nMaxFile
= MAX_PATH
;
366 sfn
.Flags
= OFN_OVERWRITEPROMPT
| OFN_HIDEREADONLY
;
370 for (j
= 0; j
< num
; ++j
)
372 StringCbPrintfExW(c
, sizeRemain
, &c
, &sizeRemain
, 0, L
"%ls (%ls)", codecInfo
[j
].FormatDescription
, codecInfo
[j
].FilenameExtension
);
374 /* Skip the NULL character */
376 sizeRemain
-= sizeof(*c
);
378 StringCbPrintfExW(c
, sizeRemain
, &c
, &sizeRemain
, 0, L
"%ls", codecInfo
[j
].FilenameExtension
);
380 /* Skip the NULL character */
382 sizeRemain
-= sizeof(*c
);
384 if (IsEqualGUID(&rawFormat
, &codecInfo
[j
].FormatID
) != FALSE
)
386 sfn
.nFilterIndex
= j
+ 1;
390 if (GetSaveFileNameW(&sfn
))
395 KillTimer(hDispWnd
, ANIME_TIMER_ID
);
397 DPRINT1("FIXME: save animation\n");
398 if (GdipSaveImageToFile(image
, szSaveFileName
, &codecInfo
[sfn
.nFilterIndex
- 1].Clsid
, NULL
) != Ok
)
400 DPRINT1("GdipSaveImageToFile() failed\n");
403 SetTimer(hDispWnd
, ANIME_TIMER_ID
, 0, NULL
);
407 /* save non-animation */
408 if (GdipSaveImageToFile(image
, szSaveFileName
, &codecInfo
[sfn
.nFilterIndex
- 1].Clsid
, NULL
) != Ok
)
410 DPRINT1("GdipSaveImageToFile() failed\n");
420 pLoadImageFromNode(SHIMGVW_FILENODE
*node
, HWND hwnd
)
422 WCHAR szTitleBuf
[800];
428 c
= wcsrchr(node
->FileName
, '\\');
434 LoadStringW(hInstance
, IDS_APPTITLE
, szResStr
, ARRAYSIZE(szResStr
));
435 StringCbPrintfW(szTitleBuf
, sizeof(szTitleBuf
), L
"%ls%ls%ls", szResStr
, L
" - ", c
);
436 SetWindowTextW(hwnd
, szTitleBuf
);
440 GdipDisposeImage(image
);
443 pLoadImage(node
->FileName
);
447 static SHIMGVW_FILENODE
*
448 pBuildFileList(LPWSTR szFirstFile
)
452 WCHAR szSearchPath
[MAX_PATH
];
453 WCHAR szSearchMask
[MAX_PATH
];
454 WCHAR szFileTypes
[MAX_PATH
];
455 WIN32_FIND_DATAW findData
;
456 SHIMGVW_FILENODE
*currentNode
= NULL
;
457 SHIMGVW_FILENODE
*root
= NULL
;
458 SHIMGVW_FILENODE
*conductor
= NULL
;
459 ImageCodecInfo
*codecInfo
;
464 StringCbCopyW(szSearchPath
, sizeof(szSearchPath
), szFirstFile
);
465 PathRemoveFileSpecW(szSearchPath
);
467 GdipGetImageDecodersSize(&num
, &size
);
468 codecInfo
= malloc(size
);
471 DPRINT1("malloc() failed in pLoadFileList()\n");
475 GdipGetImageDecoders(num
, size
, codecInfo
);
477 root
= malloc(sizeof(SHIMGVW_FILENODE
));
480 DPRINT1("malloc() failed in pLoadFileList()\n");
487 for (j
= 0; j
< num
; ++j
)
489 StringCbCopyW(szFileTypes
, sizeof(szFileTypes
), codecInfo
[j
].FilenameExtension
);
491 extension
= wcstok(szFileTypes
, L
";");
492 while (extension
!= NULL
)
494 PathCombineW(szSearchMask
, szSearchPath
, extension
);
496 hFindHandle
= FindFirstFileW(szSearchMask
, &findData
);
497 if (hFindHandle
!= INVALID_HANDLE_VALUE
)
501 PathCombineW(conductor
->FileName
, szSearchPath
, findData
.cFileName
);
503 // compare the name of the requested file with the one currently found.
504 // if the name matches, the current node is returned by the function.
505 if (wcscmp(szFirstFile
, conductor
->FileName
) == 0)
507 currentNode
= conductor
;
510 conductor
->Next
= malloc(sizeof(SHIMGVW_FILENODE
));
512 // if malloc fails, make circular what we have and return it
513 if (!conductor
->Next
)
515 DPRINT1("malloc() failed in pLoadFileList()\n");
517 conductor
->Next
= root
;
518 root
->Prev
= conductor
;
520 FindClose(hFindHandle
);
525 conductor
->Next
->Prev
= conductor
;
526 conductor
= conductor
->Next
;
528 while (FindNextFileW(hFindHandle
, &findData
) != 0);
530 FindClose(hFindHandle
);
533 extension
= wcstok(NULL
, L
";");
537 // we now have a node too much in the list. In case the requested file was not found,
538 // we use this node to store the name of it, otherwise we free it.
539 if (currentNode
== NULL
)
541 StringCchCopyW(conductor
->FileName
, MAX_PATH
, szFirstFile
);
542 currentNode
= conductor
;
546 conductor
= conductor
->Prev
;
547 free(conductor
->Next
);
550 // link the last node with the first one to make the list circular
551 conductor
->Next
= root
;
552 root
->Prev
= conductor
;
553 conductor
= currentNode
;
561 pFreeFileList(SHIMGVW_FILENODE
*root
)
563 SHIMGVW_FILENODE
*conductor
;
565 root
->Prev
->Next
= NULL
;
571 root
= conductor
->Next
;
577 ImageView_UpdateWindow(HWND hwnd
)
579 InvalidateRect(hwnd
, NULL
, FALSE
);
583 static HBRUSH
CreateCheckerBoardBrush(HDC hdc
)
585 static const CHAR pattern
[] =
586 "\x28\x00\x00\x00\x10\x00\x00\x00\x10\x00\x00\x00\x01\x00\x04\x00\x00\x00"
587 "\x00\x00\x80\x00\x00\x00\x23\x2E\x00\x00\x23\x2E\x00\x00\x10\x00\x00\x00"
588 "\x00\x00\x00\x00\x99\x99\x99\x00\xCC\xCC\xCC\x00\x00\x00\x00\x00\x00\x00"
589 "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
590 "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
591 "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x11\x11\x11\x11"
592 "\x00\x00\x00\x00\x11\x11\x11\x11\x00\x00\x00\x00\x11\x11\x11\x11\x00\x00"
593 "\x00\x00\x11\x11\x11\x11\x00\x00\x00\x00\x11\x11\x11\x11\x00\x00\x00\x00"
594 "\x11\x11\x11\x11\x00\x00\x00\x00\x11\x11\x11\x11\x00\x00\x00\x00\x11\x11"
595 "\x11\x11\x00\x00\x00\x00\x00\x00\x00\x00\x11\x11\x11\x11\x00\x00\x00\x00"
596 "\x11\x11\x11\x11\x00\x00\x00\x00\x11\x11\x11\x11\x00\x00\x00\x00\x11\x11"
597 "\x11\x11\x00\x00\x00\x00\x11\x11\x11\x11\x00\x00\x00\x00\x11\x11\x11\x11"
598 "\x00\x00\x00\x00\x11\x11\x11\x11\x00\x00\x00\x00\x11\x11\x11\x11";
600 return CreateDIBPatternBrushPt(pattern
, DIB_RGB_COLORS
);
604 ImageView_DrawImage(HWND hwnd
)
606 GpGraphics
*graphics
;
607 UINT ImageWidth
, ImageHeight
;
608 INT ZoomedWidth
, ZoomedHeight
, x
, y
;
616 hdc
= BeginPaint(hwnd
, &ps
);
619 DPRINT1("BeginPaint() failed\n");
623 GdipCreateFromHDC(hdc
, &graphics
);
626 DPRINT1("GdipCreateFromHDC() failed\n");
630 GdipGetImageWidth(image
, &ImageWidth
);
631 GdipGetImageHeight(image
, &ImageHeight
);
633 if (GetClientRect(hwnd
, &rect
))
635 ZoomedWidth
= (ImageWidth
* ZoomPercents
) / 100;
636 ZoomedHeight
= (ImageHeight
* ZoomPercents
) / 100;
638 x
= (rect
.right
- ZoomedWidth
) / 2;
639 y
= (rect
.bottom
- ZoomedHeight
) / 2;
641 white
= GetStockObject(WHITE_BRUSH
);
644 margin
.bottom
= y
- 1;
645 FillRect(hdc
, &margin
, white
);
647 margin
.top
= y
+ ZoomedHeight
+ 1;
648 margin
.bottom
= rect
.bottom
;
649 FillRect(hdc
, &margin
, white
);
652 margin
.bottom
= y
+ ZoomedHeight
+ 1;
653 margin
.right
= x
- 1;
654 FillRect(hdc
, &margin
, white
);
656 margin
.left
= x
+ ZoomedWidth
+ 1;
657 margin
.right
= rect
.right
;
658 FillRect(hdc
, &margin
, white
);
660 DPRINT("x = %d, y = %d, ImageWidth = %u, ImageHeight = %u\n");
661 DPRINT("rect.right = %ld, rect.bottom = %ld\n", rect
.right
, rect
.bottom
);
662 DPRINT("ZoomPercents = %d, ZoomedWidth = %d, ZoomedHeight = %d\n",
663 ZoomPercents
, ZoomedWidth
, ZoomedWidth
);
665 if (ZoomPercents
% 100 == 0)
667 GdipSetInterpolationMode(graphics
, InterpolationModeNearestNeighbor
);
668 GdipSetSmoothingMode(graphics
, SmoothingModeNone
);
672 GdipSetInterpolationMode(graphics
, InterpolationModeHighQualityBilinear
);
673 GdipSetSmoothingMode(graphics
, SmoothingModeHighQuality
);
677 GdipGetImageFlags(image
, &uFlags
);
679 if (uFlags
& (ImageFlagsHasAlpha
| ImageFlagsHasTranslucent
))
681 HBRUSH hbr
= CreateCheckerBoardBrush(hdc
);
682 hbrOld
= SelectObject(hdc
, hbr
);
683 Rectangle(hdc
, x
- 1, y
- 1, x
+ ZoomedWidth
+ 1, y
+ ZoomedHeight
+ 1);
684 SelectObject(hdc
, hbrOld
);
689 hbrOld
= SelectObject(hdc
, GetStockObject(NULL_BRUSH
));
690 Rectangle(hdc
, x
- 1, y
- 1, x
+ ZoomedWidth
+ 1, y
+ ZoomedHeight
+ 1);
691 SelectObject(hdc
, hbrOld
);
694 GdipDrawImageRectI(graphics
, image
, x
, y
, ZoomedWidth
, ZoomedHeight
);
696 GdipDeleteGraphics(graphics
);
701 ImageView_LoadSettings()
706 if (RegOpenKeyEx(HKEY_CURRENT_USER
, _T("Software\\ReactOS\\shimgvw"), 0, KEY_READ
, &hKey
) == ERROR_SUCCESS
)
708 dwSize
= sizeof(SHIMGVW_SETTINGS
);
709 if (RegQueryValueEx(hKey
, _T("Settings"), NULL
, NULL
, (LPBYTE
)&shiSettings
, &dwSize
) == ERROR_SUCCESS
)
722 ImageView_SaveSettings(HWND hwnd
)
727 ShowWindow(hwnd
, SW_HIDE
);
728 wp
.length
= sizeof(WINDOWPLACEMENT
);
729 GetWindowPlacement(hwnd
, &wp
);
731 shiSettings
.Left
= wp
.rcNormalPosition
.left
;
732 shiSettings
.Top
= wp
.rcNormalPosition
.top
;
733 shiSettings
.Right
= wp
.rcNormalPosition
.right
;
734 shiSettings
.Bottom
= wp
.rcNormalPosition
.bottom
;
735 shiSettings
.Maximized
= (IsZoomed(hwnd
) || (wp
.flags
& WPF_RESTORETOMAXIMIZED
));
737 if (RegCreateKeyEx(HKEY_CURRENT_USER
, _T("Software\\ReactOS\\shimgvw"), 0, NULL
,
738 REG_OPTION_NON_VOLATILE
, KEY_WRITE
, NULL
, &hKey
, NULL
) == ERROR_SUCCESS
)
740 RegSetValueEx(hKey
, _T("Settings"), 0, REG_BINARY
, (LPBYTE
)&shiSettings
, sizeof(SHIMGVW_SETTINGS
));
746 ImageView_CreateToolBar(HWND hwnd
)
748 INT numButtons
= sizeof(Buttons
) / sizeof(Buttons
[0]);
750 hToolBar
= CreateWindowEx(0, TOOLBARCLASSNAME
, NULL
,
751 WS_CHILD
| WS_VISIBLE
| TBSTYLE_FLAT
| CCS_BOTTOM
| TBSTYLE_TOOLTIPS
,
756 HIMAGELIST hImageList
;
758 SendMessage(hToolBar
, TB_SETEXTENDEDSTYLE
,
759 0, TBSTYLE_EX_HIDECLIPPEDBUTTONS
);
761 SendMessage(hToolBar
, TB_BUTTONSTRUCTSIZE
,
762 sizeof(Buttons
[0]), 0);
764 hImageList
= ImageList_Create(TB_IMAGE_WIDTH
, TB_IMAGE_HEIGHT
, ILC_MASK
| ILC_COLOR24
, 1, 1);
766 ImageList_AddMasked(hImageList
, LoadImage(hInstance
, MAKEINTRESOURCE(IDB_PREVICON
), IMAGE_BITMAP
,
767 TB_IMAGE_WIDTH
, TB_IMAGE_HEIGHT
, LR_DEFAULTCOLOR
), RGB(255, 255, 255));
769 ImageList_AddMasked(hImageList
, LoadImage(hInstance
, MAKEINTRESOURCE(IDB_NEXTICON
), IMAGE_BITMAP
,
770 TB_IMAGE_WIDTH
, TB_IMAGE_HEIGHT
, LR_DEFAULTCOLOR
), RGB(255, 255, 255));
772 ImageList_AddMasked(hImageList
, LoadImage(hInstance
, MAKEINTRESOURCE(IDB_ZOOMPICON
), IMAGE_BITMAP
,
773 TB_IMAGE_WIDTH
, TB_IMAGE_HEIGHT
, LR_DEFAULTCOLOR
), RGB(255, 255, 255));
775 ImageList_AddMasked(hImageList
, LoadImage(hInstance
, MAKEINTRESOURCE(IDB_ZOOMMICON
), IMAGE_BITMAP
,
776 TB_IMAGE_WIDTH
, TB_IMAGE_HEIGHT
, LR_DEFAULTCOLOR
), RGB(255, 255, 255));
778 ImageList_AddMasked(hImageList
, LoadImage(hInstance
, MAKEINTRESOURCE(IDB_SAVEICON
), IMAGE_BITMAP
,
779 TB_IMAGE_WIDTH
, TB_IMAGE_HEIGHT
, LR_DEFAULTCOLOR
), RGB(255, 255, 255));
781 ImageList_AddMasked(hImageList
, LoadImage(hInstance
, MAKEINTRESOURCE(IDB_PRINTICON
), IMAGE_BITMAP
,
782 TB_IMAGE_WIDTH
, TB_IMAGE_HEIGHT
, LR_DEFAULTCOLOR
), RGB(255, 255, 255));
784 ImageList_AddMasked(hImageList
, LoadImage(hInstance
, MAKEINTRESOURCE(IDB_ROT1ICON
), IMAGE_BITMAP
,
785 TB_IMAGE_WIDTH
, TB_IMAGE_HEIGHT
, LR_DEFAULTCOLOR
), RGB(255, 255, 255));
787 ImageList_AddMasked(hImageList
, LoadImage(hInstance
, MAKEINTRESOURCE(IDB_ROT2ICON
), IMAGE_BITMAP
,
788 TB_IMAGE_WIDTH
, TB_IMAGE_HEIGHT
, LR_DEFAULTCOLOR
), RGB(255, 255, 255));
790 if (hImageList
== NULL
) return FALSE
;
792 ImageList_Destroy((HIMAGELIST
)SendMessage(hToolBar
, TB_SETIMAGELIST
,
793 0, (LPARAM
)hImageList
));
795 SendMessage(hToolBar
, TB_ADDBUTTONS
,
796 numButtons
, (LPARAM
)Buttons
);
804 static void ImageView_OnTimer(HWND hwnd
)
808 KillTimer(hwnd
, ANIME_TIMER_ID
);
809 InvalidateRect(hwnd
, NULL
, FALSE
);
811 if (Anime_Step(&dwDelay
))
813 SetTimer(hwnd
, ANIME_TIMER_ID
, dwDelay
, NULL
);
818 ImageView_DispWndProc(HWND hwnd
, UINT Message
, WPARAM wParam
, LPARAM lParam
)
824 ImageView_DrawImage(hwnd
);
829 if (wParam
== ANIME_TIMER_ID
)
831 ImageView_OnTimer(hwnd
);
837 return CallWindowProc(PrevProc
, hwnd
, Message
, wParam
, lParam
);
841 ImageView_InitControls(HWND hwnd
)
843 MoveWindow(hwnd
, shiSettings
.Left
, shiSettings
.Top
,
844 shiSettings
.Right
- shiSettings
.Left
,
845 shiSettings
.Bottom
- shiSettings
.Top
, TRUE
);
847 if (shiSettings
.Maximized
) ShowWindow(hwnd
, SW_MAXIMIZE
);
849 hDispWnd
= CreateWindowEx(0, WC_STATIC
, _T(""),
850 WS_CHILD
| WS_VISIBLE
,
851 0, 0, 0, 0, hwnd
, NULL
, hInstance
, NULL
);
853 SetClassLongPtr(hDispWnd
, GCL_STYLE
, CS_HREDRAW
| CS_VREDRAW
);
854 PrevProc
= (WNDPROC
) SetWindowLongPtr(hDispWnd
, GWLP_WNDPROC
, (LPARAM
) ImageView_DispWndProc
);
856 ImageView_CreateToolBar(hwnd
);
860 ImageView_OnMouseWheel(HWND hwnd
, INT x
, INT y
, INT zDelta
, UINT fwKeys
)
864 ZoomInOrOut(zDelta
> 0);
869 ImageView_WndProc(HWND hwnd
, UINT Message
, WPARAM wParam
, LPARAM lParam
)
875 ImageView_InitControls(hwnd
);
880 switch (LOWORD(wParam
))
883 PostMessage(hwnd
, WM_COMMAND
, MAKEWPARAM(IDC_PREV
, BN_CLICKED
), (LPARAM
)NULL
);
887 PostMessage(hwnd
, WM_COMMAND
, MAKEWPARAM(IDC_NEXT
, BN_CLICKED
), (LPARAM
)NULL
);
898 currentFile
= currentFile
->Prev
;
899 pLoadImageFromNode(currentFile
, hwnd
);
905 currentFile
= currentFile
->Next
;
906 pLoadImageFromNode(currentFile
, hwnd
);
929 GdipImageRotateFlip(image
, Rotate270FlipNone
);
930 ImageView_UpdateWindow(hwnd
);
936 GdipImageRotateFlip(image
, Rotate90FlipNone
);
937 ImageView_UpdateWindow(hwnd
);
946 ImageView_OnMouseWheel(hwnd
,
947 GET_X_LPARAM(lParam
), GET_Y_LPARAM(lParam
),
948 (SHORT
)HIWORD(wParam
), (UINT
)LOWORD(wParam
));
953 LPNMHDR pnmhdr
= (LPNMHDR
)lParam
;
955 switch (pnmhdr
->code
)
957 case TTN_GETDISPINFO
:
962 lpttt
= (LPTOOLTIPTEXT
)lParam
;
963 idButton
= (UINT
)lpttt
->hdr
.idFrom
;
964 lpttt
->hinst
= hInstance
;
969 lpttt
->lpszText
= MAKEINTRESOURCE(IDS_TOOLTIP_PREV_PIC
);
972 lpttt
->lpszText
= MAKEINTRESOURCE(IDS_TOOLTIP_NEXT_PIC
);
975 lpttt
->lpszText
= MAKEINTRESOURCE(IDS_TOOLTIP_ZOOM_IN
);
978 lpttt
->lpszText
= MAKEINTRESOURCE(IDS_TOOLTIP_ZOOM_OUT
);
981 lpttt
->lpszText
= MAKEINTRESOURCE(IDS_TOOLTIP_SAVEAS
);
984 lpttt
->lpszText
= MAKEINTRESOURCE(IDS_TOOLTIP_PRINT
);
987 lpttt
->lpszText
= MAKEINTRESOURCE(IDS_TOOLTIP_ROT_COUNCW
);
990 lpttt
->lpszText
= MAKEINTRESOURCE(IDS_TOOLTIP_ROT_CLOCKW
);
1000 LPRECT pRect
= (LPRECT
)lParam
;
1001 if (pRect
->right
-pRect
->left
< 350)
1002 pRect
->right
= pRect
->left
+ 350;
1004 if (pRect
->bottom
-pRect
->top
< 290)
1005 pRect
->bottom
= pRect
->top
+ 290;
1011 SendMessage(hToolBar
, TB_AUTOSIZE
, 0, 0);
1012 GetWindowRect(hToolBar
, &rc
);
1013 MoveWindow(hDispWnd
, 1, 1, LOWORD(lParam
) - 1, HIWORD(lParam
) - (rc
.bottom
- rc
.top
) - 1, TRUE
);
1014 /* is it maximized or restored? */
1015 if (wParam
== SIZE_MAXIMIZED
|| wParam
== SIZE_RESTORED
)
1024 ImageView_SaveSettings(hwnd
);
1025 SetWindowLongPtr(hDispWnd
, GWLP_WNDPROC
, (LPARAM
) PrevProc
);
1031 return DefWindowProc(hwnd
, Message
, wParam
, lParam
);
1035 ImageView_CreateWindow(HWND hwnd
, LPWSTR szFileName
)
1037 struct GdiplusStartupInput gdiplusStartupInput
;
1038 ULONG_PTR gdiplusToken
;
1039 WNDCLASS WndClass
= {0};
1041 WCHAR szInitialFile
[MAX_PATH
];
1045 if (!ImageView_LoadSettings())
1047 shiSettings
.Maximized
= FALSE
;
1048 shiSettings
.Left
= 0;
1049 shiSettings
.Top
= 0;
1050 shiSettings
.Right
= 520;
1051 shiSettings
.Bottom
= 400;
1055 gdiplusStartupInput
.GdiplusVersion
= 1;
1056 gdiplusStartupInput
.DebugEventCallback
= NULL
;
1057 gdiplusStartupInput
.SuppressBackgroundThread
= FALSE
;
1058 gdiplusStartupInput
.SuppressExternalCodecs
= FALSE
;
1060 GdiplusStartup(&gdiplusToken
, &gdiplusStartupInput
, NULL
);
1061 pLoadImage(szFileName
);
1063 // Create the window
1064 WndClass
.lpszClassName
= _T("shimgvw_window");
1065 WndClass
.lpfnWndProc
= ImageView_WndProc
;
1066 WndClass
.hInstance
= hInstance
;
1067 WndClass
.style
= CS_HREDRAW
| CS_VREDRAW
;
1068 WndClass
.hIcon
= LoadIcon(hInstance
, MAKEINTRESOURCE(IDI_APPICON
));
1069 WndClass
.hCursor
= LoadCursor(NULL
, IDC_ARROW
);
1070 WndClass
.hbrBackground
= NULL
; /* less flicker */
1072 if (!RegisterClass(&WndClass
)) return -1;
1074 LoadString(hInstance
, IDS_APPTITLE
, szBuf
, sizeof(szBuf
) / sizeof(TCHAR
));
1075 hMainWnd
= CreateWindow(_T("shimgvw_window"), szBuf
,
1076 WS_OVERLAPPEDWINDOW
| WS_VISIBLE
| WS_CAPTION
,
1077 CW_USEDEFAULT
, CW_USEDEFAULT
,
1078 0, 0, NULL
, NULL
, hInstance
, NULL
);
1080 // make sure the path has no quotes on it
1081 wcscpy(szInitialFile
, szFileName
);
1082 PathUnquoteSpacesW(szInitialFile
);
1084 currentFile
= pBuildFileList(szInitialFile
);
1087 pLoadImageFromNode(currentFile
, hMainWnd
);
1091 ShowWindow(hMainWnd
, SW_SHOW
);
1092 UpdateWindow(hMainWnd
);
1095 while(GetMessage(&msg
,NULL
,0,0))
1097 TranslateMessage(&msg
);
1098 DispatchMessageW(&msg
);
1101 pFreeFileList(currentFile
);
1104 GdipDisposeImage(image
);
1108 GdiplusShutdown(gdiplusToken
);
1113 ImageView_FullscreenW(HWND hwnd
, HINSTANCE hInst
, LPCWSTR path
, int nShow
)
1115 ImageView_CreateWindow(hwnd
, (LPWSTR
)path
);
1119 ImageView_Fullscreen(HWND hwnd
, HINSTANCE hInst
, LPCWSTR path
, int nShow
)
1121 ImageView_CreateWindow(hwnd
, (LPWSTR
)path
);
1125 ImageView_FullscreenA(HWND hwnd
, HINSTANCE hInst
, LPCSTR path
, int nShow
)
1127 WCHAR szFile
[MAX_PATH
];
1129 if (MultiByteToWideChar(CP_ACP
, 0, (char*)path
, strlen((char*)path
)+1, szFile
, MAX_PATH
))
1131 ImageView_CreateWindow(hwnd
, (LPWSTR
)szFile
);
1136 ImageView_PrintTo(HWND hwnd
, HINSTANCE hInst
, LPCWSTR path
, int nShow
)
1138 DPRINT("ImageView_PrintTo() not implemented\n");
1142 ImageView_PrintToA(HWND hwnd
, HINSTANCE hInst
, LPCSTR path
, int nShow
)
1144 DPRINT("ImageView_PrintToA() not implemented\n");
1148 ImageView_PrintToW(HWND hwnd
, HINSTANCE hInst
, LPCWSTR path
, int nShow
)
1150 DPRINT("ImageView_PrintToW() not implemented\n");
1154 DllMain(IN HINSTANCE hinstDLL
,
1156 IN LPVOID lpvReserved
)
1160 case DLL_PROCESS_ATTACH
:
1161 case DLL_THREAD_ATTACH
:
1162 hInstance
= hinstDLL
;