https://git.reactos.org/?p=reactos.git;a=commitdiff;h=0fe0b40ee18be504821f2…
commit 0fe0b40ee18be504821f29624987b7df154cb49d
Author: Katayama Hirofumi MZ <katayama.hirofumi.mz(a)gmail.com>
AuthorDate: Sun Dec 10 14:07:46 2023 +0900
Commit: GitHub <noreply(a)github.com>
CommitDate: Sun Dec 10 14:07:46 2023 +0900
[SHIMGVW] Split animation code to anime.c (#6144)
Improve code flexibility.
Add anime.c and move animation code to anime.c.
CORE-19358
---
dll/win32/shimgvw/CMakeLists.txt | 1 +
dll/win32/shimgvw/anime.c | 156 +++++++++++++++++++++++++++++
dll/win32/shimgvw/shimgvw.c | 210 ++++-----------------------------------
dll/win32/shimgvw/shimgvw.h | 59 ++++++++++-
4 files changed, 231 insertions(+), 195 deletions(-)
diff --git a/dll/win32/shimgvw/CMakeLists.txt b/dll/win32/shimgvw/CMakeLists.txt
index 11df2db4098..3c2f5a1f3c3 100644
--- a/dll/win32/shimgvw/CMakeLists.txt
+++ b/dll/win32/shimgvw/CMakeLists.txt
@@ -2,6 +2,7 @@
spec2def(shimgvw.dll shimgvw.spec)
list(APPEND SOURCE
+ anime.c
shimgvw.c
comsup.c
shimgvw.rc
diff --git a/dll/win32/shimgvw/anime.c b/dll/win32/shimgvw/anime.c
new file mode 100644
index 00000000000..485b509675b
--- /dev/null
+++ b/dll/win32/shimgvw/anime.c
@@ -0,0 +1,156 @@
+/*
+ * PROJECT: ReactOS Picture and Fax Viewer
+ * LICENSE: GPL-2.0 (
https://spdx.org/licenses/GPL-2.0)
+ * PURPOSE: Animation of shimgvw.dll
+ * COPYRIGHT: Copyright 2023 Katayama Hirofumi MZ (katayama.hirofumi.mz(a)gmail.com)
+ */
+
+#include "shimgvw.h"
+
+#define ANIME_TIMER_ID 9999
+
+void Anime_FreeInfo(PANIME pAnime)
+{
+ if (pAnime->m_pDelayItem)
+ {
+ free(pAnime->m_pDelayItem);
+ pAnime->m_pDelayItem = NULL;
+ }
+ pAnime->m_nFrameIndex = 0;
+ pAnime->m_nFrameCount = 0;
+ pAnime->m_nLoopIndex = 0;
+ pAnime->m_nLoopCount = (UINT)-1;
+}
+
+void Anime_SetTimerWnd(PANIME pAnime, HWND hwndTimer)
+{
+ pAnime->m_hwndTimer = hwndTimer;
+}
+
+void Anime_Pause(PANIME pAnime)
+{
+ KillTimer(pAnime->m_hwndTimer, ANIME_TIMER_ID);
+}
+
+void Anime_Start(PANIME pAnime, DWORD dwDelay)
+{
+ if (pAnime->m_pDelayItem)
+ SetTimer(pAnime->m_hwndTimer, ANIME_TIMER_ID, dwDelay, NULL);
+}
+
+BOOL Anime_OnTimer(PANIME pAnime, WPARAM wParam)
+{
+ DWORD dwDelay;
+
+ if (wParam != ANIME_TIMER_ID)
+ return FALSE;
+
+ Anime_Pause(pAnime);
+ if (Anime_Step(pAnime, &dwDelay))
+ Anime_Start(pAnime, dwDelay);
+ return TRUE;
+}
+
+BOOL Anime_LoadInfo(PANIME pAnime)
+{
+ UINT nDimCount = 0;
+ UINT cbItem;
+ UINT result;
+
+ Anime_Pause(pAnime);
+ Anime_FreeInfo(pAnime);
+
+ if (!g_pImage)
+ return FALSE;
+
+ GdipImageGetFrameDimensionsCount(g_pImage, &nDimCount);
+ if (nDimCount)
+ {
+ GUID *dims = (GUID *)calloc(nDimCount, sizeof(GUID));
+ if (dims)
+ {
+ GdipImageGetFrameDimensionsList(g_pImage, dims, nDimCount);
+ GdipImageGetFrameCount(g_pImage, dims, &result);
+ pAnime->m_nFrameCount = result;
+ free(dims);
+ }
+ }
+
+ result = 0;
+ GdipGetPropertyItemSize(g_pImage, PropertyTagFrameDelay, &result);
+ cbItem = result;
+ if (cbItem)
+ {
+ pAnime->m_pDelayItem = (PropertyItem *)malloc(cbItem);
+ GdipGetPropertyItem(g_pImage, PropertyTagFrameDelay, cbItem,
pAnime->m_pDelayItem);
+ }
+
+ result = 0;
+ GdipGetPropertyItemSize(g_pImage, PropertyTagLoopCount, &result);
+ cbItem = result;
+ if (cbItem)
+ {
+ PropertyItem *pItem = (PropertyItem *)malloc(cbItem);
+ if (pItem)
+ {
+ if (GdipGetPropertyItem(g_pImage, PropertyTagLoopCount, cbItem, pItem) ==
Ok)
+ {
+ pAnime->m_nLoopCount = *(WORD *)pItem->value;
+ }
+ free(pItem);
+ }
+ }
+
+ Anime_Start(pAnime, 0);
+
+ return pAnime->m_pDelayItem != NULL;
+}
+
+void Anime_SetFrameIndex(PANIME pAnime, UINT nFrameIndex)
+{
+ if (nFrameIndex < pAnime->m_nFrameCount)
+ {
+ GUID guid = FrameDimensionTime;
+ if (Ok != GdipImageSelectActiveFrame(g_pImage, &guid, nFrameIndex))
+ {
+ guid = FrameDimensionPage;
+ GdipImageSelectActiveFrame(g_pImage, &guid, nFrameIndex);
+ }
+ }
+ pAnime->m_nFrameIndex = nFrameIndex;
+}
+
+DWORD Anime_GetFrameDelay(PANIME pAnime, UINT nFrameIndex)
+{
+ if (nFrameIndex < pAnime->m_nFrameCount && pAnime->m_pDelayItem)
+ {
+ return ((DWORD *)pAnime->m_pDelayItem->value)[pAnime->m_nFrameIndex] *
10;
+ }
+ return 0;
+}
+
+BOOL Anime_Step(PANIME pAnime, DWORD *pdwDelay)
+{
+ *pdwDelay = INFINITE;
+ if (pAnime->m_nLoopCount == (UINT)-1)
+ return FALSE;
+
+ if (pAnime->m_nFrameIndex + 1 < pAnime->m_nFrameCount)
+ {
+ *pdwDelay = Anime_GetFrameDelay(pAnime, pAnime->m_nFrameIndex);
+ Anime_SetFrameIndex(pAnime, pAnime->m_nFrameIndex);
+ ++pAnime->m_nFrameIndex;
+ return TRUE;
+ }
+
+ if (pAnime->m_nLoopCount == 0 || pAnime->m_nLoopIndex <
pAnime->m_nLoopCount)
+ {
+ *pdwDelay = Anime_GetFrameDelay(pAnime, pAnime->m_nFrameIndex);
+ Anime_SetFrameIndex(pAnime, pAnime->m_nFrameIndex);
+ pAnime->m_nFrameIndex = 0;
+ ++pAnime->m_nLoopIndex;
+ return TRUE;
+ }
+
+ return FALSE;
+}
diff --git a/dll/win32/shimgvw/shimgvw.c b/dll/win32/shimgvw/shimgvw.c
index 7a73eeaccb3..f8915000893 100644
--- a/dll/win32/shimgvw/shimgvw.c
+++ b/dll/win32/shimgvw/shimgvw.c
@@ -1,37 +1,19 @@
/*
- * PROJECT: ReactOS Picture and Fax Viewer
- * FILE: dll/win32/shimgvw/shimgvw.c
- * PURPOSE: shimgvw.dll
- * PROGRAMMERS: Dmitry Chapyshev (dmitry(a)reactos.org)
- * Katayama Hirofumi MZ (katayama.hirofumi.mz(a)gmail.com)
+ * PROJECT: ReactOS Picture and Fax Viewer
+ * LICENSE: GPL-2.0 (
https://spdx.org/licenses/GPL-2.0)
+ * PURPOSE: Image file browsing and manipulation
+ * COPYRIGHT: Copyright Dmitry Chapyshev (dmitry(a)reactos.org)
+ * Copyright 2018-2023 Katayama Hirofumi MZ
(katayama.hirofumi.mz(a)gmail.com)
*/
-#define WIN32_NO_STATUS
-#define _INC_WINDOWS
-#define COM_NO_WINDOWS_H
-#define INITGUID
-
-#include <windef.h>
-#include <winbase.h>
-#include <winnls.h>
-#include <winreg.h>
-#include <wingdi.h>
-#include <wincon.h>
+#include "shimgvw.h"
#include <windowsx.h>
-#include <objbase.h>
#include <commctrl.h>
#include <commdlg.h>
-#include <gdiplus.h>
#include <shlobj.h>
-#include <strsafe.h>
#include <shlwapi.h>
#include <shellapi.h>
-#define NDEBUG
-#include <debug.h>
-
-#include "shimgvw.h"
-
HINSTANCE g_hInstance;
SHIMGVW_SETTINGS g_Settings;
SHIMGVW_FILENODE *g_pCurrentFile;
@@ -41,6 +23,8 @@ WNDPROC g_fnPrevProc = NULL;
HWND g_hDispWnd = NULL;
HWND g_hToolBar = NULL;
+ANIME g_Anime; /* Animation */
+
/* zooming */
static UINT s_nZoomPercents = 100;
@@ -109,135 +93,6 @@ static const TB_BUTTON_CONFIG s_ButtonConfig[] =
DEFINE_BTN_CONFIG(HELP_TOC)
};
-/* animation */
-UINT m_nFrameIndex = 0;
-UINT m_nFrameCount = 0;
-UINT m_nLoopIndex = 0;
-UINT m_nLoopCount = (UINT)-1;
-PropertyItem *m_pDelayItem = NULL;
-
-#define ANIME_TIMER_ID 9999
-
-static void Anime_FreeInfo(void)
-{
- if (m_pDelayItem)
- {
- free(m_pDelayItem);
- m_pDelayItem = NULL;
- }
- m_nFrameIndex = 0;
- m_nFrameCount = 0;
- m_nLoopIndex = 0;
- m_nLoopCount = (UINT)-1;
-}
-
-static BOOL Anime_LoadInfo(void)
-{
- UINT nDimCount = 0;
- UINT cbItem;
- UINT result;
-
- Anime_FreeInfo();
- KillTimer(g_hDispWnd, ANIME_TIMER_ID);
-
- if (!g_pImage)
- return FALSE;
-
- GdipImageGetFrameDimensionsCount(g_pImage, &nDimCount);
- if (nDimCount)
- {
- GUID *dims = (GUID *)calloc(nDimCount, sizeof(GUID));
- if (dims)
- {
- GdipImageGetFrameDimensionsList(g_pImage, dims, nDimCount);
- GdipImageGetFrameCount(g_pImage, dims, &result);
- m_nFrameCount = result;
- free(dims);
- }
- }
-
- result = 0;
- GdipGetPropertyItemSize(g_pImage, PropertyTagFrameDelay, &result);
- cbItem = result;
- if (cbItem)
- {
- m_pDelayItem = (PropertyItem *)malloc(cbItem);
- GdipGetPropertyItem(g_pImage, PropertyTagFrameDelay, cbItem, m_pDelayItem);
- }
-
- result = 0;
- GdipGetPropertyItemSize(g_pImage, PropertyTagLoopCount, &result);
- cbItem = result;
- if (cbItem)
- {
- PropertyItem *pItem = (PropertyItem *)malloc(cbItem);
- if (pItem)
- {
- if (GdipGetPropertyItem(g_pImage, PropertyTagLoopCount, cbItem, pItem) ==
Ok)
- {
- m_nLoopCount = *(WORD *)pItem->value;
- }
- free(pItem);
- }
- }
-
- if (m_pDelayItem)
- {
- SetTimer(g_hDispWnd, ANIME_TIMER_ID, 0, NULL);
- }
-
- return m_pDelayItem != NULL;
-}
-
-static void Anime_SetFrameIndex(UINT nFrameIndex)
-{
- if (nFrameIndex < m_nFrameCount)
- {
- GUID guid = FrameDimensionTime;
- if (Ok != GdipImageSelectActiveFrame(g_pImage, &guid, nFrameIndex))
- {
- guid = FrameDimensionPage;
- GdipImageSelectActiveFrame(g_pImage, &guid, nFrameIndex);
- }
- }
- m_nFrameIndex = nFrameIndex;
-}
-
-DWORD Anime_GetFrameDelay(UINT nFrameIndex)
-{
- if (nFrameIndex < m_nFrameCount && m_pDelayItem)
- {
- return ((DWORD *)m_pDelayItem->value)[m_nFrameIndex] * 10;
- }
- return 0;
-}
-
-BOOL Anime_Step(DWORD *pdwDelay)
-{
- *pdwDelay = INFINITE;
- if (m_nLoopCount == (UINT)-1)
- return FALSE;
-
- if (m_nFrameIndex + 1 < m_nFrameCount)
- {
- *pdwDelay = Anime_GetFrameDelay(m_nFrameIndex);
- Anime_SetFrameIndex(m_nFrameIndex);
- ++m_nFrameIndex;
- return TRUE;
- }
-
- if (m_nLoopCount == 0 || m_nLoopIndex < m_nLoopCount)
- {
- *pdwDelay = Anime_GetFrameDelay(m_nFrameIndex);
- Anime_SetFrameIndex(m_nFrameIndex);
- m_nFrameIndex = 0;
- ++m_nLoopIndex;
- return TRUE;
- }
-
- return FALSE;
-}
-
static void UpdateZoom(UINT NewZoom, BOOL bEnableBestFit, BOOL bEnableRealSize)
{
BOOL bEnableZoomIn, bEnableZoomOut;
@@ -356,7 +211,8 @@ static void pLoadImage(LPCWSTR szOpenFileName)
DPRINT1("GdipLoadImageFromFile() failed\n");
return;
}
- Anime_LoadInfo();
+
+ Anime_LoadInfo(&g_Anime);
if (szOpenFileName && szOpenFileName[0])
SHAddToRecentDocs(SHARD_PATHW, szOpenFileName);
@@ -447,27 +303,14 @@ static void pSaveImageAs(HWND hwnd)
if (GetSaveFileNameW(&sfn))
{
- if (m_pDelayItem)
- {
- /* save animation */
- KillTimer(g_hDispWnd, ANIME_TIMER_ID);
-
- DPRINT1("FIXME: save animation\n");
- if (GdipSaveImageToFile(g_pImage, szSaveFileName,
&codecInfo[sfn.nFilterIndex - 1].Clsid, NULL) != Ok)
- {
- DPRINT1("GdipSaveImageToFile() failed\n");
- }
+ Anime_Pause(&g_Anime);
- SetTimer(g_hDispWnd, ANIME_TIMER_ID, 0, NULL);
- }
- else
+ if (GdipSaveImageToFile(g_pImage, szSaveFileName, &codecInfo[sfn.nFilterIndex
- 1].Clsid, NULL) != Ok)
{
- /* save non-animation */
- if (GdipSaveImageToFile(g_pImage, szSaveFileName,
&codecInfo[sfn.nFilterIndex - 1].Clsid, NULL) != Ok)
- {
- DPRINT1("GdipSaveImageToFile() failed\n");
- }
+ DPRINT1("GdipSaveImageToFile() failed\n");
}
+
+ Anime_Start(&g_Anime, 0);
}
free(szFilterMask);
@@ -894,19 +737,6 @@ ImageView_CreateToolBar(HWND hwnd)
return FALSE;
}
-static void ImageView_OnTimer(HWND hwnd)
-{
- DWORD dwDelay;
-
- KillTimer(hwnd, ANIME_TIMER_ID);
- InvalidateRect(hwnd, NULL, FALSE);
-
- if (Anime_Step(&dwDelay))
- {
- SetTimer(hwnd, ANIME_TIMER_ID, dwDelay, NULL);
- }
-}
-
LRESULT CALLBACK
ImageView_DispWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
@@ -919,11 +749,8 @@ ImageView_DispWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM
lParam)
}
case WM_TIMER:
{
- if (wParam == ANIME_TIMER_ID)
- {
- ImageView_OnTimer(hwnd);
- return 0;
- }
+ if (Anime_OnTimer(&g_Anime, wParam))
+ InvalidateRect(hwnd, NULL, FALSE);
break;
}
}
@@ -941,6 +768,7 @@ ImageView_InitControls(HWND hwnd)
g_fnPrevProc = (WNDPROC) SetWindowLongPtr(g_hDispWnd, GWLP_WNDPROC, (LPARAM)
ImageView_DispWndProc);
ImageView_CreateToolBar(hwnd);
+ Anime_SetTimerWnd(&g_Anime, g_hDispWnd);
}
static VOID
@@ -1244,7 +1072,7 @@ ImageView_CreateWindow(HWND hwnd, LPCWSTR szFileName)
g_pImage = NULL;
}
- Anime_FreeInfo();
+ Anime_FreeInfo(&g_Anime);
GdiplusShutdown(gdiplusToken);
diff --git a/dll/win32/shimgvw/shimgvw.h b/dll/win32/shimgvw/shimgvw.h
index 76aa255856f..f66118acd7c 100644
--- a/dll/win32/shimgvw/shimgvw.h
+++ b/dll/win32/shimgvw/shimgvw.h
@@ -1,9 +1,39 @@
+/*
+ * PROJECT: ReactOS Picture and Fax Viewer
+ * LICENSE: GPL-2.0 (
https://spdx.org/licenses/GPL-2.0)
+ * PURPOSE: Image file browsing and manipulation
+ * COPYRIGHT: Copyright Dmitry Chapyshev (dmitry(a)reactos.org)
+ * Copyright 2018-2023 Katayama Hirofumi MZ
(katayama.hirofumi.mz(a)gmail.com)
+ */
+
+#pragma once
+
+#define WIN32_NO_STATUS
+#define _INC_WINDOWS
+#define COM_NO_WINDOWS_H
+#define INITGUID
+
+#include <windef.h>
+#include <winbase.h>
+#include <winnls.h>
+#include <winreg.h>
+#include <wingdi.h>
+#include <wincon.h>
+#include <objbase.h>
+#include <gdiplus.h>
+#include <strsafe.h>
+
+#define NDEBUG
+#include <debug.h>
+
#include "resource.h"
#define TB_IMAGE_WIDTH 16
#define TB_IMAGE_HEIGHT 16
-extern HINSTANCE hInstance;
+extern HINSTANCE g_hInstance;
+extern HWND g_hDispWnd;
+extern GpImage *g_pImage;
typedef struct
{
@@ -14,11 +44,32 @@ typedef struct
INT Height;
} SHIMGVW_SETTINGS;
-typedef struct SHIMGVW_FILENODE_INTERNAL
+typedef struct tagSHIMGVW_FILENODE
{
WCHAR FileName[MAX_PATH];
- struct SHIMGVW_FILENODE_INTERNAL *Prev;
- struct SHIMGVW_FILENODE_INTERNAL *Next;
+ struct tagSHIMGVW_FILENODE *Prev;
+ struct tagSHIMGVW_FILENODE *Next;
} SHIMGVW_FILENODE;
#define WC_SHIMGVW L"ShImgVw:CPreviewWnd"
+
+/* Animation */
+typedef struct tagANIME
+{
+ UINT m_nFrameIndex;
+ UINT m_nFrameCount;
+ UINT m_nLoopIndex;
+ UINT m_nLoopCount;
+ PropertyItem *m_pDelayItem;
+ HWND m_hwndTimer;
+} ANIME, *PANIME;
+
+void Anime_FreeInfo(PANIME pAnime);
+BOOL Anime_LoadInfo(PANIME pAnime);
+void Anime_SetTimerWnd(PANIME pAnime, HWND hwndTimer);
+void Anime_SetFrameIndex(PANIME pAnime, UINT nFrameIndex);
+DWORD Anime_GetFrameDelay(PANIME pAnime, UINT nFrameIndex);
+void Anime_Start(PANIME pAnime, DWORD dwDelay);
+void Anime_Pause(PANIME pAnime);
+BOOL Anime_Step(PANIME pAnime, DWORD *pdwDelay);
+BOOL Anime_OnTimer(PANIME pAnime, WPARAM wParam);