mirror of
				https://github.com/RetroDECK/ES-DE.git
				synced 2025-04-10 19:15:13 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			521 lines
		
	
	
		
			16 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			521 lines
		
	
	
		
			16 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| // rlottiePlayer.cpp : Defines the entry point for the application.
 | |
| //
 | |
| 
 | |
| 
 | |
| #include "framework.h"
 | |
| #include "rlottiePlayer.h"
 | |
| using namespace Gdiplus;
 | |
| 
 | |
| #define MAX_LOADSTRING 100
 | |
| 
 | |
| // Global Variables:
 | |
| HINSTANCE hInst;                                        // current instance
 | |
| WCHAR szTitle[MAX_LOADSTRING];                  // The title bar text
 | |
| WCHAR szWindowClass[MAX_LOADSTRING];            // the main window class name
 | |
| HWND mainWindow;                                    // Main Window Instance
 | |
| HWND hTextFileToBeOpened;                               // openDialog file path
 | |
| HWND hBtnPlay;
 | |
| HWND hSliderPlay, hSliderCanvasResize;
 | |
| UINT curFrame = 0;
 | |
| RlottieBitmap anim;                                          // rendered Animation Bitmap
 | |
| RECT animRect, backRect;
 | |
| size_t animWidth, animHeight;
 | |
| Gdiplus::Color backColor(255, 255, 255, 255);
 | |
| Gdiplus::Color borderColor(255, 0, 0, 0);
 | |
| bool isViewChanged = false;
 | |
| 
 | |
| // Forward declarations of functions included in this code module:
 | |
| ATOM                MyRegisterClass(HINSTANCE hInstance);
 | |
| BOOL                InitInstance(HINSTANCE, int);
 | |
| LRESULT CALLBACK    WndProc(HWND, UINT, WPARAM, LPARAM);
 | |
| INT_PTR CALLBACK    About(HWND, UINT, WPARAM, LPARAM);
 | |
| void openJSONFileDialog(HWND);
 | |
| void initUIControl(HWND);
 | |
| void dlgUICommand(HWND, WPARAM);
 | |
| void resizeCanvas(HWND, int);
 | |
| void changeBackgroundColor(int r, int g, int b);
 | |
| 
 | |
| // Animation Rendering Functions
 | |
| void draw(HDC);
 | |
| Bitmap* CreateBitmap(void* data, unsigned int width, unsigned int height);
 | |
| void renderAnimation(UINT);
 | |
| 
 | |
| int APIENTRY wWinMain(_In_ HINSTANCE hInstance,
 | |
|     _In_opt_ HINSTANCE hPrevInstance,
 | |
|     _In_ LPWSTR    lpCmdLine,
 | |
|     _In_ int       nCmdShow)
 | |
| {
 | |
|     UNREFERENCED_PARAMETER(hPrevInstance);
 | |
|     UNREFERENCED_PARAMETER(lpCmdLine);
 | |
| 
 | |
|     // initialize Gdiplus
 | |
|     Gdiplus::GdiplusStartupInput gdiplusStartUpInput;
 | |
|     ULONG_PTR gdiplustoken;
 | |
|     Gdiplus::GdiplusStartup(&gdiplustoken, &gdiplusStartUpInput, nullptr);
 | |
| 
 | |
|     // Initialize global strings
 | |
|     LoadStringW(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
 | |
|     LoadStringW(hInstance, IDC_RLOTTIEPLAYER, szWindowClass, MAX_LOADSTRING);
 | |
|     MyRegisterClass(hInstance);
 | |
| 
 | |
|     // Perform application initialization:
 | |
|     if (!InitInstance(hInstance, nCmdShow))
 | |
|     {
 | |
|         return FALSE;
 | |
|     }
 | |
| 
 | |
|     HACCEL hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_RLOTTIEPLAYER));
 | |
| 
 | |
|     MSG msg;
 | |
| 
 | |
|     // Main message loop:
 | |
|     while (GetMessage(&msg, nullptr, 0, 0))
 | |
|     {
 | |
|         if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
 | |
|         {
 | |
|             TranslateMessage(&msg);
 | |
|             DispatchMessage(&msg);
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     Gdiplus::GdiplusShutdown(gdiplustoken);
 | |
|     return (int)msg.wParam;
 | |
| }
 | |
| 
 | |
| 
 | |
| 
 | |
| //
 | |
| //  FUNCTION: MyRegisterClass()
 | |
| //
 | |
| //  PURPOSE: Registers the window class.
 | |
| //
 | |
| ATOM MyRegisterClass(HINSTANCE hInstance)
 | |
| {
 | |
|     WNDCLASSEXW wcex;
 | |
| 
 | |
|     wcex.cbSize = sizeof(WNDCLASSEX);
 | |
| 
 | |
|     wcex.style = CS_HREDRAW | CS_VREDRAW;
 | |
|     wcex.lpfnWndProc = WndProc;
 | |
|     wcex.cbClsExtra = 0;
 | |
|     wcex.cbWndExtra = 0;
 | |
|     wcex.hInstance = hInstance;
 | |
|     wcex.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_RLOTTIEPLAYER));
 | |
|     wcex.hCursor = LoadCursor(nullptr, IDC_ARROW);
 | |
|     wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
 | |
|     wcex.lpszMenuName = MAKEINTRESOURCEW(IDC_RLOTTIEPLAYER);
 | |
|     wcex.lpszClassName = szWindowClass;
 | |
|     wcex.hIconSm = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL));
 | |
| 
 | |
|     return RegisterClassExW(&wcex);
 | |
| }
 | |
| 
 | |
| //
 | |
| //   FUNCTION: InitInstance(HINSTANCE, int)
 | |
| //
 | |
| //   PURPOSE: Saves instance handle and creates main window
 | |
| //
 | |
| //   COMMENTS:
 | |
| //
 | |
| //        In this function, we save the instance handle in a global variable and
 | |
| //        create and display the main program window.
 | |
| //
 | |
| BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
 | |
| {
 | |
|     hInst = hInstance; // Store instance handle in our global variable
 | |
| 
 | |
|     DWORD dwStyle = WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX;
 | |
|     mainWindow = CreateWindowEx(0, szWindowClass, szTitle, dwStyle,
 | |
|         CW_USEDEFAULT, CW_USEDEFAULT, WND_WIDTH, WND_HEIGHT, nullptr, nullptr, hInstance, nullptr);
 | |
| 
 | |
|     if (!mainWindow)
 | |
|     {
 | |
|         return FALSE;
 | |
|     }
 | |
| 
 | |
|     ShowWindow(mainWindow, nCmdShow);
 | |
|     UpdateWindow(mainWindow);
 | |
|     SetMenu(mainWindow, NULL);
 | |
| 
 | |
|     return TRUE;
 | |
| }
 | |
| 
 | |
| //
 | |
| //  FUNCTION: WndProc(HWND, UINT, WPARAM, LPARAM)
 | |
| //
 | |
| //  PURPOSE: Processes messages for the main window.
 | |
| //
 | |
| //  WM_COMMAND  - process the application menu
 | |
| //  WM_PAINT    - Paint the main window
 | |
| //  WM_DESTROY  - post a quit message and return
 | |
| //
 | |
| //
 | |
| LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
 | |
| {
 | |
|     static bool isplay = false;
 | |
|     int wmId = LOWORD(wParam);
 | |
| 
 | |
|     switch (message)
 | |
|     {
 | |
|     case WM_CREATE:
 | |
|     {
 | |
|         initUIControl(hWnd);
 | |
|         break;
 | |
|     }
 | |
|     case WM_TIMER:
 | |
|     {
 | |
|         switch (wmId)
 | |
|         {
 | |
|         case TIMER_PLAY_ANIM:
 | |
|         {
 | |
|             renderAnimation(curFrame + 1);
 | |
|             SendMessage(hSliderPlay, TBM_SETPOS, TRUE, curFrame);
 | |
|             break;
 | |
|         }
 | |
|         default:
 | |
|             break;
 | |
|         }
 | |
|         break;
 | |
|     }
 | |
|     case WM_COMMAND:
 | |
|     {
 | |
|         // Parse the menu selections:
 | |
|         switch (wmId)
 | |
|         {
 | |
|         case IDM_ABOUT:
 | |
|             DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, About);
 | |
|             break;
 | |
| 
 | |
|         case IDM_EXIT:
 | |
|             DestroyWindow(hWnd);
 | |
|             break;
 | |
| 
 | |
|         case BTN_BROWSE:
 | |
|             openJSONFileDialog(hWnd);
 | |
|             break;
 | |
| 
 | |
|         case BTN_PLAY:
 | |
|         {
 | |
|             LPWSTR textBtnPlay;
 | |
|             USES_CONVERSION;
 | |
|             if (isplay)
 | |
|             {
 | |
|                 isplay = false;
 | |
|                 textBtnPlay = A2W("Play");
 | |
|                 KillTimer(hWnd, TIMER_PLAY_ANIM);
 | |
|             }
 | |
|             else
 | |
|             {
 | |
|                 isplay = true;
 | |
|                 textBtnPlay = A2W("Pause");
 | |
|                 SetTimer(hWnd, TIMER_PLAY_ANIM, 10, NULL);
 | |
|             }
 | |
|             SetWindowText(hBtnPlay, textBtnPlay);
 | |
|             break;
 | |
|         }
 | |
| 
 | |
|         case WM_DROPFILES:
 | |
|             break;
 | |
|         case BTN_WHITE:
 | |
|             changeBackgroundColor(1, 1, 1);
 | |
|             break;
 | |
|         case BTN_BLACK:
 | |
|             changeBackgroundColor(0, 0, 0);
 | |
|             break;
 | |
|         case BTN_RED:
 | |
|             changeBackgroundColor(1, 0, 0);
 | |
|             break;
 | |
|         case BTN_GREEN:
 | |
|             changeBackgroundColor(0, 1, 0);
 | |
|             break;
 | |
|         case BTN_BLUE:
 | |
|             changeBackgroundColor(0, 0, 1);
 | |
|             break;
 | |
| 
 | |
|         default:
 | |
|             return DefWindowProc(hWnd, message, wParam, lParam);
 | |
|         }
 | |
|     }
 | |
|     break;
 | |
| 
 | |
|     case WM_HSCROLL:
 | |
|     {
 | |
|         if ((lParam != 0) && (reinterpret_cast<HWND>(lParam) == hSliderPlay))
 | |
|         {
 | |
|             UINT frameNum = SendDlgItemMessage(hWnd, SLIDER_PLAY, TBM_GETPOS, 0, 0);
 | |
|             renderAnimation(frameNum);
 | |
|         }
 | |
|         else if ((lParam != 0) && (reinterpret_cast<HWND>(lParam) == hSliderCanvasResize))
 | |
|         {
 | |
|             static int curSize = anim.width / RESIZE_LENGTH;
 | |
|             int newSize = SendDlgItemMessage(hWnd, SLIDER_CANVAS_RESIZE, TBM_GETPOS, 0, 0);
 | |
|             resizeCanvas(hWnd, (curSize - newSize) * RESIZE_LENGTH);
 | |
|             curSize = newSize;
 | |
|         }
 | |
|         break;
 | |
|     }
 | |
| 
 | |
|     case WM_PAINT:
 | |
|     {
 | |
|         PAINTSTRUCT ps;
 | |
|         HDC hdc = BeginPaint(hWnd, &ps);
 | |
|         draw(hdc);
 | |
|         EndPaint(hWnd, &ps);
 | |
|     }
 | |
|     break;
 | |
|     case WM_CTLCOLORSTATIC:
 | |
|     {
 | |
|         static HBRUSH hBrushEdit = CreateSolidBrush(RGB(255, 255, 255));
 | |
|         return (LRESULT)hBrushEdit;
 | |
|     }
 | |
| 
 | |
|     case WM_DESTROY:
 | |
|         freeAnimation();
 | |
|         PostQuitMessage(0);
 | |
|         break;
 | |
| 
 | |
|     default:
 | |
|         return DefWindowProc(hWnd, message, wParam, lParam);
 | |
|     }
 | |
|     return 0;
 | |
| }
 | |
| 
 | |
| // Message handler for about box.
 | |
| INT_PTR CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
 | |
| {
 | |
|     UNREFERENCED_PARAMETER(lParam);
 | |
|     switch (message)
 | |
|     {
 | |
|     case WM_INITDIALOG:
 | |
|         return (INT_PTR)TRUE;
 | |
| 
 | |
|     case WM_COMMAND:
 | |
|         if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL)
 | |
|         {
 | |
|             EndDialog(hDlg, LOWORD(wParam));
 | |
|             return (INT_PTR)TRUE;
 | |
|         }
 | |
|         break;
 | |
|     }
 | |
|     return (INT_PTR)FALSE;
 | |
| }
 | |
| 
 | |
| void openJSONFileDialog(HWND hDlg)
 | |
| {
 | |
|     OPENFILENAME ofn;       // common dialog box structure
 | |
|     TCHAR szFile[260] = { 0 };       // if using TCHAR macros
 | |
| 
 | |
|     // Initialize OPENFILENAME
 | |
|     ZeroMemory(&ofn, sizeof(ofn));
 | |
|     ofn.lStructSize = sizeof(ofn);
 | |
|     ofn.hwndOwner = hDlg;
 | |
|     ofn.lpstrFile = szFile;
 | |
|     ofn.nMaxFile = sizeof(szFile);
 | |
|     ofn.lpstrFilter = _T("JSON\0*.json\0");
 | |
|     ofn.nFilterIndex = 1;
 | |
|     ofn.lpstrFileTitle = NULL;
 | |
|     ofn.nMaxFileTitle = 0;
 | |
|     ofn.lpstrInitialDir = NULL;
 | |
|     ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST;
 | |
| 
 | |
|     isViewChanged = true;
 | |
|     if (GetOpenFileName(&ofn))
 | |
|     {
 | |
|         isViewChanged = true;
 | |
|         SetWindowText(hTextFileToBeOpened, ofn.lpstrFile);
 | |
|         // LPWSTR(w_char*) -> LPSTR(char*)
 | |
|         USES_CONVERSION;
 | |
|         LPSTR path = W2A(ofn.lpstrFile);
 | |
| 
 | |
|         setAnimation(path, &animWidth, &animHeight);
 | |
|         // init play slider
 | |
|         SendMessage(hSliderPlay, TBM_SETRANGE, FALSE, MAKELPARAM(0, getTotalFrame()));
 | |
|         SendMessage(hSliderPlay, TBM_SETPOS, TRUE, 0);
 | |
|         renderAnimation(0);
 | |
|     }
 | |
| }
 | |
| 
 | |
| void draw(HDC hdc)
 | |
| {
 | |
|     Graphics gf(hdc);
 | |
|     int half_interval = UI_INTERVAL / 2;
 | |
| 
 | |
|     // background
 | |
|     SolidBrush brush(backColor);
 | |
|     int back_y = half_interval + BTN_HEIGHT;
 | |
|     int back_height = back_y + BMP_MAX_LEN + UI_INTERVAL;
 | |
|     if (isViewChanged)
 | |
|     {
 | |
|         isViewChanged = false;
 | |
|         gf.FillRectangle(&brush, 0, back_y, WND_WIDTH, back_height);
 | |
|     }
 | |
| 
 | |
|     // image borderline
 | |
|     Pen pen(borderColor);
 | |
|     gf.DrawRectangle(&pen, anim.x - half_interval, anim.y - half_interval, anim.width + half_interval * 2, anim.height + half_interval * 2);
 | |
| 
 | |
|     // image
 | |
|     if (anim.image != NULL)
 | |
|     {
 | |
|         gf.DrawImage(anim.image, anim.x, anim.y, anim.width, anim.height);
 | |
|     }
 | |
| }
 | |
| 
 | |
| Bitmap* CreateBitmap(void* data, unsigned int width, unsigned int height)
 | |
| {
 | |
|     BITMAPINFO Info;
 | |
|     memset(&Info, 0, sizeof(Info));
 | |
| 
 | |
|     Info.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
 | |
|     Info.bmiHeader.biWidth = width;
 | |
|     Info.bmiHeader.biHeight = height;
 | |
|     Info.bmiHeader.biPlanes = 1;
 | |
|     Info.bmiHeader.biBitCount = 32;
 | |
|     Info.bmiHeader.biCompression = BI_RGB;
 | |
|     Info.bmiHeader.biSizeImage = 0;  //(((32 * width + 31) & ~31) / 8) * height;
 | |
| 
 | |
|     return new Gdiplus::Bitmap(&Info, data);
 | |
| }
 | |
| 
 | |
| void renderAnimation(UINT frameNum)
 | |
| {
 | |
|     if (isAnimNULL()) return;
 | |
|     if (anim.image != NULL) delete anim.image;
 | |
| 
 | |
|     curFrame = frameNum % getTotalFrame();
 | |
| 
 | |
|     // render
 | |
|     UINT* resRender = renderRLottieAnimation(curFrame);
 | |
|     anim.image = CreateBitmap(resRender, animWidth, animHeight);
 | |
|     anim.image->RotateFlip(RotateNoneFlipY);
 | |
|     // call WM_PAINT message
 | |
|     InvalidateRect(mainWindow, &animRect, FALSE);
 | |
| }
 | |
| 
 | |
| void initUIControl(HWND hWnd)
 | |
| {
 | |
|     int half_ui_interval = UI_INTERVAL / 2;
 | |
| 
 | |
|     // button browse
 | |
|     int browse_x = UI_INTERVAL;
 | |
|     int browse_y = half_ui_interval;
 | |
|     CreateWindow(L"button", L"Browse", WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON,
 | |
|         browse_x, browse_y, BTN_WIDTH, BTN_HEIGHT, hWnd, (HMENU)BTN_BROWSE, hInst, NULL);
 | |
| 
 | |
|     // textbox FilePath
 | |
|     int textFile_x = browse_x + BTN_WIDTH + UI_INTERVAL;
 | |
|     int textFile_y = browse_y;
 | |
|     hTextFileToBeOpened = CreateWindowEx(0, L"static", L"No file selected.", WS_CHILD | WS_VISIBLE | ES_LEFT,
 | |
|         textFile_x, textFile_y, WND_WIDTH * 0.6, TEXT_HEIGHT, hWnd, (HMENU)TEXT_FILENAME, hInst, 0);
 | |
| 
 | |
|     // image
 | |
|     anim.x = WND_WIDTH / 4;
 | |
|     anim.y = browse_y + BTN_HEIGHT + UI_INTERVAL * 2;
 | |
|     anim.width = BMP_MAX_LEN;
 | |
|     anim.height = anim.width;
 | |
| 
 | |
|     // animating range
 | |
|     SetRect(&animRect, 
 | |
|         anim.x - UI_INTERVAL, 
 | |
|         anim.y - UI_INTERVAL,
 | |
|         anim.x + anim.width + UI_INTERVAL * 2,
 | |
|         anim.y + anim.height + UI_INTERVAL * 2
 | |
|     );
 | |
| 
 | |
|     // background range
 | |
|     SetRect(&backRect,
 | |
|         0,
 | |
|         anim.y - UI_INTERVAL,
 | |
|         WND_WIDTH,
 | |
|         anim.y + anim.height + UI_INTERVAL * 2
 | |
|     );
 | |
| 
 | |
|     // text Background Color
 | |
|     int textBC_x = WND_WIDTH / 20;
 | |
|     int textBC_y = anim.y + anim.height + UI_INTERVAL * 2;
 | |
|     CreateWindowEx(0, L"static", L"Background Color", WS_CHILD | WS_VISIBLE | ES_LEFT,
 | |
|         textBC_x, textBC_y, 120, TEXT_HEIGHT, hWnd, (HMENU)TEXT_FILENAME, hInst, 0);
 | |
| 
 | |
|     // radio button
 | |
|     // white
 | |
|     int white_x = WND_WIDTH / 20;
 | |
|     int white_y = textBC_y + TEXT_HEIGHT + half_ui_interval;
 | |
|     CreateWindowEx(0, L"button", L"White", WS_VISIBLE | WS_CHILD | BS_AUTORADIOBUTTON,
 | |
|         white_x, white_y, RDOBTN_WIDTH, RDOBTN_HEIGHT, hWnd, (HMENU)BTN_WHITE, hInst, NULL);
 | |
| 
 | |
|     // black
 | |
|     int black_x = white_x + RDOBTN_WIDTH + half_ui_interval;
 | |
|     int black_y = white_y;
 | |
|     CreateWindowEx(0, L"button", L"Black", WS_VISIBLE | WS_CHILD | BS_AUTORADIOBUTTON,
 | |
|         black_x, black_y, RDOBTN_WIDTH, RDOBTN_HEIGHT, hWnd, (HMENU)BTN_BLACK, hInst, NULL);
 | |
| 
 | |
|     // red
 | |
|     int red_x = black_x + RDOBTN_WIDTH + half_ui_interval;
 | |
|     int red_y = white_y;
 | |
|     CreateWindowEx(0, L"button", L"Red", WS_VISIBLE | WS_CHILD | BS_AUTORADIOBUTTON,
 | |
|         red_x, red_y, RDOBTN_WIDTH, RDOBTN_HEIGHT, hWnd, (HMENU)BTN_RED, hInst, NULL);
 | |
| 
 | |
|     // green
 | |
|     int green_x = red_x + RDOBTN_WIDTH + half_ui_interval;
 | |
|     int green_y = white_y;
 | |
|     CreateWindowEx(0, L"button", L"Green", WS_VISIBLE | WS_CHILD | BS_AUTORADIOBUTTON,
 | |
|         green_x, green_y, RDOBTN_WIDTH, RDOBTN_HEIGHT, hWnd, (HMENU)BTN_GREEN, hInst, NULL);
 | |
| 
 | |
|     // blue
 | |
|     int blue_x = green_x + RDOBTN_WIDTH + half_ui_interval;
 | |
|     int blue_y = white_y;
 | |
|     CreateWindowEx(0, L"button", L"Blue", WS_VISIBLE | WS_CHILD | BS_AUTORADIOBUTTON,
 | |
|         blue_x, blue_y, RDOBTN_WIDTH, RDOBTN_HEIGHT, hWnd, (HMENU)BTN_BLUE, hInst, NULL);
 | |
| 
 | |
|     CheckRadioButton(hWnd, BTN_WHITE, BTN_BLUE, BTN_WHITE);
 | |
| 
 | |
|     // text Canvas Resize
 | |
|     int textCR_x = WND_WIDTH / 2;
 | |
|     int textCR_y = textBC_y;
 | |
|     CreateWindowEx(0, L"static", L"Canvas Resize", WS_CHILD | WS_VISIBLE | ES_LEFT,
 | |
|         textCR_x, textCR_y, 120, TEXT_HEIGHT, hWnd, (HMENU)TEXT_FILENAME, hInst, 0);
 | |
| 
 | |
|     // slider Canvas Resize
 | |
|     int sliderCR_x = textCR_x;
 | |
|     int sliderCR_y = textCR_y + TEXT_HEIGHT + half_ui_interval;
 | |
|     hSliderCanvasResize = CreateWindowExW(0, TRACKBAR_CLASSW, NULL, WS_CHILD | WS_VISIBLE | TBS_FIXEDLENGTH | TBS_NOTICKS,
 | |
|         sliderCR_x, sliderCR_y, WND_WIDTH * 0.2, SLIDER_HEIGHT, hWnd, (HMENU)SLIDER_CANVAS_RESIZE, hInst, NULL);
 | |
| 
 | |
|     // init resize slider
 | |
|     UINT sizeSlider = anim.width / RESIZE_LENGTH;
 | |
|     SendMessage(hSliderCanvasResize, TBM_SETRANGE, FALSE, MAKELPARAM(0, sizeSlider));
 | |
|     SendMessage(hSliderCanvasResize, TBM_SETPOS, TRUE, sizeSlider);
 | |
| 
 | |
|     // button play
 | |
|     int btnPlay_x = WND_WIDTH / 10;
 | |
|     int btnPlay_y = red_y + RDOBTN_HEIGHT + UI_INTERVAL * 2;
 | |
|     hBtnPlay = CreateWindow(L"button", L"Play", WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON,
 | |
|         btnPlay_x, btnPlay_y, BTN_WIDTH, BTN_HEIGHT, hWnd, (HMENU)BTN_PLAY, hInst, NULL);
 | |
| 
 | |
|     // slider play
 | |
|     int sliderPlay_x = btnPlay_x + BTN_WIDTH + UI_INTERVAL;
 | |
|     int sliderPlay_y = btnPlay_y;
 | |
|     hSliderPlay = CreateWindowExW(0, TRACKBAR_CLASSW, NULL, WS_CHILD | WS_VISIBLE | TBS_FIXEDLENGTH | TBS_NOTICKS,
 | |
|         sliderPlay_x, sliderPlay_y, WND_WIDTH * 0.6, SLIDER_HEIGHT, hWnd, (HMENU)SLIDER_PLAY, hInst, NULL);
 | |
| }
 | |
| 
 | |
| void resizeCanvas(HWND hWnd, int resizeValue)
 | |
| {
 | |
|     isViewChanged = true;
 | |
|     anim.x += resizeValue / 2;
 | |
|     anim.y += resizeValue / 2;
 | |
|     anim.width -= resizeValue;
 | |
|     anim.height -= resizeValue;
 | |
|     InvalidateRect(hWnd, &animRect, TRUE);
 | |
| }
 | |
| 
 | |
| void changeBackgroundColor(int r, int g, int b)
 | |
| {
 | |
|     isViewChanged = true;
 | |
|     backColor = Gdiplus::Color(r * 255, g * 255, b * 255);
 | |
|     if (r + g + b == 0) borderColor = Gdiplus::Color(255, 255, 255);
 | |
|     else borderColor = Gdiplus::Color(0, 0, 0);
 | |
|     setAnimationColor(r, g, b);
 | |
|     renderAnimation(curFrame);
 | |
|     InvalidateRect(mainWindow, &backRect, FALSE);
 | |
| } | 
