diff --git a/demo/gdi_native_nuklear/build.bat b/demo/gdi_native_nuklear/build.bat index 65a8ce6..2f87f8e 100644 --- a/demo/gdi_native_nuklear/build.bat +++ b/demo/gdi_native_nuklear/build.bat @@ -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 diff --git a/demo/gdi_native_nuklear/main.cpp b/demo/gdi_native_nuklear/main.c similarity index 61% rename from demo/gdi_native_nuklear/main.cpp rename to demo/gdi_native_nuklear/main.c index 000ea2a..70ba268 100644 --- a/demo/gdi_native_nuklear/main.cpp +++ b/demo/gdi_native_nuklear/main.c @@ -1,5 +1,4 @@ #include -#include #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; } diff --git a/demo/gdi_native_nuklear/window.h b/demo/gdi_native_nuklear/window.h index 123e4a7..ce60475 100644 --- a/demo/gdi_native_nuklear/window.h +++ b/demo/gdi_native_nuklear/window.h @@ -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 + +/* 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