mirror of
https://github.com/reactos/reactos.git
synced 2025-05-03 12:50:05 +00:00
[SHIMGVW] Split animation code to anime.c (#6144)
Improve code flexibility. Add anime.c and move animation code to anime.c. CORE-19358
This commit is contained in:
parent
5a2c451696
commit
0fe0b40ee1
4 changed files with 231 additions and 195 deletions
|
@ -2,6 +2,7 @@
|
|||
spec2def(shimgvw.dll shimgvw.spec)
|
||||
|
||||
list(APPEND SOURCE
|
||||
anime.c
|
||||
shimgvw.c
|
||||
comsup.c
|
||||
shimgvw.rc
|
||||
|
|
156
dll/win32/shimgvw/anime.c
Normal file
156
dll/win32/shimgvw/anime.c
Normal file
|
@ -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@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;
|
||||
}
|
|
@ -1,37 +1,19 @@
|
|||
/*
|
||||
* PROJECT: ReactOS Picture and Fax Viewer
|
||||
* FILE: dll/win32/shimgvw/shimgvw.c
|
||||
* PURPOSE: shimgvw.dll
|
||||
* PROGRAMMERS: Dmitry Chapyshev (dmitry@reactos.org)
|
||||
* Katayama Hirofumi MZ (katayama.hirofumi.mz@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@reactos.org)
|
||||
* Copyright 2018-2023 Katayama Hirofumi MZ (katayama.hirofumi.mz@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);
|
||||
Anime_Pause(&g_Anime);
|
||||
|
||||
DPRINT1("FIXME: save animation\n");
|
||||
if (GdipSaveImageToFile(g_pImage, szSaveFileName, &codecInfo[sfn.nFilterIndex - 1].Clsid, NULL) != Ok)
|
||||
{
|
||||
DPRINT1("GdipSaveImageToFile() failed\n");
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
|
|
|
@ -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@reactos.org)
|
||||
* Copyright 2018-2023 Katayama Hirofumi MZ (katayama.hirofumi.mz@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);
|
||||
|
|
Loading…
Reference in a new issue