Converted from C++ to C

WARNING: Is currently not working! Needs more debugging.
This commit is contained in:
Ludwig Füchsl 2022-02-28 14:57:47 +01:00
parent d4e695420d
commit 169470d2e3
3 changed files with 183 additions and 200 deletions

View File

@ -3,4 +3,4 @@
rem This will use VS2015 for compiler
call "C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat" x86
cl /nologo /W3 /O2 /fp:fast /Gm- /D_CRT_SECURE_NO_DEPRECATE /Fedemo.exe main.cpp user32.lib gdi32.lib Msimg32.lib /link /incremental:no
cl /nologo /W3 /O2 /fp:fast /Gm- /D_CRT_SECURE_NO_DEPRECATE /Fedemo.exe main.c user32.lib gdi32.lib Msimg32.lib /link /incremental:no

View File

@ -1,5 +1,4 @@
#include <Windows.h>
#include <iostream>
#pragma comment(linker,"\"/manifestdependency:type='win32' \
name='Microsoft.Windows.Common-Controls' version='6.0.0.0' \
@ -19,19 +18,21 @@ processorArchitecture='*' publicKeyToken='6595b64144ccf1df' language='*'\"")
INT WINAPI wWinMain(HINSTANCE _In_ hInstance, HINSTANCE _In_opt_ hPrevInstance, PWSTR _In_ cmdArgs, INT _In_ cmdShow)
{
NkGdi::Window w1(500, 500, "F1", 10, 10);
w1.AllowSizing = false;
w1.AllowMaximize = false;
w1.AllowMove = false;
w1.HasTitlebar = false;
struct nkgdi_window w1, w2;
NkGdi::Window w2(500, 500, "F2", 520, 10);
w2.AllowSizing = true;
w2.AllowMaximize = true;
w2.AllowMove = true;
w2.HasTitlebar = true;
w1.allow_sizing = 0;
w1.allow_maximize = 0;
w1.allow_move = 0;
w1.has_titlebar = 0;
nkgdi_window_create(&w1, 500, 500, "F1", 10, 10);
w2.allow_sizing = 1;
w2.allow_maximize = 1;
w2.allow_move = 1;
w2.has_titlebar = 1;
nkgdi_window_create(&w2, 500, 500, "F2", 520, 10);
while (w1.Update() && w2.Update()) Sleep(20);
while (nkgdi_window_update(&w1) && nkgdi_window_update(&w2)) Sleep(20);
return 0;
}

View File

@ -1,117 +1,93 @@
#pragma once
#ifndef NK_GDI_WINDOW
#define NK_GDI_WINDOW
namespace NkGdi
#define NK_GDI_WINDOW_CLS L"WNDCLS_NkGdi"
#include <Windows.h>
/* Functin pointer types for window callbacks */
typedef void(*nkgdi_window_func_update)(void);
typedef int(*nkgdi_window_func_close)(void);
typedef int(*nkgdi_window_func_draw)(struct nk_context*);
/* Window container / context */
struct nkgdi_window
{
// Container for window management
class WindowClass
/* Properties */
int allow_sizing;
int allow_maximize;
int allow_move;
int has_titlebar;
/* Callbacks */
nkgdi_window_func_update cb_on_update;
nkgdi_window_func_close cb_on_close;
nkgdi_window_func_draw cb_on_draw;
/* Internal Data */
struct
{
public:
// Public exposed name
static const wchar_t* const ClassName;
// Window handle
HWND window_handle;
WindowClass(const WindowClass&) = delete;
private:
// Instance
static WindowClass ClassInstance;
// Nuklear context
nk_gdi_ctx nk_gdi_ctx;
struct nk_context* nk_ctx;
// Sigelton
WindowClass();
};
// Nuklear objects
GdiFont* gdi_font;
HDC window_dc;
// Window base class
class Window
{
friend class WindowClass;
// Window runtime features
int is_open;
int is_draggin;
int ws_override;
int is_maximized;
POINT drag_offset;
int width;
int height;
}_internal;
};
public:
// Default constructs
Window() = default;
Window(const Window&) = delete;
Window(Window&&) = default;
// Constructor
Window(unsigned int width, unsigned int height, const char* name, int posX = 100, int posY = 100);
// Destructor
~Window();
// Processs window events and render the window (returns true as long as window is open)
bool Update();
// Properties
bool AllowSizing = true;
bool AllowMaximize = true;
bool AllowMove = true;
bool HasTitlebar = true;
public:
// Called when the core window gets an event
virtual LRESULT OnWindowMessage(HWND wnd, UINT msg, WPARAM wParam, LPARAM lParam);
// Called when the window is created
inline virtual void OnCreate() {};
// Called when the window is destroyed
inline virtual void OnDestroy() {};
// Called when the windows is beein updated (before events are served)
inline virtual void OnUpdate() {};
// Called when the window is beeing closed by the user (return false to abort)
inline virtual bool OnClose() { return true; };
// Called when nuklear drawcalls can be issued (return false to close the window)
inline virtual bool OnDraw(nk_context* ctx) { return true; };
private:
// Static window procs
static LRESULT wndProcSetup(HWND wnd, UINT msg, WPARAM wParam, LPARAM lParam);
static LRESULT wndProcRun(HWND wnd, UINT msg, WPARAM wParam, LPARAM lParam);
private:
// Window handle
HWND m_window = NULL;
// Nuklear context
nk_gdi_ctx m_nkGdiCtx = nullptr;
nk_context* m_nkCtx = nullptr;
// Nuklear objects
GdiFont* m_gdiFont = nullptr;
HDC m_windowDc = NULL;
// Window runtime features
bool m_isOpen = true;
bool m_isDraggin = false;
bool m_wsOverride = false;
bool m_isMaximized = false;
POINT m_dragOffset = {};
int m_width = 0;
int m_height = 0;
};
}
/* API */
void nkgdi_window_init(void);
void nkgdi_window_shutdown(void);
void nkgdi_window_create(struct nkgdi_window* wnd, unsigned int width, unsigned int height, const char* name, int posX, int posY);
int nkgdi_window_update(struct nkgdi_window* wnd);
void nkgdi_window_destroy(struct nkgdi_window* wnd);
#ifdef NKGDI_IMPLEMENT_WINDOW
const wchar_t* const NkGdi::WindowClass::ClassName = L"WNDCLS_NkGdi";
NkGdi::WindowClass NkGdi::WindowClass::ClassInstance;
LRESULT nkgdi_window_proc_setup(HWND wnd, UINT msg, WPARAM wParam, LPARAM lParam);
LRESULT nkgdi_window_proc_run(HWND wnd, UINT msg, WPARAM wParam, LPARAM lParam);
NkGdi::WindowClass::WindowClass()
void nkgdi_window_init(void)
{
// Describe class
WNDCLASSEXW cls;
cls.cbSize = sizeof(WNDCLASSEXW);
cls.style = CS_OWNDC | CS_DBLCLKS;
cls.lpfnWndProc = &Window::wndProcSetup;
cls.lpfnWndProc = &nkgdi_window_proc_setup;
cls.cbClsExtra = 0;
cls.cbWndExtra = 0;
cls.hInstance = GetModuleHandle(NULL);
cls.hIcon = LoadIcon(NULL, IDI_APPLICATION);
cls.hCursor = LoadCursor(NULL, IDC_ARROW);
cls.hbrBackground = NULL;
cls.lpszMenuName = nullptr;
cls.lpszClassName = ClassName;
cls.lpszMenuName = NULL;
cls.lpszClassName = NK_GDI_WINDOW_CLS;
cls.hIconSm = NULL;
// Register class
RegisterClassExW(&cls);
}
NkGdi::Window::Window(unsigned int width, unsigned int height, const char* name, int posX, int posY)
void nkgdi_window_shutdown(void)
{
UnregisterClassW(NK_GDI_WINDOW_CLS, GetModuleHandle(NULL));
}
void nkgdi_window_create(struct nkgdi_window* wnd, unsigned int width, unsigned int height, const char* name, int posX, int posY)
{
DWORD styleEx = WS_EX_WINDOWEDGE;
DWORD style = WS_POPUP;
@ -125,121 +101,155 @@ NkGdi::Window::Window(unsigned int width, unsigned int height, const char* name,
AdjustWindowRectEx(&cr, style, FALSE, styleEx);
// Create the window
m_window = CreateWindowExW(
wnd->_internal.window_handle = CreateWindowExW(
styleEx,
WindowClass::ClassName,
NK_GDI_WINDOW_CLS,
L"NkGdi",
style | WS_VISIBLE,
posX, posY,
cr.right - cr.left, cr.bottom - cr.top,
NULL, NULL,
GetModuleHandleW(nullptr),
this
GetModuleHandleW(NULL),
wnd
);
// Rename window to user picked name
SetWindowTextA(m_window, name);
SetWindowTextA(wnd->_internal.window_handle, name);
// Get DC
m_windowDc = GetWindowDC(m_window);
wnd->_internal.window_dc = GetWindowDC(wnd->_internal.window_handle);
// Create font
m_gdiFont = nk_gdifont_create("Arial", 16);
m_nkCtx = nk_gdi_init(&m_nkGdiCtx, m_gdiFont, m_windowDc, width, height);
wnd->_internal.gdi_font = nk_gdifont_create("Arial", 16);
wnd->_internal.nk_ctx = nk_gdi_init(&wnd->_internal.nk_gdi_ctx, wnd->_internal.gdi_font, wnd->_internal.window_dc, width, height);
// Setup internal data
wnd->_internal.is_open = 1;
wnd->_internal.is_draggin = 0;
wnd->_internal.ws_override = 0;
wnd->_internal.is_maximized = 0;
wnd->_internal.drag_offset.x = 0;
wnd->_internal.drag_offset.y = 0;
wnd->_internal.width = 0;
wnd->_internal.height = 0;
}
NkGdi::Window::~Window()
void nkgdi_window_destroy(struct nkgdi_window* wnd)
{
// Destroy GDI context
if (m_nkGdiCtx)
if (wnd->_internal.nk_gdi_ctx)
{
nk_gdi_shutdown(m_nkGdiCtx);
nk_gdi_shutdown(wnd->_internal.nk_gdi_ctx);
}
// Destroy font
if (m_gdiFont)
if (wnd->_internal.gdi_font)
{
nk_gdifont_del(m_gdiFont);
nk_gdifont_del(wnd->_internal.gdi_font);
}
// Close DC
if (m_windowDc)
if (wnd->_internal.window_dc)
{
ReleaseDC(m_window, m_windowDc);
ReleaseDC(wnd->_internal.window_handle, wnd->_internal.window_dc);
}
// Destroy window
if (m_window)
if (wnd->_internal.window_handle)
{
CloseWindow(m_window);
DestroyWindow(m_window);
CloseWindow(wnd->_internal.window_handle);
DestroyWindow(wnd->_internal.window_handle);
}
}
bool NkGdi::Window::Update()
int nkgdi_window_update(struct nkgdi_window* wnd)
{
// Only process events while window is open
if (m_isOpen)
if (wnd->_internal.is_open)
{
// Notify class that event processing has stated
OnUpdate();
// Windows event loop
MSG msg = {};
nk_input_begin(m_nkCtx);
while (PeekMessage(&msg, m_window, 0, 0, PM_REMOVE))
MSG msg;
nk_input_begin(wnd->_internal.nk_ctx);
while (PeekMessage(&msg, wnd->_internal.window_handle, 0, 0, PM_REMOVE))
{
TranslateMessage(&msg);
DispatchMessageW(&msg);
}
nk_input_end(m_nkCtx);
nk_input_end(wnd->_internal.nk_ctx);
// Get title
char title[1024];
GetWindowTextA(m_window, title, 1024);
GetWindowTextA(wnd->_internal.window_handle, title, 1024);
// Window flags
nk_flags window_flags = NK_WINDOW_BORDER;
if(wnd->has_titlebar)
window_flags |= NK_WINDOW_CLOSABLE | NK_WINDOW_TITLE;
if(!wnd->_internal.is_maximized && wnd->allow_sizing)
window_flags |= NK_WINDOW_SCALABLE;
// Window body
if (m_wsOverride)
nk_window_set_bounds(m_nkCtx, title, nk_rect(0, 0, m_width, m_height));
if (nk_begin(m_nkCtx, title, nk_rect(0, 0, m_width, m_height),
NK_WINDOW_BORDER |
(HasTitlebar ? NK_WINDOW_CLOSABLE | NK_WINDOW_TITLE : NULL) |
(m_isMaximized || !AllowSizing ? NULL : NK_WINDOW_SCALABLE)
))
if (wnd->_internal.ws_override)
nk_window_set_bounds(wnd->_internal.nk_ctx, title, nk_rect(0, 0, wnd->_internal.width, wnd->_internal.height));
if (nk_begin(wnd->_internal.nk_ctx, title, nk_rect(0, 0, wnd->_internal.width, wnd->_internal.height), window_flags))
{
if(!OnDraw(m_nkCtx))
m_isOpen = false;
if(!wnd->cb_on_draw(wnd->_internal.nk_ctx))
wnd->_internal.is_open = 0;
// Update window size
struct nk_rect bounds = nk_window_get_bounds(m_nkCtx);
if(bounds.w != m_width || bounds.h != m_height)
SetWindowPos(m_window, NULL, 0, 0, bounds.w, bounds.h, SWP_NOMOVE | SWP_NOOWNERZORDER);
struct nk_rect bounds = nk_window_get_bounds(wnd->_internal.nk_ctx);
if(bounds.w != wnd->_internal.width || bounds.h != wnd->_internal.height)
SetWindowPos(wnd->_internal.window_handle, NULL, 0, 0, bounds.w, bounds.h, SWP_NOMOVE | SWP_NOOWNERZORDER);
}
else
{
// Handle window closing
if(OnClose())
m_isOpen = false;
if(!wnd->cb_on_close || wnd->cb_on_close())
wnd->_internal.is_open = 0;
}
nk_end(m_nkCtx);
m_wsOverride = false;
nk_end(wnd->_internal.nk_ctx);
wnd->_internal.ws_override = 0;
// Final render pass
nk_gdi_render(m_nkGdiCtx, nk_rgb(30, 30, 30));
nk_gdi_render(wnd->_internal.nk_gdi_ctx, nk_rgb(30, 30, 30));
}
return m_isOpen;
return wnd->_internal.is_open;
}
LRESULT NkGdi::Window::OnWindowMessage(HWND wnd, UINT msg, WPARAM wParam, LPARAM lParam)
LRESULT nkgdi_window_proc_setup(HWND wnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
// Wait for setup message
if (msg == WM_NCCREATE)
{
// Get creation parameters & window pointer
CREATESTRUCT* ptrCr = (CREATESTRUCT*)lParam;
struct nkgdi_window* nkgdi_wnd = (struct nkgdi_window*)ptrCr->lpCreateParams;
// Store pointer and new proc in window
SetWindowLongPtr(wnd, GWLP_USERDATA, (LONG_PTR)nkgdi_wnd);
SetWindowLongPtr(wnd, GWLP_WNDPROC, (LONG_PTR)&nkgdi_window_proc_run);
// Handled by window
return nkgdi_window_proc_run(wnd, msg, wParam, lParam);
}
// Default handler
return DefWindowProc(wnd, msg, wParam, lParam);
}
LRESULT nkgdi_window_proc_run(HWND wnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
// Get window pointer
struct nkgdi_window* nkwnd = (struct nkgdi_window*)GetWindowLongPtrW(wnd, GWLP_USERDATA);
// Switch on supplied message code
switch (msg)
{
// Close event
case WM_CLOSE:
if (OnClose())
m_isOpen = false;
if(!nkwnd->cb_on_close || nkwnd->cb_on_close())
nkwnd->_internal.is_open = 0;
return 0; // Will always be handled internaly
// While sizing
@ -247,8 +257,8 @@ LRESULT NkGdi::Window::OnWindowMessage(HWND wnd, UINT msg, WPARAM wParam, LPARAM
{
RECT cr;
GetClientRect(wnd, &cr);
m_width = cr.right - cr.left;
m_height = cr.bottom - cr.top;
nkwnd->_internal.width = cr.right - cr.left;
nkwnd->_internal.height = cr.bottom - cr.top;
}
break;
@ -263,56 +273,56 @@ LRESULT NkGdi::Window::OnWindowMessage(HWND wnd, UINT msg, WPARAM wParam, LPARAM
monitorInfo.cbSize = sizeof(MONITORINFO);
if (GetMonitorInfoW(monitor, &monitorInfo))
{
m_height = monitorInfo.rcWork.bottom - monitorInfo.rcWork.top;
m_width = monitorInfo.rcWork.right - monitorInfo.rcWork.left;
m_wsOverride = true;
m_isMaximized = true;
SetWindowPos(wnd, NULL, 0, 0, m_width, m_height, SWP_NOMOVE | SWP_NOZORDER);
nkwnd->_internal.height = monitorInfo.rcWork.bottom - monitorInfo.rcWork.top;
nkwnd->_internal.width = monitorInfo.rcWork.right - monitorInfo.rcWork.left;
nkwnd->_internal.ws_override = 1;
nkwnd->_internal.is_maximized = 1;
SetWindowPos(wnd, NULL, 0, 0, nkwnd->_internal.width, nkwnd->_internal.height, SWP_NOMOVE | SWP_NOZORDER);
}
}
else if (wParam == SIZE_RESTORED)
{
m_isMaximized = false;
nkwnd->_internal.is_maximized = 0;
}
// Compute new bounds
RECT cr;
GetClientRect(wnd, &cr);
m_width = cr.right - cr.left;
m_height = cr.bottom - cr.top;
nkwnd->_internal.width = cr.right - cr.left;
nkwnd->_internal.height = cr.bottom - cr.top;
}
break;
// When mouse start l-press (drag window)
case WM_LBUTTONDOWN:
{
if (HIWORD(lParam) <= 30 && AllowMove)
if (HIWORD(lParam) <= 30 && nkwnd->allow_move)
{
// Start dragging
m_isDraggin = true;
m_dragOffset.x = LOWORD(lParam);
m_dragOffset.y = HIWORD(lParam);
nkwnd->_internal.is_draggin = 1;
nkwnd->_internal.drag_offset.x = LOWORD(lParam);
nkwnd->_internal.drag_offset.y = HIWORD(lParam);
}
}
break;
// When mouse stops l-press (drag window)
case WM_LBUTTONUP:
m_isDraggin = false;
nkwnd->_internal.is_draggin = 0;
break;
// Mouse movement (dragging)
case WM_MOUSEMOVE:
{
if (m_isDraggin && !m_isMaximized)
if (nkwnd->_internal.is_draggin && !nkwnd->_internal.is_maximized)
{
// Get mouse postion and substract offset
POINT cursorPos;
GetCursorPos(&cursorPos);
cursorPos.x -= m_dragOffset.x;
cursorPos.y -= m_dragOffset.y;
cursorPos.x -= nkwnd->_internal.drag_offset.x;
cursorPos.y -= nkwnd->_internal.drag_offset.y;
// Use as new position
ShowWindow(m_window, SW_RESTORE);
ShowWindow(wnd, SW_RESTORE);
SetWindowPos(wnd, NULL, cursorPos.x, cursorPos.y, 0, 0, SWP_NOSIZE | SWP_NOZORDER);
}
}
@ -321,9 +331,9 @@ LRESULT NkGdi::Window::OnWindowMessage(HWND wnd, UINT msg, WPARAM wParam, LPARAM
// On mouse doubble click (maximize)
case WM_LBUTTONDBLCLK:
{
if (HIWORD(lParam) <= 30 && AllowMaximize)
if (HIWORD(lParam) <= 30 && nkwnd->allow_maximize)
{
if (m_isMaximized)
if (nkwnd->_internal.is_maximized)
{
ShowWindow(wnd, SW_RESTORE);
}
@ -331,47 +341,19 @@ LRESULT NkGdi::Window::OnWindowMessage(HWND wnd, UINT msg, WPARAM wParam, LPARAM
{
ShowWindow(wnd, SW_MAXIMIZE);
}
m_wsOverride = true;
nkwnd->_internal.ws_override = 1;
}
}
break;
}
// Send to nuklear
if (m_nkGdiCtx && nk_gdi_handle_event(m_nkGdiCtx, wnd, msg, wParam, lParam))
if (nkwnd->_internal.nk_gdi_ctx && nk_gdi_handle_event(nkwnd->_internal.nk_gdi_ctx, wnd, msg, wParam, lParam))
return 0;
// In case this is ever reached: Run default behaviour
return DefWindowProc(wnd, msg, wParam, lParam);
}
LRESULT NkGdi::Window::wndProcSetup(HWND wnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
// Wait for setup message
if (msg == WM_NCCREATE)
{
// Get creation parameters & window pointer
CREATESTRUCT* ptrCr = (CREATESTRUCT*)lParam;
Window* ptrWindow = (Window*)ptrCr->lpCreateParams;
// Store pointer and new proc in window
SetWindowLongPtr(wnd, GWLP_USERDATA, (LONG_PTR)ptrWindow);
SetWindowLongPtr(wnd, GWLP_WNDPROC, (LONG_PTR)&wndProcRun);
// Handled by window
return ptrWindow->OnWindowMessage(wnd, msg, wParam, lParam);
}
// Default handler
return DefWindowProc(wnd, msg, wParam, lParam);
}
LRESULT NkGdi::Window::wndProcRun(HWND wnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
// Get window pointer
Window* ptrWindow = (Window*)GetWindowLongPtr(wnd, GWLP_USERDATA);
// Call window
return ptrWindow->OnWindowMessage(wnd, msg, wParam, lParam);
}
#endif
#endif