clay/examples/win32_gdi/main.c
Philosoph228 d9c68cd32d
Fix CreateWindow client size
CreateWindow(Ex) size parameters actually accepts outer window dimensions containing caption and border, which we can calculate with AdjustWindowRect by giving client size window dimensions.
2025-03-24 03:21:19 +05:00

226 lines
6.0 KiB
C

#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <windowsx.h>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include "../../renderers/win32_gdi/clay_renderer_gdi.c"
#define CLAY_IMPLEMENTATION
#include "../../clay.h"
#include "../shared-layouts/clay-video-demo.c"
ClayVideoDemo_Data demo_data;
#define APPNAME "Clay GDI Example"
char szAppName[] = APPNAME; // The name of this application
char szTitle[] = APPNAME; // The title bar text
void CenterWindow(HWND hWnd);
long lastMsgTime = 0;
bool ui_debug_mode;
#define RECTWIDTH(rc) ((rc).right - (rc).left)
#define RECTHEIGHT(rc) ((rc).bottom - (rc).top)
LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
// ----------------------- first and last
case WM_CREATE:
CenterWindow(hwnd);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
case WM_MOUSEWHEEL: // scrolling data
{
short zDelta = GET_WHEEL_DELTA_WPARAM(wParam);
// todo: i think GetMessageTime can roll over, so something like if(lastmsgtime > now) ... may be needed
long now = GetMessageTime();
float dt = (now - lastMsgTime) / 1000.00;
lastMsgTime = now;
// little hacky hack to make scrolling *feel* right
if (abs(zDelta) > 100)
{
zDelta = zDelta * .012;
}
Clay_UpdateScrollContainers(true, (Clay_Vector2){.x = 0, .y = zDelta}, dt);
InvalidateRect(hwnd, NULL, false); // force a wm_paint event
break;
}
case WM_RBUTTONUP:
case WM_LBUTTONUP:
case WM_LBUTTONDOWN:
case WM_RBUTTONDOWN:
case WM_MOUSEMOVE: // mouse events
{
short mouseX = GET_X_LPARAM(lParam);
short mouseY = GET_Y_LPARAM(lParam);
short mouseButtons = LOWORD(wParam);
Clay_SetPointerState((Clay_Vector2){mouseX, mouseY}, mouseButtons & 0b01);
InvalidateRect(hwnd, NULL, false); // force a wm_paint event
break;
}
case WM_SIZE: // resize events
{
RECT r = {0};
if (GetClientRect(hwnd, &r))
{
Clay_Dimensions dim = (Clay_Dimensions){.height = r.bottom - r.top, .width = r.right - r.left};
Clay_SetLayoutDimensions(dim);
}
InvalidateRect(hwnd, NULL, false); // force a wm_paint event
break;
}
case WM_KEYDOWN:
if (VK_ESCAPE == wParam)
{
DestroyWindow(hwnd);
break;
}
if (wParam == VK_F12)
{
Clay_SetDebugModeEnabled(ui_debug_mode = !ui_debug_mode);
break;
}
printf("Key Pressed: %d\r\n", wParam);
InvalidateRect(hwnd, NULL, false); // force a wm_paint event
break;
// ----------------------- render
case WM_PAINT:
{
Clay_RenderCommandArray renderCommands = ClayVideoDemo_CreateLayout(&demo_data);
Clay_Win32_Render(hwnd, renderCommands);
break;
}
// ----------------------- let windows do all other stuff
default:
return DefWindowProc(hwnd, message, wParam, lParam);
}
return 0;
}
bool didAllocConsole = false;
void HandleClayErrors(Clay_ErrorData errorData)
{
if (!didAllocConsole)
{
didAllocConsole = AllocConsole();
}
printf("Handle Clay Errors: %s\r\n", errorData.errorText.chars);
}
int APIENTRY WinMain(
HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow)
{
MSG msg;
WNDCLASS wc;
HWND hwnd;
demo_data = ClayVideoDemo_Initialize();
uint64_t clayRequiredMemory = Clay_MinMemorySize();
Clay_Arena clayMemory = Clay_CreateArenaWithCapacityAndMemory(clayRequiredMemory, malloc(clayRequiredMemory));
Clay_Initialize(clayMemory, (Clay_Dimensions){.width = 800, .height = 600}, (Clay_ErrorHandler){HandleClayErrors}); // This final argument is new since the video was published
Clay_SetMeasureTextFunction(Clay_Win32_MeasureText, NULL);
ZeroMemory(&wc, sizeof wc);
wc.hInstance = hInstance;
wc.lpszClassName = szAppName;
wc.lpfnWndProc = (WNDPROC)WndProc;
wc.style = CS_DBLCLKS | CS_VREDRAW | CS_HREDRAW;
wc.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
if (FALSE == RegisterClass(&wc))
return 0;
// Calculate window rectangle by given client size
// TODO: AdjustWindowRectExForDpi for DPI support
RECT rcWindow = { .right = 800, .bottom = 600 };
AdjustWindowRect(&rcWindow, WS_OVERLAPPEDWINDOW, FALSE);
hwnd = CreateWindow(
szAppName,
szTitle,
WS_OVERLAPPEDWINDOW | WS_VISIBLE,
CW_USEDEFAULT,
CW_USEDEFAULT,
RECTWIDTH(rcWindow), // CW_USEDEFAULT,
RECTHEIGHT(rcWindow), // CW_USEDEFAULT,
0,
0,
hInstance,
0);
if (hwnd == NULL)
return 0;
// Main message loop:
while (GetMessage(&msg, NULL, 0, 0) > 0)
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return msg.wParam;
}
void CenterWindow(HWND hwnd_self)
{
HWND hwnd_parent;
RECT rw_self, rc_parent, rw_parent;
int xpos, ypos;
hwnd_parent = GetParent(hwnd_self);
if (NULL == hwnd_parent)
hwnd_parent = GetDesktopWindow();
GetWindowRect(hwnd_parent, &rw_parent);
GetClientRect(hwnd_parent, &rc_parent);
GetWindowRect(hwnd_self, &rw_self);
xpos = rw_parent.left + (rc_parent.right + rw_self.left - rw_self.right) / 2;
ypos = rw_parent.top + (rc_parent.bottom + rw_self.top - rw_self.bottom) / 2;
SetWindowPos(
hwnd_self, NULL,
xpos, ypos, 0, 0,
SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
}
//+---------------------------------------------------------------------------