https://git.reactos.org/?p=reactos.git;a=commitdiff;h=0fe0b40ee18be504821f29624987b7df154cb49d
commit 0fe0b40ee18be504821f29624987b7df154cb49d Author: Katayama Hirofumi MZ <katayama.hirofumi...@gmail.com> AuthorDate: Sun Dec 10 14:07:46 2023 +0900 Commit: GitHub <nore...@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...@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 (dmi...@reactos.org) - * Katayama Hirofumi MZ (katayama.hirofumi...@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 (dmi...@reactos.org) + * Copyright 2018-2023 Katayama Hirofumi MZ (katayama.hirofumi...@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 (dmi...@reactos.org) + * Copyright 2018-2023 Katayama Hirofumi MZ (katayama.hirofumi...@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);