Ver código fonte

Merge branch 'master' of git://github.com/vurtun/nuklear

DeXP 8 anos atrás
pai
commit
f994b15b84

+ 41 - 1
CHANGELOG.md → CHANGELOG.txt

@@ -1,7 +1,7 @@
 # Changelog
 [date][x.yy.zz]-[description]
 
-- [date]: current date on which the change has been pushed
+- [date]: date on which the change has been pushed
 - [x.yy.zz]: Numerical version string representation. Each version number on the right
              resets back to zero if version on the left is incremented.
     - [x]: Major version with API and library breaking (extremly rare, maybe never)
@@ -11,6 +11,46 @@
 
 Changes:
 --------
+- 2017/08/27 (1.40.8) - Fixed `nk_item_is_any_active` for hidden windows
+- 2017/08/27 (1.40.7) - Fixed window background flag
+- 2017/07/07 (1.40.6) - Fixed missing clipping rect check for hovering/clicked
+                        query for widgets
+- 2017/07/07 (1.40.5) - Fixed drawing bug for vertex output for lines and stroked
+                        and filled rectangles
+- 2017/07/07 (1.40.4) - Fixed bug in nk_convert trying to add windows that are in
+                        process of being destroyed.
+- 2017/07/07 (1.40.3) - Fixed table internal bug caused by storing table size in
+                        window instead of directly in table.
+- 2017/06/30 (1.40.2) - Removed unneeded semicolon in C++ NK_ALIGNOF macro
+- 2017/06/30 (1.40.1) - Fixed drawing lines smaller or equal zero
+- 2017/06/08 (1.40.0) - Removed the breaking part of last commit. Auto layout now only
+                        comes in effect if you pass in zero was row height argument
+- 2017/06/08 (1.40.0) - BREAKING CHANGE: while not directly API breaking it will change
+                        how layouting works. From now there will be an internal minimum
+                        row height derived from font height. If you need a row smaller than
+                        that you can directly set it by `nk_layout_set_min_row_height` and
+                        reset the value back by calling `nk_layout_reset_min_row_height.
+- 2017/06/08 (1.39.1) - Fixed property text edit handling bug caused by past `nk_widget` fix
+- 2017/06/08 (1.39.0) - Added function to retrieve window space without calling a nk_layout_xxx function
+- 2017/06/06 (1.38.5) - Fixed `nk_convert` return flag for command buffer
+- 2017/05/23 (1.38.4) - Fixed activation behavior for widgets partially clipped
+- 2017/05/10 (1.38.3) - Fixed wrong min window size mouse scaling over boundries
+- 2017/05/09 (1.38.2) - Fixed vertical scrollbar drawing with not enough space
+- 2017/05/09 (1.38.1) - Fixed scaler dragging behavior if window size hits minimum size
+- 2017/05/06 (1.38.0) - Added platform double-click support
+- 2017/04/20 (1.37.1) - Fixed key repeat found inside glfw demo backends
+- 2017/04/20 (1.37.0) - Extended properties with selection and clipbard support
+- 2017/04/20 (1.36.2) - Fixed #405 overlapping rows with zero padding and spacing
+- 2017/04/09 (1.36.1) - Fixed #403 with another widget float error
+- 2017/04/09 (1.36.0) - Added window `NK_WINDOW_NO_INPUT` and `NK_WINDOW_NOT_INTERACTIVE` flags
+- 2017/04/09 (1.35.3) - Fixed buffer heap corruption
+- 2017/03/25 (1.35.2) - Fixed popup overlapping for `NK_WINDOW_BACKGROUND` windows
+- 2017/03/25 (1.35.1) - Fixed windows closing behavior
+- 2017/03/18 (1.35.0) - Added horizontal scroll requested in #377
+- 2017/03/18 (1.34.3) - Fixed long window header titles
+- 2017/03/04 (1.34.2) - Fixed text edit filtering
+- 2017/03/04 (1.34.1) - Fixed group closable flag
+- 2017/02/25 (1.34.0) - Added custom draw command for better language binding support
 - 2017/01/24 (1.33.0) - Added programatic way of remove edit focus
 - 2017/01/24 (1.32.3) - Fixed wrong define for basic type definitions for windows
 - 2017/01/21 (1.32.2) - Fixed input capture from hidden or closed windows

+ 24 - 12
Readme.md

@@ -1,6 +1,7 @@
+# Nuklear
+
 [![Build Status](https://travis-ci.org/vurtun/nuklear.svg)](https://travis-ci.org/vurtun/nuklear)
 
-# Nuklear
 This is a minimal state immediate mode graphical user interface toolkit
 written in ANSI C and licensed under public domain. It was designed as a simple
 embeddable user interface for application and does not have any dependencies,
@@ -11,10 +12,11 @@ layered library that tries to abstract over a number of platform and
 render backends it only focuses on the actual UI.
 
 ## Features
+
 - Immediate mode graphical user interface toolkit
 - Single header library
 - Written in C89 (ANSI C)
-- Small codebase (~17kLOC)
+- Small codebase (~18kLOC)
 - Focus on portability, efficiency and simplicity
 - No dependencies (not even the standard library if not wanted)
 - Fully skinnable and customizable
@@ -25,6 +27,7 @@ render backends it only focuses on the actual UI.
 - Optional font baker and vertex buffer output
 
 ## Building
+
 This library is self contained in one single header file and can be used either
 in header only mode or in implementation mode. The header only mode is used
 by default when included and allows including this header in other headers
@@ -40,6 +43,7 @@ IMPORTANT: Every time you include "nuklear.h" you have to define the same option
 This is very important not doing it either leads to compiler errors or even worse stack corruptions.
 
 ## Gallery
+
 ![screenshot](https://cloud.githubusercontent.com/assets/8057201/11761525/ae06f0ca-a0c6-11e5-819d-5610b25f6ef4.gif)
 ![screen](https://cloud.githubusercontent.com/assets/8057201/13538240/acd96876-e249-11e5-9547-5ac0b19667a0.png)
 ![screen2](https://cloud.githubusercontent.com/assets/8057201/13538243/b04acd4c-e249-11e5-8fd2-ad7744a5b446.png)
@@ -48,15 +52,16 @@ This is very important not doing it either leads to compiler errors or even wors
 ![gamepad](https://cloud.githubusercontent.com/assets/8057201/14902576/339926a8-0d9c-11e6-9fee-a8b73af04473.png)
 
 ## Example
+
 ```c
 /* init gui state */
 struct nk_context ctx;
 nk_init_fixed(&ctx, calloc(1, MAX_MEMORY), MAX_MEMORY, &font);
 
 enum {EASY, HARD};
-int op = EASY;
-float value = 0.6f;
-int i =  20;
+static int op = EASY;
+static float value = 0.6f;
+static int i =  20;
 
 if (nk_begin(&ctx, "Show", nk_rect(50, 50, 220, 220),
     NK_WINDOW_BORDER|NK_WINDOW_MOVABLE|NK_WINDOW_CLOSABLE)) {
@@ -85,13 +90,19 @@ nk_end(&ctx);
 ```
 ![example](https://cloud.githubusercontent.com/assets/8057201/10187981/584ecd68-675c-11e5-897c-822ef534a876.png)
 
-## Bindings:
-Java: https://github.com/glegris/nuklear4j  
-Golang: https://github.com/golang-ui/nuklear  
-Rust: https://github.com/snuk182/nuklear-rust  
-Chicken: https://github.com/wasamasa/nuklear
+## Bindings
+There are a number of nuklear bindings for different languges created by other authors.
+I cannot atest for their quality since I am not necessarily proficient in either of these
+languages. Furthermore there are no guarantee that all bindings will always be kept up to date:
 
-## Credits:
+- [Java](https://github.com/glegris/nuklear4j) by Guillaume Legris
+- [Golang](https://github.com/golang-ui/nuklear) by [email protected]
+- [Rust](https://github.com/snuk182/nuklear-rust) by [email protected]
+- [Chicken](https://github.com/wasamasa/nuklear) by [email protected]
+- [Nim](https://github.com/zacharycarter/nuklear-nim) by [email protected]
+- [Lua/Löve2d](https://github.com/keharriso/love-nuklear) by Kevin Harrison
+
+## Credits
 Developed by Micha Mettke and every direct or indirect contributor to the GitHub.
 
 
@@ -105,7 +116,8 @@ and his original immediate mode graphical user interface idea and Sean
 Barret for his amazing single header [libraries](https://github.com/nothings/stb) which restored my faith
 in libraries and brought me to create some of my own.
 
-## License:
+## License
+
 This software is dual-licensed to the public domain and under the following
 license: you are granted a perpetual, irrevocable license to copy, modify,
 publish and distribute this file as you see fit.

+ 5 - 10
demo/allegro5/nuklear_allegro5.h

@@ -95,11 +95,9 @@ static float
 nk_allegro5_font_get_text_width(nk_handle handle, float height, const char *text, int len)
 {
     NkAllegro5Font *font = (NkAllegro5Font*)handle.ptr;
-
     if (!font || !text) {
         return 0;
     }
-
     /* We must copy into a new buffer with exact length null-terminated
        as nuklear uses variable size buffers and al_get_text_width doesn't
        accept a length, it infers length from null-termination
@@ -107,7 +105,6 @@ nk_allegro5_font_get_text_width(nk_handle handle, float height, const char *text
     char strcpy[len+1];
     strncpy((char*)&strcpy, text, len);
     strcpy[len] = '\0';
-
     return al_get_text_width(font->font, strcpy);
 }
 
@@ -289,7 +286,7 @@ nk_allegro5_handle_event(ALLEGRO_EVENT *ev)
         case ALLEGRO_EVENT_MOUSE_AXES: {
             nk_input_motion(ctx, ev->mouse.x, ev->mouse.y);
             if (ev->mouse.dz != 0) {
-                nk_input_scroll(ctx, (float)ev->mouse.dz / al_get_mouse_wheel_precision());
+                nk_input_scroll(ctx, nk_vec2(0,(float)ev->mouse.dz / al_get_mouse_wheel_precision()));
             }
         } break;
         case ALLEGRO_EVENT_MOUSE_BUTTON_DOWN:
@@ -342,7 +339,7 @@ nk_allegro5_handle_event(ALLEGRO_EVENT *ev)
         case ALLEGRO_EVENT_KEY_UP: {
             int kc = ev->keyboard.keycode;
             int down = ev->type == ALLEGRO_EVENT_KEY_DOWN;
-            
+
             if (kc == ALLEGRO_KEY_LSHIFT || kc == ALLEGRO_KEY_RSHIFT) nk_input_key(ctx, NK_KEY_SHIFT, down);
             else if (kc == ALLEGRO_KEY_DELETE)    nk_input_key(ctx, NK_KEY_DEL, down);
             else if (kc == ALLEGRO_KEY_ENTER)     nk_input_key(ctx, NK_KEY_ENTER, down);
@@ -367,7 +364,7 @@ nk_allegro5_handle_event(ALLEGRO_EVENT *ev)
             int kc = ev->keyboard.keycode;
             int control_mask = (ev->keyboard.modifiers & ALLEGRO_KEYMOD_CTRL) ||
                                (ev->keyboard.modifiers & ALLEGRO_KEYMOD_COMMAND);
-            
+
             if (kc == ALLEGRO_KEY_C && control_mask) {
                 nk_input_key(ctx, NK_KEY_COPY, 1);
             } else if (kc == ALLEGRO_KEY_V && control_mask) {
@@ -380,9 +377,7 @@ nk_allegro5_handle_event(ALLEGRO_EVENT *ev)
                 nk_input_key(ctx, NK_KEY_TEXT_REDO, 1);
             } else if (kc == ALLEGRO_KEY_A && control_mask) {
                 nk_input_key(ctx, NK_KEY_TEXT_SELECT_ALL, 1);
-            }
-            else {
-                
+            } else {
                 if (kc != ALLEGRO_KEY_BACKSPACE &&
                     kc != ALLEGRO_KEY_LEFT &&
                     kc != ALLEGRO_KEY_RIGHT &&
@@ -398,7 +393,6 @@ nk_allegro5_handle_event(ALLEGRO_EVENT *ev)
                     nk_input_unicode(ctx, ev->keyboard.unichar);
                 }
             }
-
         } break;
         default: break;
     }
@@ -462,3 +456,4 @@ void nk_allegro5_shutdown(void)
 }
 
 #endif /* NK_ALLEGRO5_IMPLEMENTATION */
+

+ 1 - 1
demo/d3d11/main.c

@@ -131,6 +131,7 @@ int main(void)
 
     /* Win32 */
     memset(&wc, 0, sizeof(wc));
+    wc.style = CS_DBLCLKS;
     wc.lpfnWndProc = WindowProc;
     wc.hInstance = GetModuleHandleW(0);
     wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
@@ -241,7 +242,6 @@ int main(void)
             }
         }
         nk_end(ctx);
-        if (nk_window_is_closed(ctx, "Demo")) break;
 
         /* -------------- EXAMPLES ---------------- */
         /*calculator(ctx);*/

+ 6 - 1
demo/d3d11/nuklear_d3d11.h

@@ -316,6 +316,7 @@ nk_d3d11_handle_event(HWND wnd, UINT msg, WPARAM wparam, LPARAM lparam)
         return 1;
 
     case WM_LBUTTONUP:
+        nk_input_button(&d3d11.ctx, NK_BUTTON_DOUBLE, (short)LOWORD(lparam), (short)HIWORD(lparam), 0);
         nk_input_button(&d3d11.ctx, NK_BUTTON_LEFT, (short)LOWORD(lparam), (short)HIWORD(lparam), 0);
         ReleaseCapture();
         return 1;
@@ -341,12 +342,16 @@ nk_d3d11_handle_event(HWND wnd, UINT msg, WPARAM wparam, LPARAM lparam)
         return 1;
 
     case WM_MOUSEWHEEL:
-        nk_input_scroll(&d3d11.ctx, (float)(short)HIWORD(wparam) / WHEEL_DELTA);
+        nk_input_scroll(&d3d11.ctx, nk_vec2(0,(float)(short)HIWORD(wparam) / WHEEL_DELTA));
         return 1;
 
     case WM_MOUSEMOVE:
         nk_input_motion(&d3d11.ctx, (short)LOWORD(lparam), (short)HIWORD(lparam));
         return 1;
+
+    case WM_LBUTTONDBLCLK:
+        nk_input_button(&d3d11.ctx, NK_BUTTON_DOUBLE, (short)LOWORD(lparam), (short)HIWORD(lparam), 1);
+        return 1;
     }
 
     return 0;

+ 6 - 0
demo/d3d9/build.bat

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

+ 298 - 0
demo/d3d9/main.c

@@ -0,0 +1,298 @@
+/* nuklear - 1.32.0 - public domain */
+#define COBJMACROS
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+#include <d3d9.h>
+#include <stdio.h>
+#include <string.h>
+#include <limits.h>
+#include <time.h>
+
+#define WINDOW_WIDTH 800
+#define WINDOW_HEIGHT 600
+
+#define NK_INCLUDE_FIXED_TYPES
+#define NK_INCLUDE_STANDARD_IO
+#define NK_INCLUDE_STANDARD_VARARGS
+#define NK_INCLUDE_DEFAULT_ALLOCATOR
+#define NK_INCLUDE_VERTEX_BUFFER_OUTPUT
+#define NK_INCLUDE_FONT_BAKING
+#define NK_INCLUDE_DEFAULT_FONT
+#define NK_IMPLEMENTATION
+#define NK_D3D9_IMPLEMENTATION
+#include "../../nuklear.h"
+#include "nuklear_d3d9.h"
+
+/* ===============================================================
+ *
+ *                          EXAMPLE
+ *
+ * ===============================================================*/
+/* This are some code examples to provide a small overview of what can be
+ * done with this library. To try out an example uncomment the include
+ * and the corresponding function. */
+ #define UNUSED(a) (void)a
+ #define MIN(a,b) ((a) < (b) ? (a) : (b))
+ #define MAX(a,b) ((a) < (b) ? (b) : (a))
+ #define LEN(a) (sizeof(a)/sizeof(a)[0])
+
+/*#include "../style.c"*/
+/*#include "../calculator.c"*/
+/*#include "../overview.c"*/
+/*#include "../node_editor.c"*/
+
+/* ===============================================================
+ *
+ *                          DEMO
+ *
+ * ===============================================================*/
+static IDirect3DDevice9 *device;
+static IDirect3DDevice9Ex *deviceEx;
+static D3DPRESENT_PARAMETERS present;
+
+static LRESULT CALLBACK
+WindowProc(HWND wnd, UINT msg, WPARAM wparam, LPARAM lparam)
+{
+    switch (msg)
+    {
+    case WM_DESTROY:
+        PostQuitMessage(0);
+        return 0;
+
+    case WM_SIZE:
+        if (device)
+        {
+            UINT width = LOWORD(lparam);
+            UINT height = HIWORD(lparam);
+            if (width != 0 && height != 0 &&
+                (width != present.BackBufferWidth || height != present.BackBufferHeight))
+            {
+                nk_d3d9_release();
+                present.BackBufferWidth = width;
+                present.BackBufferHeight = height;
+                HRESULT hr = IDirect3DDevice9_Reset(device, &present);
+                NK_ASSERT(SUCCEEDED(hr));
+                nk_d3d9_resize(width, height);
+            }
+        }
+        break;
+    }
+
+    if (nk_d3d9_handle_event(wnd, msg, wparam, lparam))
+        return 0;
+
+    return DefWindowProcW(wnd, msg, wparam, lparam);
+}
+
+static void create_d3d9_device(HWND wnd)
+{
+    HRESULT hr;
+
+    present.PresentationInterval = D3DPRESENT_INTERVAL_DEFAULT;
+    present.BackBufferWidth = WINDOW_WIDTH;
+    present.BackBufferHeight = WINDOW_HEIGHT;
+    present.BackBufferFormat = D3DFMT_X8R8G8B8;
+    present.BackBufferCount = 1;
+    present.MultiSampleType = D3DMULTISAMPLE_NONE;
+    present.SwapEffect = D3DSWAPEFFECT_DISCARD;
+    present.hDeviceWindow = wnd;
+    present.EnableAutoDepthStencil = TRUE;
+    present.AutoDepthStencilFormat = D3DFMT_D24S8;
+    present.Flags = D3DPRESENTFLAG_DISCARD_DEPTHSTENCIL;
+    present.Windowed = TRUE;
+
+    {/* first try to create Direct3D9Ex device if possible (on Windows 7+) */
+        typedef HRESULT WINAPI Direct3DCreate9ExPtr(UINT, IDirect3D9Ex**);
+        Direct3DCreate9ExPtr *Direct3DCreate9Ex = (void *)GetProcAddress(GetModuleHandleA("d3d9.dll"), "Direct3DCreate9Ex");
+        if (Direct3DCreate9Ex) {
+            IDirect3D9Ex *d3d9ex;
+            if (SUCCEEDED(Direct3DCreate9Ex(D3D_SDK_VERSION, &d3d9ex))) {
+                hr = IDirect3D9Ex_CreateDeviceEx(d3d9ex, D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, wnd,
+                    D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_PUREDEVICE | D3DCREATE_FPU_PRESERVE,
+                    &present, NULL, &deviceEx);
+                if (SUCCEEDED(hr)) {
+                    device = (IDirect3DDevice9 *)deviceEx;
+                } else {
+                    /* hardware vertex processing not supported, no big deal
+                    retry with software vertex processing */
+                    hr = IDirect3D9Ex_CreateDeviceEx(d3d9ex, D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, wnd,
+                        D3DCREATE_SOFTWARE_VERTEXPROCESSING | D3DCREATE_PUREDEVICE | D3DCREATE_FPU_PRESERVE,
+                        &present, NULL, &deviceEx);
+                    if (SUCCEEDED(hr)) {
+                        device = (IDirect3DDevice9 *)deviceEx;
+                    }
+                }
+                IDirect3D9Ex_Release(d3d9ex);
+            }
+        }
+    }
+
+    if (!device) {
+        /* otherwise do regular D3D9 setup */
+        IDirect3D9 *d3d9 = Direct3DCreate9(D3D_SDK_VERSION);
+
+        hr = IDirect3D9_CreateDevice(d3d9, D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, wnd,
+            D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_PUREDEVICE | D3DCREATE_FPU_PRESERVE,
+            &present, &device);
+        if (FAILED(hr)) {
+            /* hardware vertex processing not supported, no big deal
+            retry with software vertex processing */
+            hr = IDirect3D9_CreateDevice(d3d9, D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, wnd,
+                D3DCREATE_SOFTWARE_VERTEXPROCESSING | D3DCREATE_PUREDEVICE | D3DCREATE_FPU_PRESERVE,
+                &present, &device);
+            NK_ASSERT(SUCCEEDED(hr));
+        }
+        IDirect3D9_Release(d3d9);
+    }
+}
+
+int main(void)
+{
+    struct nk_context *ctx;
+    struct nk_color background;
+
+    WNDCLASSW wc;
+    RECT rect = { 0, 0, WINDOW_WIDTH, WINDOW_HEIGHT };
+    DWORD style = WS_OVERLAPPEDWINDOW;
+    DWORD exstyle = WS_EX_APPWINDOW;
+    HWND wnd;
+    int running = 1;
+
+    /* Win32 */
+    memset(&wc, 0, sizeof(wc));
+    wc.style = CS_DBLCLKS;
+    wc.lpfnWndProc = WindowProc;
+    wc.hInstance = GetModuleHandleW(0);
+    wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
+    wc.hCursor = LoadCursor(NULL, IDC_ARROW);
+    wc.lpszClassName = L"NuklearWindowClass";
+    RegisterClassW(&wc);
+
+    AdjustWindowRectEx(&rect, style, FALSE, exstyle);
+
+    wnd = CreateWindowExW(exstyle, wc.lpszClassName, L"Nuklear Demo",
+        style | WS_VISIBLE, CW_USEDEFAULT, CW_USEDEFAULT,
+        rect.right - rect.left, rect.bottom - rect.top,
+        NULL, NULL, wc.hInstance, NULL);
+
+    create_d3d9_device(wnd);
+
+    /* GUI */
+    ctx = nk_d3d9_init(device, WINDOW_WIDTH, WINDOW_HEIGHT);
+    /* Load Fonts: if none of these are loaded a default font will be used  */
+    /* Load Cursor: if you uncomment cursor loading please hide the cursor */
+    {struct nk_font_atlas *atlas;
+    nk_d3d9_font_stash_begin(&atlas);
+    /*struct nk_font *droid = nk_font_atlas_add_from_file(atlas, "../../extra_font/DroidSans.ttf", 14, 0);*/
+    /*struct nk_font *robot = nk_font_atlas_add_from_file(atlas, "../../extra_font/Roboto-Regular.ttf", 14, 0);*/
+    /*struct nk_font *future = nk_font_atlas_add_from_file(atlas, "../../extra_font/kenvector_future_thin.ttf", 13, 0);*/
+    /*struct nk_font *clean = nk_font_atlas_add_from_file(atlas, "../../extra_font/ProggyClean.ttf", 12, 0);*/
+    /*struct nk_font *tiny = nk_font_atlas_add_from_file(atlas, "../../extra_font/ProggyTiny.ttf", 10, 0);*/
+    /*struct nk_font *cousine = nk_font_atlas_add_from_file(atlas, "../../extra_font/Cousine-Regular.ttf", 13, 0);*/
+    nk_d3d9_font_stash_end();
+    /*nk_style_load_all_cursors(ctx, atlas->cursors);*/
+    /*nk_style_set_font(ctx, &droid->handle)*/;}
+
+    /* style.c */
+    /*set_style(ctx, THEME_WHITE);*/
+    /*set_style(ctx, THEME_RED);*/
+    /*set_style(ctx, THEME_BLUE);*/
+    /*set_style(ctx, THEME_DARK);*/
+
+    background = nk_rgb(28,48,62);
+    while (running)
+    {
+        /* Input */
+        MSG msg;
+        nk_input_begin(ctx);
+        while (PeekMessageW(&msg, NULL, 0, 0, PM_REMOVE)) {
+            if (msg.message == WM_QUIT)
+                running = 0;
+            TranslateMessage(&msg);
+            DispatchMessageW(&msg);
+        }
+        nk_input_end(ctx);
+
+        /* GUI */
+        if (nk_begin(ctx, "Demo", nk_rect(50, 50, 230, 250),
+            NK_WINDOW_BORDER|NK_WINDOW_MOVABLE|NK_WINDOW_SCALABLE|
+            NK_WINDOW_MINIMIZABLE|NK_WINDOW_TITLE))
+        {
+            enum {EASY, HARD};
+            static int op = EASY;
+            static int property = 20;
+
+            nk_layout_row_static(ctx, 30, 80, 1);
+            if (nk_button_label(ctx, "button"))
+                fprintf(stdout, "button pressed\n");
+            nk_layout_row_dynamic(ctx, 30, 2);
+            if (nk_option_label(ctx, "easy", op == EASY)) op = EASY;
+            if (nk_option_label(ctx, "hard", op == HARD)) op = HARD;
+            nk_layout_row_dynamic(ctx, 22, 1);
+            nk_property_int(ctx, "Compression:", 0, &property, 100, 10, 1);
+
+            nk_layout_row_dynamic(ctx, 20, 1);
+            nk_label(ctx, "background:", NK_TEXT_LEFT);
+            nk_layout_row_dynamic(ctx, 25, 1);
+            if (nk_combo_begin_color(ctx, background, nk_vec2(nk_widget_width(ctx),400))) {
+                nk_layout_row_dynamic(ctx, 120, 1);
+                background = nk_color_picker(ctx, background, NK_RGBA);
+                nk_layout_row_dynamic(ctx, 25, 1);
+                background.r = (nk_byte)nk_propertyi(ctx, "#R:", 0, background.r, 255, 1,1);
+                background.g = (nk_byte)nk_propertyi(ctx, "#G:", 0, background.g, 255, 1,1);
+                background.b = (nk_byte)nk_propertyi(ctx, "#B:", 0, background.b, 255, 1,1);
+                background.a = (nk_byte)nk_propertyi(ctx, "#A:", 0, background.a, 255, 1,1);
+                nk_combo_end(ctx);
+            }
+        }
+        nk_end(ctx);
+
+        /* -------------- EXAMPLES ---------------- */
+        /*calculator(ctx);*/
+        /*overview(ctx);*/
+        /*node_editor(ctx);*/
+        /* ----------------------------------------- */
+
+        /* Draw */
+        {
+            HRESULT hr;
+
+            hr = IDirect3DDevice9_Clear(device, 0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER | D3DCLEAR_STENCIL,
+                D3DCOLOR_ARGB(background.a, background.r, background.g, background.b), 0.0f, 0);
+            NK_ASSERT(SUCCEEDED(hr));
+
+            hr = IDirect3DDevice9_BeginScene(device);
+            NK_ASSERT(SUCCEEDED(hr));
+
+            nk_d3d9_render(NK_ANTI_ALIASING_ON);
+
+            hr = IDirect3DDevice9_EndScene(device);
+            NK_ASSERT(SUCCEEDED(hr));
+
+            if (deviceEx) {
+                hr = IDirect3DDevice9Ex_PresentEx(deviceEx, NULL, NULL, NULL, NULL, 0);
+            } else {
+                hr = IDirect3DDevice9_Present(device, NULL, NULL, NULL, NULL);
+            }
+
+            if (hr == D3DERR_DEVICELOST || hr == D3DERR_DEVICEHUNG || hr == D3DERR_DEVICEREMOVED) {
+                /* to recover from this, you'll need to recreate device and all the resources */
+                MessageBoxW(NULL, L"D3D9 device is lost or removed!", L"Error", 0);
+                break;
+            } else if (hr == S_PRESENT_OCCLUDED) {
+                /* window is not visible, so vsync won't work. Let's sleep a bit to reduce CPU usage */
+                Sleep(10);
+            }
+            NK_ASSERT(SUCCEEDED(hr));
+        }
+    }
+
+    nk_d3d9_shutdown();
+    if (deviceEx) {
+        IDirect3DDevice9Ex_Release(deviceEx);
+    } else {
+        IDirect3DDevice9_Release(device);
+    }
+    UnregisterClassW(wc.lpszClassName, wc.hInstance);
+    return 0;
+}

+ 533 - 0
demo/d3d9/nuklear_d3d9.h

@@ -0,0 +1,533 @@
+/*
+ * Nuklear - 1.32.0 - public domain
+ * no warrenty implied; use at your own risk.
+ * authored from 2015-2016 by Micha Mettke
+ */
+/*
+ * ==============================================================
+ *
+ *                              API
+ *
+ * ===============================================================
+ */
+#ifndef NK_D3D9_H_
+#define NK_D3D9_H_
+
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+
+typedef struct IDirect3DDevice9 IDirect3DDevice9;
+
+NK_API struct nk_context *nk_d3d9_init(IDirect3DDevice9 *device, int width, int height);
+NK_API void nk_d3d9_font_stash_begin(struct nk_font_atlas **atlas);
+NK_API void nk_d3d9_font_stash_end(void);
+NK_API int nk_d3d9_handle_event(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam);
+NK_API void nk_d3d9_render(enum nk_anti_aliasing);
+NK_API void nk_d3d9_release(void);
+NK_API void nk_d3d9_resize(int width, int height);
+NK_API void nk_d3d9_shutdown(void);
+
+#endif
+/*
+ * ==============================================================
+ *
+ *                          IMPLEMENTATION
+ *
+ * ===============================================================
+ */
+#ifdef NK_D3D9_IMPLEMENTATION
+
+#define WIN32_LEAN_AND_MEAN
+#define COBJMACROS
+#include <d3d9.h>
+
+#include <stddef.h>
+#include <string.h>
+
+struct nk_d3d9_vertex {
+    /* D3d9 FFP requires three coordinate position, but nuklear writes only 2 elements
+       projection matrix doesn't use z coordinate => so it can be any value.
+       Member order here is important! Do not rearrange them! */
+    float position[3];
+    nk_uchar col[4];
+    float uv[2];
+};
+
+static struct {
+    struct nk_context ctx;
+    struct nk_font_atlas atlas;
+    struct nk_buffer cmds;
+
+    struct nk_draw_null_texture null;
+
+    D3DVIEWPORT9 viewport;
+    D3DMATRIX projection;
+    IDirect3DDevice9 *device;
+    IDirect3DTexture9 *texture;
+    IDirect3DStateBlock9 *state;
+} d3d9;
+
+NK_API void
+nk_d3d9_render(enum nk_anti_aliasing AA)
+{
+    HRESULT hr;
+
+    hr = IDirect3DStateBlock9_Apply(d3d9.state);
+    NK_ASSERT(SUCCEEDED(hr));
+
+    /* projection matrix */
+    IDirect3DDevice9_SetTransform(d3d9.device, D3DTS_PROJECTION, &d3d9.projection);
+
+    /* viewport */
+    IDirect3DDevice9_SetViewport(d3d9.device, &d3d9.viewport);
+
+    /* convert from command queue into draw list and draw to screen */
+    {
+        struct nk_buffer vbuf, ebuf;
+        const struct nk_draw_command *cmd;
+        const nk_draw_index *offset = NULL;
+        UINT vertex_count;
+
+        /* fill converting configuration */
+        struct nk_convert_config config;
+        NK_STORAGE const struct nk_draw_vertex_layout_element vertex_layout[] = {
+            {NK_VERTEX_POSITION, NK_FORMAT_FLOAT,    NK_OFFSETOF(struct nk_d3d9_vertex, position)},
+            {NK_VERTEX_COLOR,    NK_FORMAT_B8G8R8A8, NK_OFFSETOF(struct nk_d3d9_vertex, col)},
+            {NK_VERTEX_TEXCOORD, NK_FORMAT_FLOAT,    NK_OFFSETOF(struct nk_d3d9_vertex, uv)},
+            {NK_VERTEX_LAYOUT_END}
+        };
+        memset(&config, 0, sizeof(config));
+        config.vertex_layout = vertex_layout;
+        config.vertex_size = sizeof(struct nk_d3d9_vertex);
+        config.vertex_alignment = NK_ALIGNOF(struct nk_d3d9_vertex);
+        config.global_alpha = 1.0f;
+        config.shape_AA = AA;
+        config.line_AA = AA;
+        config.circle_segment_count = 22;
+        config.curve_segment_count = 22;
+        config.arc_segment_count = 22;
+        config.null = d3d9.null;
+
+        /* convert shapes into vertexes */
+        nk_buffer_init_default(&vbuf);
+        nk_buffer_init_default(&ebuf);
+        nk_convert(&d3d9.ctx, &d3d9.cmds, &vbuf, &ebuf, &config);
+
+        /* iterate over and execute each draw command */
+        offset = (const nk_draw_index *)nk_buffer_memory_const(&ebuf);
+        vertex_count = (UINT)vbuf.needed / sizeof(struct nk_d3d9_vertex);
+
+        nk_draw_foreach(cmd, &d3d9.ctx, &d3d9.cmds)
+        {
+            RECT scissor;
+            if (!cmd->elem_count) continue;
+
+            hr = IDirect3DDevice9_SetTexture(d3d9.device, 0, (IDirect3DBaseTexture9 *)cmd->texture.ptr);
+            NK_ASSERT(SUCCEEDED(hr));
+
+            scissor.left = (LONG)cmd->clip_rect.x;
+            scissor.right = (LONG)(cmd->clip_rect.x + cmd->clip_rect.w);
+            scissor.top = (LONG)cmd->clip_rect.y;
+            scissor.bottom = (LONG)(cmd->clip_rect.y + cmd->clip_rect.h);
+
+            hr = IDirect3DDevice9_SetScissorRect(d3d9.device, &scissor);
+            NK_ASSERT(SUCCEEDED(hr));
+
+            NK_ASSERT(sizeof(nk_draw_index) == sizeof(NK_UINT16));
+            hr = IDirect3DDevice9_DrawIndexedPrimitiveUP(d3d9.device, D3DPT_TRIANGLELIST,
+                0, vertex_count, cmd->elem_count/3, offset, D3DFMT_INDEX16,
+                nk_buffer_memory_const(&vbuf), sizeof(struct nk_d3d9_vertex));
+            NK_ASSERT(SUCCEEDED(hr));
+            offset += cmd->elem_count;
+        }
+
+        nk_buffer_free(&vbuf);
+        nk_buffer_free(&ebuf);
+    }
+
+    nk_clear(&d3d9.ctx);
+}
+
+static void
+nk_d3d9_get_projection_matrix(int width, int height, float *result)
+{
+    const float L = 0.5f;
+    const float R = (float)width + 0.5f;
+    const float T = 0.5f;
+    const float B = (float)height + 0.5f;
+    float matrix[4][4] = {
+        {    2.0f / (R - L),              0.0f, 0.0f, 0.0f },
+        {              0.0f,    2.0f / (T - B), 0.0f, 0.0f },
+        {              0.0f,              0.0f, 0.0f, 0.0f },
+        { (R + L) / (L - R), (T + B) / (B - T), 0.0f, 1.0f },
+    };
+    memcpy(result, matrix, sizeof(matrix));
+}
+
+NK_API void
+nk_d3d9_release(void)
+{
+    IDirect3DTexture9_Release(d3d9.texture);
+    IDirect3DStateBlock9_Release(d3d9.state);
+}
+
+static void
+nk_d3d9_create_font_texture()
+{
+    int w, h, y;
+    const void *image;
+
+    HRESULT hr;
+    D3DLOCKED_RECT locked;
+
+    image = nk_font_atlas_bake(&d3d9.atlas, &w, &h, NK_FONT_ATLAS_RGBA32);
+
+    hr = IDirect3DDevice9_CreateTexture(d3d9.device, w, h, 1, D3DUSAGE_DYNAMIC, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &d3d9.texture, NULL);
+    NK_ASSERT(SUCCEEDED(hr));
+
+    hr = IDirect3DTexture9_LockRect(d3d9.texture, 0, &locked, NULL, 0);
+    NK_ASSERT(SUCCEEDED(hr));
+
+    for (y = 0; y < h; y++) {
+        void *src = (char *)image + y * w * 4;
+        void *dst = (char *)locked.pBits + y * locked.Pitch;
+        memcpy(dst, src, w * 4);
+    }
+
+    hr = IDirect3DTexture9_UnlockRect(d3d9.texture, 0);
+    NK_ASSERT(SUCCEEDED(hr));
+
+    nk_font_atlas_end(&d3d9.atlas, nk_handle_ptr(d3d9.texture), &d3d9.null);
+}
+
+NK_API void
+nk_d3d9_resize(int width, int height)
+{
+    HRESULT hr;
+
+    if (d3d9.texture) {
+        nk_d3d9_create_font_texture();
+    }
+
+    hr = IDirect3DDevice9_BeginStateBlock(d3d9.device);
+    NK_ASSERT(SUCCEEDED(hr));
+
+    /* vertex format */
+    IDirect3DDevice9_SetFVF(d3d9.device, D3DFVF_XYZ + D3DFVF_DIFFUSE + D3DFVF_TEX1);
+
+    /* blend state */
+    IDirect3DDevice9_SetRenderState(d3d9.device, D3DRS_SRCBLEND, D3DBLEND_SRCALPHA);
+    IDirect3DDevice9_SetRenderState(d3d9.device, D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA);
+    IDirect3DDevice9_SetRenderState(d3d9.device, D3DRS_ALPHABLENDENABLE, TRUE);
+    IDirect3DDevice9_SetRenderState(d3d9.device, D3DRS_BLENDOP, D3DBLENDOP_ADD);
+
+    /* render state */
+    IDirect3DDevice9_SetRenderState(d3d9.device, D3DRS_LIGHTING, FALSE);
+    IDirect3DDevice9_SetRenderState(d3d9.device, D3DRS_ZENABLE, FALSE);
+    IDirect3DDevice9_SetRenderState(d3d9.device, D3DRS_ZWRITEENABLE, FALSE);
+    IDirect3DDevice9_SetRenderState(d3d9.device, D3DRS_CULLMODE, D3DCULL_NONE);
+    IDirect3DDevice9_SetRenderState(d3d9.device, D3DRS_SCISSORTESTENABLE, TRUE);
+
+    /* sampler state */
+    IDirect3DDevice9_SetSamplerState(d3d9.device, 0, D3DSAMP_ADDRESSU, D3DTADDRESS_CLAMP);
+    IDirect3DDevice9_SetSamplerState(d3d9.device, 0, D3DSAMP_ADDRESSV, D3DTADDRESS_CLAMP);
+    IDirect3DDevice9_SetSamplerState(d3d9.device, 0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR);
+    IDirect3DDevice9_SetSamplerState(d3d9.device, 0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR);
+
+    /* texture stage state */
+    IDirect3DDevice9_SetTextureStageState(d3d9.device, 0, D3DTSS_COLOROP, D3DTOP_MODULATE);
+    IDirect3DDevice9_SetTextureStageState(d3d9.device, 0, D3DTSS_COLORARG1, D3DTA_TEXTURE);
+    IDirect3DDevice9_SetTextureStageState(d3d9.device, 0, D3DTSS_COLORARG2, D3DTA_DIFFUSE);
+    IDirect3DDevice9_SetTextureStageState(d3d9.device, 0, D3DTSS_ALPHAOP, D3DTOP_MODULATE);
+    IDirect3DDevice9_SetTextureStageState(d3d9.device, 0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE);
+    IDirect3DDevice9_SetTextureStageState(d3d9.device, 0, D3DTSS_ALPHAARG2, D3DTA_DIFFUSE);
+
+    hr = IDirect3DDevice9_EndStateBlock(d3d9.device, &d3d9.state);
+    NK_ASSERT(SUCCEEDED(hr));
+
+    nk_d3d9_get_projection_matrix(width, height, &d3d9.projection.m[0][0]);
+    d3d9.viewport.Width = width;
+    d3d9.viewport.Height = height;
+}
+
+NK_API int
+nk_d3d9_handle_event(HWND wnd, UINT msg, WPARAM wparam, LPARAM lparam)
+{
+    switch (msg)
+    {
+    case WM_KEYDOWN:
+    case WM_KEYUP:
+    case WM_SYSKEYDOWN:
+    case WM_SYSKEYUP:
+    {
+        int down = !((lparam >> 31) & 1);
+        int ctrl = GetKeyState(VK_CONTROL) & (1 << 15);
+
+        switch (wparam)
+        {
+        case VK_SHIFT:
+        case VK_LSHIFT:
+        case VK_RSHIFT:
+            nk_input_key(&d3d9.ctx, NK_KEY_SHIFT, down);
+            return 1;
+
+        case VK_DELETE:
+            nk_input_key(&d3d9.ctx, NK_KEY_DEL, down);
+            return 1;
+
+        case VK_RETURN:
+            nk_input_key(&d3d9.ctx, NK_KEY_ENTER, down);
+            return 1;
+
+        case VK_TAB:
+            nk_input_key(&d3d9.ctx, NK_KEY_TAB, down);
+            return 1;
+
+        case VK_LEFT:
+            if (ctrl)
+                nk_input_key(&d3d9.ctx, NK_KEY_TEXT_WORD_LEFT, down);
+            else
+                nk_input_key(&d3d9.ctx, NK_KEY_LEFT, down);
+            return 1;
+
+        case VK_RIGHT:
+            if (ctrl)
+                nk_input_key(&d3d9.ctx, NK_KEY_TEXT_WORD_RIGHT, down);
+            else
+                nk_input_key(&d3d9.ctx, NK_KEY_RIGHT, down);
+            return 1;
+
+        case VK_BACK:
+            nk_input_key(&d3d9.ctx, NK_KEY_BACKSPACE, down);
+            return 1;
+
+        case VK_HOME:
+            nk_input_key(&d3d9.ctx, NK_KEY_TEXT_START, down);
+            nk_input_key(&d3d9.ctx, NK_KEY_SCROLL_START, down);
+            return 1;
+
+        case VK_END:
+            nk_input_key(&d3d9.ctx, NK_KEY_TEXT_END, down);
+            nk_input_key(&d3d9.ctx, NK_KEY_SCROLL_END, down);
+            return 1;
+
+        case VK_NEXT:
+            nk_input_key(&d3d9.ctx, NK_KEY_SCROLL_DOWN, down);
+            return 1;
+
+        case VK_PRIOR:
+            nk_input_key(&d3d9.ctx, NK_KEY_SCROLL_UP, down);
+            return 1;
+
+        case 'C':
+            if (ctrl) {
+                nk_input_key(&d3d9.ctx, NK_KEY_COPY, down);
+                return 1;
+            }
+            break;
+
+        case 'V':
+            if (ctrl) {
+                nk_input_key(&d3d9.ctx, NK_KEY_PASTE, down);
+                return 1;
+            }
+            break;
+
+        case 'X':
+            if (ctrl) {
+                nk_input_key(&d3d9.ctx, NK_KEY_CUT, down);
+                return 1;
+            }
+            break;
+
+        case 'Z':
+            if (ctrl) {
+                nk_input_key(&d3d9.ctx, NK_KEY_TEXT_UNDO, down);
+                return 1;
+            }
+            break;
+
+        case 'R':
+            if (ctrl) {
+                nk_input_key(&d3d9.ctx, NK_KEY_TEXT_REDO, down);
+                return 1;
+            }
+            break;
+        }
+        return 0;
+    }
+
+    case WM_CHAR:
+        if (wparam >= 32)
+        {
+            nk_input_unicode(&d3d9.ctx, (nk_rune)wparam);
+            return 1;
+        }
+        break;
+
+    case WM_LBUTTONDOWN:
+        nk_input_button(&d3d9.ctx, NK_BUTTON_LEFT, (short)LOWORD(lparam), (short)HIWORD(lparam), 1);
+        SetCapture(wnd);
+        return 1;
+
+    case WM_LBUTTONUP:
+        nk_input_button(&d3d9.ctx, NK_BUTTON_DOUBLE, (short)LOWORD(lparam), (short)HIWORD(lparam), 0);
+        nk_input_button(&d3d9.ctx, NK_BUTTON_LEFT, (short)LOWORD(lparam), (short)HIWORD(lparam), 0);
+        ReleaseCapture();
+        return 1;
+
+    case WM_RBUTTONDOWN:
+        nk_input_button(&d3d9.ctx, NK_BUTTON_RIGHT, (short)LOWORD(lparam), (short)HIWORD(lparam), 1);
+        SetCapture(wnd);
+        return 1;
+
+    case WM_RBUTTONUP:
+        nk_input_button(&d3d9.ctx, NK_BUTTON_RIGHT, (short)LOWORD(lparam), (short)HIWORD(lparam), 0);
+        ReleaseCapture();
+        return 1;
+
+    case WM_MBUTTONDOWN:
+        nk_input_button(&d3d9.ctx, NK_BUTTON_MIDDLE, (short)LOWORD(lparam), (short)HIWORD(lparam), 1);
+        SetCapture(wnd);
+        return 1;
+
+    case WM_MBUTTONUP:
+        nk_input_button(&d3d9.ctx, NK_BUTTON_MIDDLE, (short)LOWORD(lparam), (short)HIWORD(lparam), 0);
+        ReleaseCapture();
+        return 1;
+
+    case WM_MOUSEWHEEL:
+        nk_input_scroll(&d3d9.ctx, nk_vec2(0,(float)(short)HIWORD(wparam) / WHEEL_DELTA));
+        return 1;
+
+    case WM_MOUSEMOVE:
+        nk_input_motion(&d3d9.ctx, (short)LOWORD(lparam), (short)HIWORD(lparam));
+        return 1;
+
+    case WM_LBUTTONDBLCLK:
+        nk_input_button(&d3d9.ctx, NK_BUTTON_DOUBLE, (short)LOWORD(lparam), (short)HIWORD(lparam), 1);
+        return 1;
+    }
+
+    return 0;
+}
+
+static void
+nk_d3d9_clipboard_paste(nk_handle usr, struct nk_text_edit *edit)
+{
+    (void)usr;
+    if (!IsClipboardFormatAvailable(CF_UNICODETEXT) && OpenClipboard(NULL)) {
+        return;
+    }
+
+    HGLOBAL mem = GetClipboardData(CF_UNICODETEXT);
+    if (!mem) {
+        CloseClipboard();
+        return;
+    }
+
+    SIZE_T size = GlobalSize(mem) - 1;
+    if (!size) {
+        CloseClipboard();
+        return;
+    }
+
+    LPCWSTR wstr = (LPCWSTR)GlobalLock(mem);
+    if (!wstr) {
+        CloseClipboard();
+        return;
+    }
+
+    int utf8size = WideCharToMultiByte(CP_UTF8, 0, wstr, (int)size / sizeof(wchar_t), NULL, 0, NULL, NULL);
+    if (utf8size) {
+        char *utf8 = (char *)malloc(utf8size);
+        if (utf8) {
+            WideCharToMultiByte(CP_UTF8, 0, wstr, (int)size / sizeof(wchar_t), utf8, utf8size, NULL, NULL);
+            nk_textedit_paste(edit, utf8, utf8size);
+            free(utf8);
+        }
+    }
+
+    GlobalUnlock(mem); 
+    CloseClipboard();
+}
+
+static void
+nk_d3d9_clipboard_copy(nk_handle usr, const char *text, int len)
+{
+    (void)usr;
+    if (!OpenClipboard(NULL)) {
+        return;
+    }
+
+    int wsize = MultiByteToWideChar(CP_UTF8, 0, text, len, NULL, 0);
+    if (wsize) {
+        HGLOBAL mem = GlobalAlloc(GMEM_MOVEABLE, (wsize + 1) * sizeof(wchar_t));
+        if (mem) {
+            wchar_t *wstr = (wchar_t*)GlobalLock(mem);
+            if (wstr) {
+                MultiByteToWideChar(CP_UTF8, 0, text, len, wstr, wsize);
+                wstr[wsize] = 0;
+                GlobalUnlock(mem);
+                SetClipboardData(CF_UNICODETEXT, mem); 
+            }
+        }
+    }
+
+    CloseClipboard();
+}
+
+NK_API struct nk_context*
+nk_d3d9_init(IDirect3DDevice9 *device, int width, int height)
+{
+    d3d9.device = device;
+    IDirect3DDevice9_AddRef(device);
+
+    nk_init_default(&d3d9.ctx, 0);
+    d3d9.state = NULL;
+    d3d9.texture = NULL;
+    d3d9.ctx.clip.copy = nk_d3d9_clipboard_copy;
+    d3d9.ctx.clip.paste = nk_d3d9_clipboard_paste;
+    d3d9.ctx.clip.userdata = nk_handle_ptr(0);
+
+    nk_buffer_init_default(&d3d9.cmds);
+
+    /* viewport */
+    d3d9.viewport.X = 0;
+    d3d9.viewport.Y = 0;
+    d3d9.viewport.MinZ = 0.0f;
+    d3d9.viewport.MaxZ = 1.0f;
+
+    nk_d3d9_resize(width, height);
+
+    return &d3d9.ctx;
+}
+
+NK_API void
+nk_d3d9_font_stash_begin(struct nk_font_atlas **atlas)
+{
+    nk_font_atlas_init_default(&d3d9.atlas);
+    nk_font_atlas_begin(&d3d9.atlas);
+    *atlas = &d3d9.atlas;
+}
+
+NK_API void
+nk_d3d9_font_stash_end(void)
+{
+    nk_d3d9_create_font_texture();
+
+    if (d3d9.atlas.default_font)
+        nk_style_set_font(&d3d9.ctx, &d3d9.atlas.default_font->handle);
+}
+
+NK_API
+void nk_d3d9_shutdown(void)
+{
+    nk_d3d9_release();
+
+    nk_font_atlas_clear(&d3d9.atlas);
+    nk_buffer_free(&d3d9.cmds);
+    nk_free(&d3d9.ctx);
+}
+
+#endif

+ 1 - 1
demo/gdi/main.c

@@ -74,6 +74,7 @@ int main(void)
 
     /* Win32 */
     memset(&wc, 0, sizeof(wc));
+    wc.style = CS_DBLCLKS;
     wc.lpfnWndProc = WindowProc;
     wc.hInstance = GetModuleHandleW(0);
     wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
@@ -141,7 +142,6 @@ int main(void)
             nk_property_int(ctx, "Compression:", 0, &property, 100, 10, 1);
         }
         nk_end(ctx);
-        if (nk_window_is_closed(ctx, "Demo")) break;
 
         /* -------------- EXAMPLES ---------------- */
         /*calculator(ctx);*/

+ 82 - 2
demo/gdi/nuklear_gdi.h

@@ -57,6 +57,78 @@ static struct {
     struct nk_context ctx;
 } gdi;
 
+static void
+nk_create_image(struct nk_image * image, const char * frame_buffer, const int width, const int height)
+{
+    if (image && frame_buffer && (width > 0) && (height > 0))
+    {
+        image->w = width;
+        image->h = height;
+        image->region[0] = 0;
+        image->region[1] = 0;
+        image->region[2] = width;
+        image->region[3] = height;
+        
+        INT row = ((width * 3 + 3) & ~3);
+        BITMAPINFO bi = { 0 };
+        bi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
+        bi.bmiHeader.biWidth = width;
+        bi.bmiHeader.biHeight = height;
+        bi.bmiHeader.biPlanes = 1;
+        bi.bmiHeader.biBitCount = 24;
+        bi.bmiHeader.biCompression = BI_RGB;
+        bi.bmiHeader.biSizeImage = row * height;
+        
+        LPBYTE lpBuf, pb = NULL;
+        HBITMAP hbm = CreateDIBSection(NULL, &bi, DIB_RGB_COLORS, (void**)&lpBuf, NULL, 0);
+        
+        pb = lpBuf + row * height;
+        unsigned char * src = (unsigned char *)frame_buffer;
+        for (int v = 0; v<height; v++)
+        {
+            pb -= row;
+            for (int i = 0; i < row; i += 3)
+            {
+                pb[i + 0] = src[0];
+                pb[i + 1] = src[1];
+                pb[i + 2] = src[2];
+                src += 3;
+            }
+        }        
+        SetDIBits(NULL, hbm, 0, height, lpBuf, &bi, DIB_RGB_COLORS);
+        image->handle.ptr = hbm;
+    }
+}
+
+static void
+nk_delete_image(struct nk_image * image)
+{
+    if (image && image->handle.id != 0)
+    {
+        HBITMAP hbm = image->handle.ptr;
+        DeleteObject(hbm);
+        memset(image, 0, sizeof(struct nk_image));
+    }
+}
+
+static void
+nk_gdi_draw_image(short x, short y, unsigned short w, unsigned short h,
+	struct nk_image img, struct nk_color col)
+{
+    HBITMAP	hbm = img.handle.ptr;
+    HDC     hDCBits;
+    BITMAP  bitmap;
+    
+    if (!gdi.memory_dc || !hbm)
+        return;
+    
+    hDCBits = CreateCompatibleDC(gdi.memory_dc);
+    GetObject(hbm, sizeof(BITMAP), (LPSTR)&bitmap);
+    SelectObject(hDCBits, hbm);
+    StretchBlt(gdi.memory_dc, x, y, w, h, hDCBits, 0, 0, bitmap.bmWidth, bitmap.bmHeight, SRCCOPY);
+    DeleteDC(hDCBits);
+}
+
 static COLORREF
 convert_color(struct nk_color c)
 {
@@ -627,6 +699,7 @@ nk_gdi_handle_event(HWND wnd, UINT msg, WPARAM wparam, LPARAM lparam)
         return 1;
 
     case WM_LBUTTONUP:
+        nk_input_button(&gdi.ctx, NK_BUTTON_DOUBLE, (short)LOWORD(lparam), (short)HIWORD(lparam), 0);
         nk_input_button(&gdi.ctx, NK_BUTTON_LEFT, (short)LOWORD(lparam), (short)HIWORD(lparam), 0);
         ReleaseCapture();
         return 1;
@@ -652,12 +725,16 @@ nk_gdi_handle_event(HWND wnd, UINT msg, WPARAM wparam, LPARAM lparam)
         return 1;
 
     case WM_MOUSEWHEEL:
-        nk_input_scroll(&gdi.ctx, (float)(short)HIWORD(wparam) / WHEEL_DELTA);
+        nk_input_scroll(&gdi.ctx, nk_vec2(0,(float)(short)HIWORD(wparam) / WHEEL_DELTA));
         return 1;
 
     case WM_MOUSEMOVE:
         nk_input_motion(&gdi.ctx, (short)LOWORD(lparam), (short)HIWORD(lparam));
         return 1;
+
+    case WM_LBUTTONDBLCLK:
+        nk_input_button(&gdi.ctx, NK_BUTTON_DOUBLE, (short)LOWORD(lparam), (short)HIWORD(lparam), 1);
+        return 1;
     }
 
     return 0;
@@ -747,7 +824,10 @@ nk_gdi_render(struct nk_color clear)
                 q->end, q->line_thickness, q->color);
         } break;
         case NK_COMMAND_RECT_MULTI_COLOR:
-        case NK_COMMAND_IMAGE:
+        case NK_COMMAND_IMAGE: {
+			const struct nk_command_image *i = (const struct nk_command_image *)cmd;
+			nk_gdi_draw_image(i->x, i->y, i->w, i->h, i->img, i->col);
+		} break;
         case NK_COMMAND_ARC:
         case NK_COMMAND_ARC_FILLED:
         default: break;

+ 1 - 1
demo/gdip/build.bat

@@ -2,4 +2,4 @@
 
 call "C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat" x86
 
-cl /nologo /W3 /O2 /fp:fast /Gm- /Fedemo.exe main.c user32.lib gdiplus.lib ole32.lib /link /incremental:no
+cl /nologo /W3 /O2 /fp:fast /Gm- /Fedemo.exe /D_CRT_SECURE_NO_DEPRECATE main.c user32.lib gdiplus.lib shlwapi.lib /link /incremental:no

+ 1 - 1
demo/gdip/main.c

@@ -69,6 +69,7 @@ int main(void)
 
     /* Win32 */
     memset(&wc, 0, sizeof(wc));
+    wc.style = CS_DBLCLKS;
     wc.lpfnWndProc = WindowProc;
     wc.hInstance = GetModuleHandleW(0);
     wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
@@ -136,7 +137,6 @@ int main(void)
             nk_property_int(ctx, "Compression:", 0, &property, 100, 10, 1);
         }
         nk_end(ctx);
-        if (nk_window_is_closed(ctx, "Demo")) break;
 
         /* -------------- EXAMPLES ---------------- */
         /*calculator(ctx);*/

+ 34 - 18
demo/gdip/nuklear_gdip.h

@@ -15,6 +15,7 @@
 
 #define WIN32_LEAN_AND_MEAN
 #include <windows.h>
+#include <shlwapi.h>
 
 /* font */
 typedef struct GdipFont GdipFont;
@@ -31,7 +32,8 @@ NK_API void nk_gdip_shutdown(void);
 
 /* image */
 NK_API struct nk_image nk_gdip_load_image_from_file(const WCHAR* filename);
-NK_API struct nk_image nk_gdip_load_image_from_memory(const void* membuf, int membufSize);
+NK_API struct nk_image nk_gdip_load_image_from_memory(const void* membuf, nk_uint membufSize);
+NK_API void nk_gdip_image_free(struct nk_image image);
 
 #endif
 /*
@@ -59,7 +61,6 @@ typedef struct GpStringFormat GpStringFormat;
 typedef struct GpFont GpFont;
 typedef struct GpFontFamily GpFontFamily;
 typedef struct GpFontCollection GpFontCollection;
-typedef struct IStream IStream;
 
 typedef GpImage GpBitmap;
 typedef GpBrush GpSolidFill;
@@ -602,8 +603,8 @@ nk_gdip_blit(GpGraphics *graphics)
     GdipDrawImageI(graphics, gdip.bitmap, 0, 0);
 }
 
-struct nk_image
-nk_gdip_image_to_nk(GpImage *image){
+static struct nk_image
+nk_gdip_image_to_nk(GpImage *image) {
     struct nk_image img;
     UINT uwidth, uheight;
     img = nk_image_ptr( (void*)image );
@@ -615,30 +616,40 @@ nk_gdip_image_to_nk(GpImage *image){
 }
 
 struct nk_image
-nk_gdip_load_image_from_file(GDIPCONST WCHAR *filename)
+nk_gdip_load_image_from_file(const WCHAR *filename)
 {
     GpImage *image;
-    GdipLoadImageFromFile(filename, &image);
+    if (GdipLoadImageFromFile(filename, &image))
+        return nk_image_id(0);
     return nk_gdip_image_to_nk(image);
 }
 
 struct nk_image
-nk_gdip_load_image_from_memory(const void *membuf, int membufSize)
+nk_gdip_load_image_from_memory(const void *membuf, nk_uint membufSize)
 {
-    GpImage *image = NULL;
-    IStream *pStream = NULL;
-    HGLOBAL hMem = GlobalAlloc(GMEM_MOVEABLE, membufSize);
-    LPVOID pImage = GlobalLock(hMem);
-    nk_memcopy(pImage, membuf, membufSize);
-    GlobalUnlock(hMem);
+    GpImage* image;
+    GpStatus status;
+    IStream *stream = SHCreateMemStream((const BYTE*)membuf, membufSize);
+    if (!stream)
+        return nk_image_id(0);
     
-    /* CreateStreamOnHGlobal needs OLE32 in linked libraries list */
-    CreateStreamOnHGlobal(hMem, FALSE, &pStream);
-    GdipLoadImageFromStream(pStream, &image);
-    GlobalFree(hMem);
+    status = GdipLoadImageFromStream(stream, &image);
+    stream->lpVtbl->Release(stream);
+
+    if (status)
+        return nk_image_id(0);
+
     return nk_gdip_image_to_nk(image);
 }
 
+void
+nk_gdip_image_free(struct nk_image image)
+{
+    if (!image.handle.ptr)
+        return;
+    GdipDisposeImage(image.handle.ptr);
+}
+
 GdipFont*
 nk_gdipfont_create(const char *name, int size)
 {
@@ -988,6 +999,7 @@ nk_gdip_handle_event(HWND wnd, UINT msg, WPARAM wparam, LPARAM lparam)
         return 1;
 
     case WM_LBUTTONUP:
+        nk_input_button(&gdip.ctx, NK_BUTTON_DOUBLE, (short)LOWORD(lparam), (short)HIWORD(lparam), 0);
         nk_input_button(&gdip.ctx, NK_BUTTON_LEFT, (short)LOWORD(lparam), (short)HIWORD(lparam), 0);
         ReleaseCapture();
         return 1;
@@ -1013,12 +1025,16 @@ nk_gdip_handle_event(HWND wnd, UINT msg, WPARAM wparam, LPARAM lparam)
         return 1;
 
     case WM_MOUSEWHEEL:
-        nk_input_scroll(&gdip.ctx, (float)(short)HIWORD(wparam) / WHEEL_DELTA);
+        nk_input_scroll(&gdip.ctx, nk_vec2(0,(float)(short)HIWORD(wparam) / WHEEL_DELTA));
         return 1;
 
     case WM_MOUSEMOVE:
         nk_input_motion(&gdip.ctx, (short)LOWORD(lparam), (short)HIWORD(lparam));
         return 1;
+
+    case WM_LBUTTONDBLCLK:
+        nk_input_button(&gdip.ctx, NK_BUTTON_DOUBLE, (short)LOWORD(lparam), (short)HIWORD(lparam), 1);
+        return 1;
     }
 
     return 0;

+ 1 - 4
demo/glfw_opengl2/main.c

@@ -27,9 +27,6 @@
 #define WINDOW_WIDTH 1200
 #define WINDOW_HEIGHT 800
 
-#define MAX_VERTEX_BUFFER 512 * 1024
-#define MAX_ELEMENT_BUFFER 128 * 1024
-
 #define UNUSED(a) (void)a
 #define MIN(a,b) ((a) < (b) ? (a) : (b))
 #define MAX(a,b) ((a) < (b) ? (b) : (a))
@@ -155,7 +152,7 @@ int main(void)
          * with blending, scissor, face culling and depth test and defaults everything
          * back into a default state. Make sure to either save and restore or
          * reset your own state after drawing rendering the UI. */
-        nk_glfw3_render(NK_ANTI_ALIASING_ON, MAX_VERTEX_BUFFER, MAX_ELEMENT_BUFFER);
+        nk_glfw3_render(NK_ANTI_ALIASING_ON);
         glfwSwapBuffers(win);}
     }
     nk_glfw3_shutdown();

+ 38 - 7
demo/glfw_opengl2/nuklear_glfw_gl2.h

@@ -1,7 +1,7 @@
 /*
  * Nuklear - v1.32.0 - public domain
  * no warrenty implied; use at your own risk.
- * authored from 2015-2016 by Micha Mettke
+ * authored from 2015-2017 by Micha Mettke
  */
 /*
  * ==============================================================
@@ -24,7 +24,7 @@ NK_API void                 nk_glfw3_font_stash_begin(struct nk_font_atlas **atl
 NK_API void                 nk_glfw3_font_stash_end(void);
 
 NK_API void                 nk_glfw3_new_frame(void);
-NK_API void                 nk_glfw3_render(enum nk_anti_aliasing , int max_vertex_buffer, int max_element_buffer);
+NK_API void                 nk_glfw3_render(enum nk_anti_aliasing);
 NK_API void                 nk_glfw3_shutdown(void);
 
 NK_API void                 nk_glfw3_char_callback(GLFWwindow *win, unsigned int codepoint);
@@ -44,6 +44,12 @@ NK_API void                 nk_gflw3_scroll_callback(GLFWwindow *win, double xof
 #ifndef NK_GLFW_TEXT_MAX
 #define NK_GLFW_TEXT_MAX 256
 #endif
+#ifndef NK_GLFW_DOUBLE_CLICK_LO
+#define NK_GLFW_DOUBLE_CLICK_LO 0.02
+#endif
+#ifndef NK_GLFW_DOUBLE_CLICK_HI
+#define NK_GLFW_DOUBLE_CLICK_HI 0.2
+#endif
 
 struct nk_glfw_device {
     struct nk_buffer cmds;
@@ -67,7 +73,10 @@ static struct nk_glfw {
     struct nk_vec2 fb_scale;
     unsigned int text[NK_GLFW_TEXT_MAX];
     int text_len;
-    float scroll;
+    struct nk_vec2 scroll;
+    double last_button_click;
+    int is_double_click_down;
+    struct nk_vec2 double_click_pos;
 } glfw;
 
 NK_INTERN void
@@ -83,7 +92,7 @@ nk_glfw3_device_upload_atlas(const void *image, int width, int height)
 }
 
 NK_API void
-nk_glfw3_render(enum nk_anti_aliasing AA, int max_vertex_buffer, int max_element_buffer)
+nk_glfw3_render(enum nk_anti_aliasing AA)
 {
     /* setup global state */
     struct nk_glfw_device *dev = &glfw.ogl;
@@ -200,7 +209,24 @@ NK_API void
 nk_gflw3_scroll_callback(GLFWwindow *win, double xoff, double yoff)
 {
     (void)win; (void)xoff;
-    glfw.scroll += (float)yoff;
+    glfw.scroll.x += (float)xoff;
+    glfw.scroll.y += (float)yoff;
+}
+
+NK_API void
+nk_glfw3_mouse_button_callback(GLFWwindow* window, int button, int action, int mods)
+{
+    double x, y;
+    if (button != GLFW_MOUSE_BUTTON_LEFT) return;
+    glfwGetCursorPos(window, &x, &y);
+    if (action == GLFW_PRESS)  {
+        double dt = glfwGetTime() - glfw.last_button_click;
+        if (dt > NK_GLFW_DOUBLE_CLICK_LO && dt < NK_GLFW_DOUBLE_CLICK_HI) {
+            glfw.is_double_click_down = nk_true;
+            glfw.double_click_pos = nk_vec2(x, y);
+        }
+        glfw.last_button_click = glfwGetTime();
+    } else glfw.is_double_click_down = nk_false;
 }
 
 NK_INTERN void
@@ -232,13 +258,17 @@ nk_glfw3_init(GLFWwindow *win, enum nk_glfw_init_state init_state)
     if (init_state == NK_GLFW3_INSTALL_CALLBACKS) {
         glfwSetScrollCallback(win, nk_gflw3_scroll_callback);
         glfwSetCharCallback(win, nk_glfw3_char_callback);
+        glfwSetMouseButtonCallback(win, nk_glfw3_mouse_button_callback);
     }
-
     nk_init_default(&glfw.ctx, 0);
     glfw.ctx.clip.copy = nk_glfw3_clipbard_copy;
     glfw.ctx.clip.paste = nk_glfw3_clipbard_paste;
     glfw.ctx.clip.userdata = nk_handle_ptr(0);
     nk_buffer_init_default(&glfw.ogl.cmds);
+
+    glfw.is_double_click_down = nk_false;
+    glfw.double_click_pos = nk_vec2(0, 0);
+
     return &glfw.ctx;
 }
 
@@ -330,10 +360,11 @@ nk_glfw3_new_frame(void)
     nk_input_button(ctx, NK_BUTTON_LEFT, (int)x, (int)y, glfwGetMouseButton(win, GLFW_MOUSE_BUTTON_LEFT) == GLFW_PRESS);
     nk_input_button(ctx, NK_BUTTON_MIDDLE, (int)x, (int)y, glfwGetMouseButton(win, GLFW_MOUSE_BUTTON_MIDDLE) == GLFW_PRESS);
     nk_input_button(ctx, NK_BUTTON_RIGHT, (int)x, (int)y, glfwGetMouseButton(win, GLFW_MOUSE_BUTTON_RIGHT) == GLFW_PRESS);
+    nk_input_button(ctx, NK_BUTTON_DOUBLE, glfw.double_click_pos.x, glfw.double_click_pos.y, glfw.is_double_click_down);
     nk_input_scroll(ctx, glfw.scroll);
     nk_input_end(&glfw.ctx);
     glfw.text_len = 0;
-    glfw.scroll = 0;
+    glfw.scroll = nk_vec2(0,0);
 }
 
 NK_API

+ 43 - 7
demo/glfw_opengl3/nuklear_glfw_gl3.h

@@ -32,6 +32,7 @@ NK_API void                 nk_glfw3_device_create(void);
 
 NK_API void                 nk_glfw3_char_callback(GLFWwindow *win, unsigned int codepoint);
 NK_API void                 nk_gflw3_scroll_callback(GLFWwindow *win, double xoff, double yoff);
+NK_API void                 nk_glfw3_mouse_button_callback(GLFWwindow *win, int button, int action, int mods);
 
 #endif
 /*
@@ -46,6 +47,12 @@ NK_API void                 nk_gflw3_scroll_callback(GLFWwindow *win, double xof
 #ifndef NK_GLFW_TEXT_MAX
 #define NK_GLFW_TEXT_MAX 256
 #endif
+#ifndef NK_GLFW_DOUBLE_CLICK_LO
+#define NK_GLFW_DOUBLE_CLICK_LO 0.02
+#endif
+#ifndef NK_GLFW_DOUBLE_CLICK_HI
+#define NK_GLFW_DOUBLE_CLICK_HI 0.2
+#endif
 
 struct nk_glfw_device {
     struct nk_buffer cmds;
@@ -78,7 +85,10 @@ static struct nk_glfw {
     struct nk_vec2 fb_scale;
     unsigned int text[NK_GLFW_TEXT_MAX];
     int text_len;
-    float scroll;
+    struct nk_vec2 scroll;
+    double last_button_click;
+    int is_double_click_down;
+    struct nk_vec2 double_click_pos;
 } glfw;
 
 #ifdef __APPLE__
@@ -201,6 +211,7 @@ NK_API void
 nk_glfw3_render(enum nk_anti_aliasing AA, int max_vertex_buffer, int max_element_buffer)
 {
     struct nk_glfw_device *dev = &glfw.ogl;
+    struct nk_buffer vbuf, ebuf;
     GLfloat ortho[4][4] = {
         {2.0f, 0.0f, 0.0f, 0.0f},
         {0.0f,-2.0f, 0.0f, 0.0f},
@@ -263,10 +274,9 @@ nk_glfw3_render(enum nk_anti_aliasing AA, int max_vertex_buffer, int max_element
             config.line_AA = AA;
 
             /* setup buffers to load vertices and elements */
-            {struct nk_buffer vbuf, ebuf;
             nk_buffer_init_fixed(&vbuf, vertices, (size_t)max_vertex_buffer);
             nk_buffer_init_fixed(&ebuf, elements, (size_t)max_element_buffer);
-            nk_convert(&glfw.ctx, &dev->cmds, &vbuf, &ebuf, &config);}
+            nk_convert(&glfw.ctx, &dev->cmds, &vbuf, &ebuf, &config);
         }
         glUnmapBuffer(GL_ARRAY_BUFFER);
         glUnmapBuffer(GL_ELEMENT_ARRAY_BUFFER);
@@ -308,7 +318,24 @@ NK_API void
 nk_gflw3_scroll_callback(GLFWwindow *win, double xoff, double yoff)
 {
     (void)win; (void)xoff;
-    glfw.scroll += (float)yoff;
+    glfw.scroll.x += (float)xoff;
+    glfw.scroll.y += (float)yoff;
+}
+
+NK_API void
+nk_glfw3_mouse_button_callback(GLFWwindow* window, int button, int action, int mods)
+{
+    double x, y;
+    if (button != GLFW_MOUSE_BUTTON_LEFT) return;
+    glfwGetCursorPos(window, &x, &y);
+    if (action == GLFW_PRESS)  {
+        double dt = glfwGetTime() - glfw.last_button_click;
+        if (dt > NK_GLFW_DOUBLE_CLICK_LO && dt < NK_GLFW_DOUBLE_CLICK_HI) {
+            glfw.is_double_click_down = nk_true;
+            glfw.double_click_pos = nk_vec2(x, y);
+        }
+        glfw.last_button_click = glfwGetTime();
+    } else glfw.is_double_click_down = nk_false;
 }
 
 NK_INTERN void
@@ -340,13 +367,18 @@ nk_glfw3_init(GLFWwindow *win, enum nk_glfw_init_state init_state)
     if (init_state == NK_GLFW3_INSTALL_CALLBACKS) {
         glfwSetScrollCallback(win, nk_gflw3_scroll_callback);
         glfwSetCharCallback(win, nk_glfw3_char_callback);
+        glfwSetMouseButtonCallback(win, nk_glfw3_mouse_button_callback);
     }
-
     nk_init_default(&glfw.ctx, 0);
     glfw.ctx.clip.copy = nk_glfw3_clipbard_copy;
     glfw.ctx.clip.paste = nk_glfw3_clipbard_paste;
     glfw.ctx.clip.userdata = nk_handle_ptr(0);
+    glfw.last_button_click = 0;
     nk_glfw3_device_create();
+
+    glfw.is_double_click_down = nk_false;
+    glfw.double_click_pos = nk_vec2(0, 0);
+
     return &glfw.ctx;
 }
 
@@ -386,11 +418,13 @@ nk_glfw3_new_frame(void)
     for (i = 0; i < glfw.text_len; ++i)
         nk_input_unicode(ctx, glfw.text[i]);
 
+#if NK_GLFW_GL3_MOUSE_GRABBING
     /* optional grabbing behavior */
     if (ctx->input.mouse.grab)
         glfwSetInputMode(glfw.win, GLFW_CURSOR, GLFW_CURSOR_HIDDEN);
     else if (ctx->input.mouse.ungrab)
         glfwSetInputMode(glfw.win, GLFW_CURSOR, GLFW_CURSOR_NORMAL);
+#endif
 
     nk_input_key(ctx, NK_KEY_DEL, glfwGetKey(win, GLFW_KEY_DELETE) == GLFW_PRESS);
     nk_input_key(ctx, NK_KEY_ENTER, glfwGetKey(win, GLFW_KEY_ENTER) == GLFW_PRESS);
@@ -429,19 +463,21 @@ nk_glfw3_new_frame(void)
 
     glfwGetCursorPos(win, &x, &y);
     nk_input_motion(ctx, (int)x, (int)y);
+#if NK_GLFW_GL3_MOUSE_GRABBING
     if (ctx->input.mouse.grabbed) {
         glfwSetCursorPos(glfw.win, ctx->input.mouse.prev.x, ctx->input.mouse.prev.y);
         ctx->input.mouse.pos.x = ctx->input.mouse.prev.x;
         ctx->input.mouse.pos.y = ctx->input.mouse.prev.y;
     }
-
+#endif
     nk_input_button(ctx, NK_BUTTON_LEFT, (int)x, (int)y, glfwGetMouseButton(win, GLFW_MOUSE_BUTTON_LEFT) == GLFW_PRESS);
     nk_input_button(ctx, NK_BUTTON_MIDDLE, (int)x, (int)y, glfwGetMouseButton(win, GLFW_MOUSE_BUTTON_MIDDLE) == GLFW_PRESS);
     nk_input_button(ctx, NK_BUTTON_RIGHT, (int)x, (int)y, glfwGetMouseButton(win, GLFW_MOUSE_BUTTON_RIGHT) == GLFW_PRESS);
+    nk_input_button(ctx, NK_BUTTON_DOUBLE, glfw.double_click_pos.x, glfw.double_click_pos.y, glfw.is_double_click_down);
     nk_input_scroll(ctx, glfw.scroll);
     nk_input_end(&glfw.ctx);
     glfw.text_len = 0;
-    glfw.scroll = 0;
+    glfw.scroll = nk_vec2(0,0);
 }
 
 NK_API

+ 1 - 4
demo/sdl_opengl2/main.c

@@ -28,9 +28,6 @@
 #define WINDOW_WIDTH 1200
 #define WINDOW_HEIGHT 800
 
-#define MAX_VERTEX_MEMORY 512 * 1024
-#define MAX_ELEMENT_MEMORY 128 * 1024
-
 #define UNUSED(a) (void)a
 #define MIN(a,b) ((a) < (b) ? (a) : (b))
 #define MAX(a,b) ((a) < (b) ? (b) : (a))
@@ -167,7 +164,7 @@ main(int argc, char* argv[])
          * defaults everything back into a default state.
          * Make sure to either a.) save and restore or b.) reset your own state after
          * rendering the UI. */
-        nk_sdl_render(NK_ANTI_ALIASING_ON, MAX_VERTEX_MEMORY, MAX_ELEMENT_MEMORY);
+        nk_sdl_render(NK_ANTI_ALIASING_ON);
         SDL_GL_SwapWindow(win);}
     }
 

+ 12 - 7
demo/sdl_opengl2/nuklear_sdl_gl2.h

@@ -1,7 +1,7 @@
 /*
  * Nuklear - 1.32.0 - public domain
  * no warrenty implied; use at your own risk.
- * authored from 2015-2016 by Micha Mettke
+ * authored from 2015-2017 by Micha Mettke
  */
 /*
  * ==============================================================
@@ -18,7 +18,7 @@ NK_API struct nk_context*   nk_sdl_init(SDL_Window *win);
 NK_API void                 nk_sdl_font_stash_begin(struct nk_font_atlas **atlas);
 NK_API void                 nk_sdl_font_stash_end(void);
 NK_API int                  nk_sdl_handle_event(SDL_Event *evt);
-NK_API void                 nk_sdl_render(enum nk_anti_aliasing , int max_vertex_buffer, int max_element_buffer);
+NK_API void                 nk_sdl_render(enum nk_anti_aliasing);
 NK_API void                 nk_sdl_shutdown(void);
 
 #endif
@@ -63,7 +63,7 @@ nk_sdl_device_upload_atlas(const void *image, int width, int height)
 }
 
 NK_API void
-nk_sdl_render(enum nk_anti_aliasing AA, int max_vertex_buffer, int max_element_buffer)
+nk_sdl_render(enum nk_anti_aliasing AA)
 {
     /* setup global state */
     struct nk_sdl_device *dev = &sdl.ogl;
@@ -302,27 +302,32 @@ nk_sdl_handle_event(SDL_Event *evt)
         /* mouse button */
         int down = evt->type == SDL_MOUSEBUTTONDOWN;
         const int x = evt->button.x, y = evt->button.y;
-        if (evt->button.button == SDL_BUTTON_LEFT)
+        if (evt->button.button == SDL_BUTTON_LEFT) {
+            if (evt->button.clicks > 1)
+                nk_input_button(ctx, NK_BUTTON_DOUBLE, x, y, down);
             nk_input_button(ctx, NK_BUTTON_LEFT, x, y, down);
-        if (evt->button.button == SDL_BUTTON_MIDDLE)
+        } else if (evt->button.button == SDL_BUTTON_MIDDLE)
             nk_input_button(ctx, NK_BUTTON_MIDDLE, x, y, down);
-        if (evt->button.button == SDL_BUTTON_RIGHT)
+        else if (evt->button.button == SDL_BUTTON_RIGHT)
             nk_input_button(ctx, NK_BUTTON_RIGHT, x, y, down);
         else return 0;
         return 1;
     } else if (evt->type == SDL_MOUSEMOTION) {
+        /* mouse motion */
         if (ctx->input.mouse.grabbed) {
             int x = (int)ctx->input.mouse.prev.x, y = (int)ctx->input.mouse.prev.y;
             nk_input_motion(ctx, x + evt->motion.xrel, y + evt->motion.yrel);
         } else nk_input_motion(ctx, evt->motion.x, evt->motion.y);
         return 1;
     } else if (evt->type == SDL_TEXTINPUT) {
+        /* text input */
         nk_glyph glyph;
         memcpy(glyph, evt->text.text, NK_UTF_SIZE);
         nk_input_glyph(ctx, glyph);
         return 1;
     } else if (evt->type == SDL_MOUSEWHEEL) {
-        nk_input_scroll(ctx,(float)evt->wheel.y);
+        /* mouse wheel */
+        nk_input_scroll(ctx,nk_vec2((float)evt->wheel.x,(float)evt->wheel.y));
         return 1;
     }
     return 0;

+ 9 - 4
demo/sdl_opengl3/nuklear_sdl_gl3.h

@@ -400,26 +400,31 @@ nk_sdl_handle_event(SDL_Event *evt)
         /* mouse button */
         int down = evt->type == SDL_MOUSEBUTTONDOWN;
         const int x = evt->button.x, y = evt->button.y;
-        if (evt->button.button == SDL_BUTTON_LEFT)
+        if (evt->button.button == SDL_BUTTON_LEFT) {
+            if (evt->button.clicks > 1)
+                nk_input_button(ctx, NK_BUTTON_DOUBLE, x, y, down);
             nk_input_button(ctx, NK_BUTTON_LEFT, x, y, down);
-        if (evt->button.button == SDL_BUTTON_MIDDLE)
+        } else if (evt->button.button == SDL_BUTTON_MIDDLE)
             nk_input_button(ctx, NK_BUTTON_MIDDLE, x, y, down);
-        if (evt->button.button == SDL_BUTTON_RIGHT)
+        else if (evt->button.button == SDL_BUTTON_RIGHT)
             nk_input_button(ctx, NK_BUTTON_RIGHT, x, y, down);
         return 1;
     } else if (evt->type == SDL_MOUSEMOTION) {
+        /* mouse motion */
         if (ctx->input.mouse.grabbed) {
             int x = (int)ctx->input.mouse.prev.x, y = (int)ctx->input.mouse.prev.y;
             nk_input_motion(ctx, x + evt->motion.xrel, y + evt->motion.yrel);
         } else nk_input_motion(ctx, evt->motion.x, evt->motion.y);
         return 1;
     } else if (evt->type == SDL_TEXTINPUT) {
+        /* text input */
         nk_glyph glyph;
         memcpy(glyph, evt->text.text, NK_UTF_SIZE);
         nk_input_glyph(ctx, glyph);
         return 1;
     } else if (evt->type == SDL_MOUSEWHEEL) {
-        nk_input_scroll(ctx,(float)evt->wheel.y);
+        /* mouse wheel */
+        nk_input_scroll(ctx,nk_vec2((float)evt->wheel.x,(float)evt->wheel.y));
         return 1;
     }
     return 0;

+ 29 - 0
demo/sfml_opengl2/Makefile

@@ -0,0 +1,29 @@
+# Install
+CC = g++
+BIN = demo
+
+# Flags
+CFLAGS = -s -O2
+
+SRC = main.cpp
+OBJ = $(SRC:.cpp=.o)
+
+# TODO: Mac Build
+ifeq ($(OS),Windows_NT)
+	# Edit the line below to point to your SFML folder on Windows
+	SFML_DIR = C:/Users/Ricky/MinGW-Libs/SFML
+
+	BIN := $(BIN).exe
+	LIBS = -lmingw32 -DSFML_STATIC -lsfml-window-s -lsfml-system-s -lopengl32 -lwinmm -lgdi32
+else
+	# Edit the line below to point to your SFML folder on Linux
+	SFML_DIR = /home/ricky/Libraries/SFML
+
+	LIBS = -DSFML_STATIC -lsfml-window-s -lsfml-system-s -pthread -ludev -lGL -lX11 -lXrandr
+endif
+
+SFML_INC = -I $(SFML_DIR)/include
+SFML_LIB = -L $(SFML_DIR)/lib
+
+$(BIN):
+	$(CC) $(SRC) $(CFLAGS) -o $(BIN) $(SFML_INC) $(SFML_LIB) $(LIBS)

+ 9 - 0
demo/sfml_opengl2/Readme.md

@@ -0,0 +1,9 @@
+# SFML 2.4 nuklear backend
+
+This backend provides support for [SFML 2.4](http://www.sfml-dev.org). It will work on all platforms supported by SFML.
+
+## Compiling
+
+You have to edit the Makefile provided so that you can build the demo. Edit the SFML_DIR variable to point to your SFML root folder. This will be the folder to which SFML was installed and contains the lib and include folders.
+
+On Linux there is an extra step. You need to install the the udev development files.

+ 159 - 0
demo/sfml_opengl2/main.cpp

@@ -0,0 +1,159 @@
+/* nuklear - v1.32.0 - public domain */
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <stdarg.h>
+#include <string.h>
+#include <math.h>
+#include <assert.h>
+#include <math.h>
+#include <limits.h>
+#include <time.h>
+
+#include <SFML/OpenGL.hpp>
+#include <SFML/Window.hpp>
+
+#define NK_INCLUDE_FIXED_TYPES
+#define NK_INCLUDE_STANDARD_IO
+#define NK_INCLUDE_STANDARD_VARARGS
+#define NK_INCLUDE_DEFAULT_ALLOCATOR
+#define NK_INCLUDE_VERTEX_BUFFER_OUTPUT
+#define NK_INCLUDE_FONT_BAKING
+#define NK_INCLUDE_DEFAULT_FONT
+#define NK_IMPLEMENTATION
+#define NK_SFML_GL2_IMPLEMENTATION
+#include "../../nuklear.h"
+#include "nuklear_sfml_gl2.h"
+
+#define WINDOW_WIDTH 1200
+#define WINDOW_HEIGHT 800
+
+#define UNUSED(a) (void)a
+#define MIN(a,b) ((a) < (b) ? (a) : (b))
+#define MAX(a,b) ((a) < (b) ? (b) : (a))
+#define LEN(a) (sizeof(a)/sizeof(a)[0])
+
+/* ===============================================================
+ *
+ *                          EXAMPLE
+ *
+ * ===============================================================*/
+/* This are some code examples to provide a small overview of what can be
+ * done with this library. To try out an example uncomment the include
+ * and the corresponding function. */
+/*#include "../style.c"*/
+/*#include "../calculator.c"*/
+/*#include "../overview.c"*/
+/*#include "../node_editor.c"*/
+
+/* ===============================================================
+ *
+ *                          DEMO
+ *
+ * ===============================================================*/
+int main(void)
+{
+    /* Platform */
+    sf::ContextSettings settings(24, 8, 4, 2, 2);
+    sf::Window win(sf::VideoMode(WINDOW_WIDTH, WINDOW_HEIGHT), "Demo", sf::Style::Default, settings);
+    win.setVerticalSyncEnabled(true);
+    win.setActive(true);
+    glViewport(0, 0, win.getSize().x, win.getSize().y);
+
+    /* GUI */
+    struct nk_context *ctx;
+    ctx = nk_sfml_init(&win);
+    /* Load Fonts: if none of these are loaded a default font will be used  */
+    /* Load Cursor: if you uncomment cursor loading please hide the cursor */
+    struct nk_font_atlas *atlas;
+    nk_sfml_font_stash_begin(&atlas);
+    /*struct nk_font *droid = nk_font_atlas_add_from_file(atlas, "../../../extra_font/DroidSans.ttf", 14, 0);*/
+    /*struct nk_font *roboto = nk_font_atlas_add_from_file(atlas, "../../../extra_font/Roboto-Regular.ttf", 14, 0);*/
+    /*struct nk_font *future = nk_font_atlas_add_from_file(atlas, "../../../extra_font/kenvector_future_thin.ttf", 13, 0);*/
+    /*struct nk_font *clean = nk_font_atlas_add_from_file(atlas, "../../../extra_font/ProggyClean.ttf", 12, 0);*/
+    /*struct nk_font *tiny = nk_font_atlas_add_from_file(atlas, "../../../extra_font/ProggyTiny.ttf", 10, 0);*/
+    /*struct nk_font *cousine = nk_font_atlas_add_from_file(atlas, "../../../extra_font/Cousine-Regular.ttf", 13, 0);*/
+    nk_sfml_font_stash_end();
+    /*nk_style_load_all_cursors(ctx, atlas->cursors);*/
+    /*nk_style_set_font(ctx, &droid->handle);*/
+
+    /* style.c */
+    /*set_style(ctx, THEME_WHITE);*/
+    /*set_style(ctx, THEME_RED);*/
+    /*set_style(ctx, THEME_BLUE);*/
+    /*set_style(ctx, THEME_DARK);*/
+
+    struct nk_color background;
+    background = nk_rgb(28,48,62);
+    while (win.isOpen())
+    {
+        /* Input */
+        sf::Event evt;
+        nk_input_begin(ctx);
+        while(win.pollEvent(evt)) {
+            if(evt.type == sf::Event::Closed)
+                win.close();
+            else if(evt.type == sf::Event::Resized)
+                glViewport(0, 0, evt.size.width, evt.size.height);
+            nk_sfml_handle_event(&evt);
+        }
+        nk_input_end(ctx);
+
+        /* GUI */
+        if (nk_begin(ctx, "Demo", nk_rect(50, 50, 230, 250),
+            NK_WINDOW_BORDER|NK_WINDOW_MOVABLE|NK_WINDOW_SCALABLE|
+            NK_WINDOW_MINIMIZABLE|NK_WINDOW_TITLE))
+        {
+            enum {EASY, HARD};
+            static int op = EASY;
+            static int property = 20;
+            nk_layout_row_static(ctx, 30, 80, 1);
+            if (nk_button_label(ctx, "button"))
+                fprintf(stdout, "button pressed\n");
+
+            nk_layout_row_dynamic(ctx, 30, 2);
+            if (nk_option_label(ctx, "easy", op == EASY)) op = EASY;
+            if (nk_option_label(ctx, "hard", op == HARD)) op = HARD;
+
+            nk_layout_row_dynamic(ctx, 25, 1);
+            nk_property_int(ctx, "Compression:", 0, &property, 100, 10, 1);
+
+            nk_layout_row_dynamic(ctx, 20, 1);
+            nk_label(ctx, "background:", NK_TEXT_LEFT);
+            nk_layout_row_dynamic(ctx, 25, 1);
+            if (nk_combo_begin_color(ctx, background, nk_vec2(nk_widget_width(ctx),400))) {
+                nk_layout_row_dynamic(ctx, 120, 1);
+                background = nk_color_picker(ctx, background, NK_RGBA);
+                nk_layout_row_dynamic(ctx, 25, 1);
+                background.r = (nk_byte)nk_propertyi(ctx, "#R:", 0, background.r, 255, 1,1);
+                background.g = (nk_byte)nk_propertyi(ctx, "#G:", 0, background.g, 255, 1,1);
+                background.b = (nk_byte)nk_propertyi(ctx, "#B:", 0, background.b, 255, 1,1);
+                background.a = (nk_byte)nk_propertyi(ctx, "#A:", 0, background.a, 255, 1,1);
+                nk_combo_end(ctx);
+            }
+        }
+        nk_end(ctx);
+
+        /* -------------- EXAMPLES ---------------- */
+        /*calculator(ctx);*/
+        /*overview(ctx);*/
+        /*node_editor(ctx);*/
+        /* ----------------------------------------- */
+
+        /* Draw */
+        float bg[4];
+        win.setActive(true);
+        nk_color_fv(bg, background);
+        glClear(GL_COLOR_BUFFER_BIT);
+        glClearColor(bg[0], bg[1], bg[2], bg[3]);
+        /* IMPORTANT: `nk_sfml_render` modifies some global OpenGL state
+        * with blending, scissor, face culling and depth test and defaults everything
+        * back into a default state. Make sure to either save and restore or
+        * reset your own state after drawing rendering the UI. */
+        nk_sfml_render(NK_ANTI_ALIASING_ON);
+        win.display();
+    }
+    nk_sfml_shutdown();
+    return 0;
+}
+

+ 354 - 0
demo/sfml_opengl2/nuklear_sfml_gl2.h

@@ -0,0 +1,354 @@
+/*
+ * Nuklear - 1.32.0 - public domain
+ * no warrenty implied; use at your own risk.
+ * authored from 2015-2016 by Micha Mettke
+ */
+/*
+ * ==============================================================
+ *
+ *                              API
+ *
+ * ===============================================================
+ */
+#ifndef NK_SFML_GL2_H_
+#define NK_SFML_GL2_H_
+
+#include <SFML/Window.hpp>
+
+NK_API struct nk_context*   nk_sfml_init(sf::Window* window);
+NK_API void                 nk_sfml_font_stash_begin(struct nk_font_atlas** atlas);
+NK_API void                 nk_sfml_font_stash_end(void);
+NK_API int                  nk_sfml_handle_event(sf::Event* event);
+NK_API void                 nk_sfml_render(enum nk_anti_aliasing);
+NK_API void                 nk_sfml_shutdown(void);
+
+#endif
+/*
+ * ==============================================================
+ *
+ *                          IMPLEMENTATION
+ *
+ * ===============================================================
+ */
+ #ifdef NK_SFML_GL2_IMPLEMENTATION
+
+struct nk_sfml_device {
+    struct nk_buffer cmds;
+    struct nk_draw_null_texture null;
+    GLuint font_tex;
+};
+
+struct nk_sfml_vertex {
+    float position[2];
+    float uv[2];
+    nk_byte col[4];
+};
+
+static struct nk_sfml {
+    sf::Window* window;
+    struct nk_sfml_device ogl;
+    struct nk_context ctx;
+    struct nk_font_atlas atlas;
+} sfml;
+
+NK_INTERN void
+nk_sfml_device_upload_atlas(const void* image, int width, int height)
+{
+    struct nk_sfml_device* dev = &sfml.ogl;
+    glGenTextures(1, &dev->font_tex);
+    glBindTexture(GL_TEXTURE_2D, dev->font_tex);
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, (GLsizei)width, (GLsizei)height, 0, 
+                GL_RGBA, GL_UNSIGNED_BYTE, image);
+}
+
+NK_API void
+nk_sfml_render(enum nk_anti_aliasing AA)
+{
+    /* setup global state */
+    struct nk_sfml_device* dev = &sfml.ogl;
+
+    int window_width = sfml.window->getSize().x;
+    int window_height = sfml.window->getSize().y;
+
+    glPushAttrib(GL_ENABLE_BIT | GL_COLOR_BUFFER_BIT | GL_TRANSFORM_BIT);
+    glDisable(GL_CULL_FACE);
+    glDisable(GL_DEPTH_TEST);
+    glEnable(GL_SCISSOR_TEST);
+    glEnable(GL_BLEND);
+    glEnable(GL_TEXTURE_2D);
+    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+
+    glViewport(0, 0, (GLsizei)window_width, (GLsizei)window_height);
+    glMatrixMode(GL_PROJECTION);
+    glPushMatrix();
+    glLoadIdentity();
+    glOrtho(0.0f, window_width, window_height, 0.0f, -1.0f, 1.0f);
+    glMatrixMode(GL_MODELVIEW);
+    glPushMatrix();
+    glLoadIdentity();
+
+    glEnableClientState(GL_VERTEX_ARRAY);
+    glEnableClientState(GL_TEXTURE_COORD_ARRAY);
+    glEnableClientState(GL_COLOR_ARRAY);
+    {
+        GLsizei vs = sizeof(struct nk_sfml_vertex);
+        size_t vp = offsetof(struct nk_sfml_vertex, position);
+        size_t vt = offsetof(struct nk_sfml_vertex, uv);
+        size_t vc = offsetof(struct nk_sfml_vertex, col);
+
+        /* convert from command queue into draw  list and draw to screen */
+        const struct nk_draw_command* cmd;
+        const nk_draw_index* offset = NULL;
+        struct nk_buffer vbuf, ebuf;
+
+        /* fill converting configuration */
+        struct nk_convert_config config;
+        static const struct nk_draw_vertex_layout_element vertex_layout[] = {
+            {NK_VERTEX_POSITION, NK_FORMAT_FLOAT, NK_OFFSETOF(struct nk_sfml_vertex, position)},
+            {NK_VERTEX_TEXCOORD, NK_FORMAT_FLOAT, NK_OFFSETOF(struct nk_sfml_vertex, uv)},
+            {NK_VERTEX_COLOR, NK_FORMAT_R8G8B8A8, NK_OFFSETOF(struct nk_sfml_vertex, col)},
+            {NK_VERTEX_LAYOUT_END}
+        };
+        NK_MEMSET(&config, 0, sizeof(config));
+        config.vertex_layout = vertex_layout;
+        config.vertex_size = sizeof(struct nk_sfml_vertex);
+        config.vertex_alignment = NK_ALIGNOF(struct nk_sfml_vertex);
+        config.null = dev->null;
+        config.circle_segment_count = 22;
+        config.curve_segment_count = 22;
+        config.arc_segment_count = 22;
+        config.global_alpha = 1.0f;
+        config.shape_AA = AA;
+        config.line_AA = AA;
+
+        /* convert shapes into vertices */
+        nk_buffer_init_default(&vbuf);
+        nk_buffer_init_default(&ebuf);
+        nk_convert(&sfml.ctx, &dev->cmds, &vbuf, &ebuf, &config);
+
+        /* setup vertex buffer pointer */
+        const void* vertices = nk_buffer_memory_const(&vbuf);
+        glVertexPointer(2, GL_FLOAT, vs, (const void*)((const nk_byte*)vertices + vp));
+        glTexCoordPointer(2, GL_FLOAT, vs, (const void*)((const nk_byte*)vertices + vt));
+        glColorPointer(4, GL_UNSIGNED_BYTE, vs, (const void*)((const nk_byte*)vertices + vc));
+
+        /* iterate over and execute each draw command */
+        offset = (const nk_draw_index*)nk_buffer_memory_const(&ebuf);
+        nk_draw_foreach(cmd, &sfml.ctx, &dev->cmds)
+        {
+            if(!cmd->elem_count) continue;
+            glBindTexture(GL_TEXTURE_2D, (GLuint)cmd->texture.id);
+            glScissor(
+                (GLint)(cmd->clip_rect.x),
+                (GLint)((window_height - (GLint)(cmd->clip_rect.y + cmd->clip_rect.h))),
+                (GLint)(cmd->clip_rect.w),
+                (GLint)(cmd->clip_rect.h));
+            glDrawElements(GL_TRIANGLES, (GLsizei)cmd->elem_count, GL_UNSIGNED_SHORT, offset);
+            offset += cmd->elem_count;
+        }
+        nk_clear(&sfml.ctx);
+        nk_buffer_free(&vbuf);
+        nk_buffer_free(&ebuf);
+    }
+
+    /* default OpenGL state */
+    glDisableClientState(GL_VERTEX_ARRAY);
+    glDisableClientState(GL_TEXTURE_COORD_ARRAY);
+    glDisableClientState(GL_COLOR_ARRAY);
+
+    glDisable(GL_CULL_FACE);
+    glDisable(GL_DEPTH_TEST);
+    glDisable(GL_SCISSOR_TEST);
+    glDisable(GL_BLEND);
+    glDisable(GL_TEXTURE_2D);
+
+    glBindTexture(GL_TEXTURE_2D, 0);
+    glMatrixMode(GL_MODELVIEW);
+    glPopMatrix();
+    glMatrixMode(GL_PROJECTION);
+    glPopMatrix();
+    glPopAttrib();
+}
+
+static void
+nk_sfml_clipboard_paste(nk_handle usr, struct nk_text_edit* edit)
+{
+#if 0
+    /* Not Implemented in SFML */
+    sf::Clipboard clipboard(sfml.window);
+    const char* text = clipboard.getText();
+
+    if(text)
+        nk_textedit_paste(edit, text, nk_strlen(text));
+        (void)usr;
+#endif
+}
+
+static void
+nk_sfml_clipboard_copy(nk_handle usr, const char* text, int len)
+{
+#if 0
+    char* str = 0;
+    (void)usr;
+    if(!len) return;
+    str = (char*)malloc((size_t)len+1);
+    if(!str) return;
+    memcpy(str, text, (size_t)len);
+    str[len] = '\0';
+
+    /* Not Implemented in SFML */
+    sf::Clipboard clipboard(sfml.window);
+    clipboard.setText(str);
+    free(str);
+#endif
+}
+
+NK_API struct nk_context*
+nk_sfml_init(sf::Window* window)
+{
+    sfml.window = window;
+    nk_init_default(&sfml.ctx, 0);
+    sfml.ctx.clip.copy = nk_sfml_clipboard_copy;
+    sfml.ctx.clip.paste = nk_sfml_clipboard_paste;
+    sfml.ctx.clip.userdata = nk_handle_ptr(0);
+    nk_buffer_init_default(&sfml.ogl.cmds);
+    return &sfml.ctx;
+}
+
+NK_API void
+nk_sfml_font_stash_begin(struct nk_font_atlas** atlas)
+{
+    nk_font_atlas_init_default(&sfml.atlas);
+    nk_font_atlas_begin(&sfml.atlas);
+    *atlas = &sfml.atlas;
+}
+
+NK_API void
+nk_sfml_font_stash_end()
+{
+    int w, h;
+    const void* img;
+    img = nk_font_atlas_bake(&sfml.atlas, &w, &h, NK_FONT_ATLAS_RGBA32);
+    nk_sfml_device_upload_atlas(img, w, h);
+    nk_font_atlas_end(&sfml.atlas, nk_handle_id((int)sfml.ogl.font_tex), &sfml.ogl.null);
+    if(sfml.atlas.default_font)
+        nk_style_set_font(&sfml.ctx, &sfml.atlas.default_font->handle);
+}
+
+NK_API int
+nk_sfml_handle_event(sf::Event* evt)
+{
+    struct nk_context* ctx = &sfml.ctx;
+    /* optional grabbing behavior */
+    if(ctx->input.mouse.grab)
+        ctx->input.mouse.grab = 0;
+    else if(ctx->input.mouse.ungrab) {
+        int x = (int)ctx->input.mouse.prev.x;
+        int y = (int)ctx->input.mouse.prev.y;
+        sf::Mouse::setPosition(sf::Vector2i(x, y), *sfml.window);
+        ctx->input.mouse.ungrab = 0;
+    }
+    if(evt->type == sf::Event::KeyReleased || evt->type == sf::Event::KeyPressed)
+    {
+        int down = evt->type == sf::Event::KeyPressed;
+        sf::Keyboard::Key key = evt->key.code;
+        if(key == sf::Keyboard::RShift || key == sf::Keyboard::LShift)
+            nk_input_key(ctx, NK_KEY_SHIFT, down);
+        else if(key == sf::Keyboard::Delete)
+            nk_input_key(ctx, NK_KEY_DEL, down);
+        else if(key == sf::Keyboard::Return)
+            nk_input_key(ctx, NK_KEY_ENTER, down);
+        else if(key == sf::Keyboard::Tab)
+            nk_input_key(ctx, NK_KEY_TAB, down);
+        else if(key == sf::Keyboard::BackSpace)
+            nk_input_key(ctx, NK_KEY_BACKSPACE, down);
+        else if(key == sf::Keyboard::Home) {
+            nk_input_key(ctx, NK_KEY_TEXT_START, down);
+            nk_input_key(ctx, NK_KEY_SCROLL_START, down);
+        } else if(key == sf::Keyboard::End) {
+            nk_input_key(ctx, NK_KEY_TEXT_END, down);
+            nk_input_key(ctx, NK_KEY_SCROLL_END, down);
+        } else if(key == sf::Keyboard::PageDown)
+            nk_input_key(ctx, NK_KEY_SCROLL_DOWN, down);
+        else if(key == sf::Keyboard::PageUp)
+            nk_input_key(ctx, NK_KEY_SCROLL_DOWN, down);
+        else if(key == sf::Keyboard::Z)
+            nk_input_key(ctx, NK_KEY_TEXT_UNDO, down && sf::Keyboard::isKeyPressed(sf::Keyboard::LControl));
+        else if(key == sf::Keyboard::R)
+            nk_input_key(ctx, NK_KEY_TEXT_REDO, down && sf::Keyboard::isKeyPressed(sf::Keyboard::LControl));
+        else if(key == sf::Keyboard::C)
+            nk_input_key(ctx, NK_KEY_COPY, down && sf::Keyboard::isKeyPressed(sf::Keyboard::LControl));
+        else if(key == sf::Keyboard::V)
+            nk_input_key(ctx, NK_KEY_PASTE, down && sf::Keyboard::isKeyPressed(sf::Keyboard::LControl));
+        else if(key == sf::Keyboard::X)
+            nk_input_key(ctx, NK_KEY_CUT, down && sf::Keyboard::isKeyPressed(sf::Keyboard::LControl));
+        else if(key == sf::Keyboard::B)
+            nk_input_key(ctx, NK_KEY_TEXT_LINE_START, down && sf::Keyboard::isKeyPressed(sf::Keyboard::LControl));
+        else if(key == sf::Keyboard::E)
+            nk_input_key(ctx, NK_KEY_TEXT_LINE_END, down && sf::Keyboard::isKeyPressed(sf::Keyboard::LControl));
+        else if(key == sf::Keyboard::Up)
+            nk_input_key(ctx, NK_KEY_UP, down);
+        else if(key == sf::Keyboard::Down)
+            nk_input_key(ctx, NK_KEY_DOWN, down);
+        else if(key == sf::Keyboard::Left) {
+            if(sf::Keyboard::isKeyPressed(sf::Keyboard::LControl))
+                nk_input_key(ctx, NK_KEY_TEXT_WORD_LEFT, down);
+            else nk_input_key(ctx, NK_KEY_LEFT, down);
+        } else if(key == sf::Keyboard::Right) {
+            if(sf::Keyboard::isKeyPressed(sf::Keyboard::LControl))
+                nk_input_key(ctx, NK_KEY_TEXT_WORD_RIGHT, down);
+            else nk_input_key(ctx, NK_KEY_RIGHT, down);
+        } else return 0;
+        return 1;
+    } else if(evt->type == sf::Event::MouseButtonPressed || evt->type == sf::Event::MouseButtonReleased) {
+        int down = evt->type == sf::Event::MouseButtonPressed;
+        const int x = evt->mouseButton.x, y = evt->mouseButton.y;
+        if(evt->mouseButton.button == sf::Mouse::Left)
+            nk_input_button(ctx, NK_BUTTON_LEFT, x, y, down);
+        if(evt->mouseButton.button == sf::Mouse::Middle)
+            nk_input_button(ctx, NK_BUTTON_MIDDLE, x, y, down);
+        if(evt->mouseButton.button == sf::Mouse::Right)
+            nk_input_button(ctx, NK_BUTTON_RIGHT, x, y, down);
+        else return 0;
+        return 1;
+    } else if(evt->type == sf::Event::MouseMoved) {
+        nk_input_motion(ctx, evt->mouseMove.x, evt->mouseMove.y);
+        return 1;
+    } else if(evt->type == sf::Event::TouchBegan || evt->type == sf::Event::TouchEnded) {
+        int down = evt->type == sf::Event::TouchBegan;
+        const int x = evt->touch.x, y = evt->touch.y;
+		ctx->input.mouse.pos.x = x;
+		ctx->input.mouse.pos.y = y;
+        nk_input_button(ctx, NK_BUTTON_LEFT, x, y, down);
+        return 1;
+    } else if(evt->type == sf::Event::TouchMoved) {
+        if(ctx->input.mouse.grabbed) {
+            int x = (int)ctx->input.mouse.prev.x;
+            int y = (int)ctx->input.mouse.prev.y;
+            nk_input_motion(ctx, x + evt->touch.x, y + evt->touch.y);
+        } else nk_input_motion(ctx, evt->touch.x, evt->touch.y);
+        return 1;
+    } else if(evt->type == sf::Event::TextEntered) {
+        nk_input_unicode(ctx, evt->text.unicode);
+        return 1;
+    } else if(evt->type == sf::Event::MouseWheelScrolled) {
+        nk_input_scroll(ctx, nk_vec2(0,evt->mouseWheelScroll.delta));
+        return 1;
+    }
+    return 0;
+}
+
+NK_API
+void nk_sfml_shutdown(void)
+{
+    struct nk_sfml_device* dev = &sfml.ogl;
+    nk_font_atlas_clear(&sfml.atlas);
+    nk_free(&sfml.ctx);
+    glDeleteTextures(1, &dev->font_tex);
+    nk_buffer_free(&dev->cmds);
+    memset(&sfml, 0, sizeof(sfml));
+}
+
+#endif

+ 33 - 0
demo/sfml_opengl3/Makefile

@@ -0,0 +1,33 @@
+# Install
+CC = g++
+BIN = demo
+
+# Flags
+CFLAGS = -s -O2
+
+SRC = main.cpp
+OBJ = $(SRC:.cpp=.o)
+
+# TODO: Mac Build
+ifeq ($(OS),Windows_NT)
+	# Edit the line below to point to your SFML/GLAD folder on Windows
+	SFML_DIR = C:/Users/Ricky/MinGW-Libs/SFML
+	GLAD_DIR = C:/Users/Ricky/MinGW-Libs/GLAD
+
+	BIN := $(BIN).exe
+	LIBS = -lmingw32 -DSFML_STATIC -lsfml-window-s -lsfml-system-s -lopengl32 -lwinmm -lgdi32
+else
+	# Edit the line below to point to your SFML/GLAD folder on Linux
+	SFML_DIR = /home/ricky/Libraries/SFML
+	GLAD_DIR = /home/ricky/Libraries/GLAD
+
+	LIBS = -DSFML_STATIC -lsfml-window-s -lsfml-system-s -pthread -ludev -lGL -lX11 -lXrandr
+endif
+
+SFML_INC = -I $(SFML_DIR)/include
+SFML_LIB = -L $(SFML_DIR)/lib
+GLAD_INC = -I $(GLAD_DIR)/include
+GLAD_SRC = $(GLAD_DIR)/src/glad.c
+
+$(BIN):
+	$(CC) $(GLAD_SRC) $(SRC) $(CFLAGS) $(GLAD_INC) $(SFML_INC) $(SFML_LIB) $(SFML_EXT) -o $(BIN) $(LIBS)

Diferenças do arquivo suprimidas por serem muito extensas
+ 6 - 0
demo/sfml_opengl3/Readme.md


+ 166 - 0
demo/sfml_opengl3/main.cpp

@@ -0,0 +1,166 @@
+/* nuklear - v1.32.0 - public domain */
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <stdarg.h>
+#include <string.h>
+#include <math.h>
+#include <assert.h>
+#include <math.h>
+#include <limits.h>
+#include <time.h>
+
+#include <SFML/Window.hpp>
+
+#define NK_INCLUDE_FIXED_TYPES
+#define NK_INCLUDE_STANDARD_IO
+#define NK_INCLUDE_STANDARD_VARARGS
+#define NK_INCLUDE_DEFAULT_ALLOCATOR
+#define NK_INCLUDE_VERTEX_BUFFER_OUTPUT
+#define NK_INCLUDE_FONT_BAKING
+#define NK_INCLUDE_DEFAULT_FONT
+#define NK_IMPLEMENTATION
+#define NK_SFML_GL3_IMPLEMENTATION
+#include "../../nuklear.h"
+#include "nuklear_sfml_gl3.h"
+
+#define WINDOW_WIDTH 1200
+#define WINDOW_HEIGHT 800
+
+#define MAX_VERTEX_BUFFER 512 * 1024
+#define MAX_ELEMENT_BUFFER 128 * 1024
+
+#define UNUSED(a) (void)a
+#define MIN(a,b) ((a) < (b) ? (a) : (b))
+#define MAX(a,b) ((a) < (b) ? (b) : (a))
+#define LEN(a) (sizeof(a)/sizeof(a)[0])
+
+/* ===============================================================
+ *
+ *                          EXAMPLE
+ *
+ * ===============================================================*/
+/* This are some code examples to provide a small overview of what can be
+ * done with this library. To try out an example uncomment the include
+ * and the corresponding function. */
+/*#include "../style.c"*/
+/*#include "../calculator.c"*/
+/*#include "../overview.c"*/
+/*#include "../node_editor.c"*/
+
+/* ===============================================================
+ *
+ *                          DEMO
+ *
+ * ===============================================================*/
+int main(void)
+{
+    /* Platform */
+    sf::ContextSettings settings(24, 8, 4, 3, 3);
+    sf::Window win(sf::VideoMode(WINDOW_WIDTH, WINDOW_HEIGHT), "Demo", sf::Style::Default, settings);
+    win.setVerticalSyncEnabled(true);
+    win.setActive(true);
+    if(!gladLoadGL()) { /* Load OpenGL extensions */
+        printf("Failed to load OpenGL extensions!\n");
+        return -1;
+    }
+    glViewport(0, 0, win.getSize().x, win.getSize().y);
+
+    /* GUI */
+    struct nk_context *ctx;
+    ctx = nk_sfml_init(&win);
+    /* Load Fonts: if none of these are loaded a default font will be used  */
+    /* Load Cursor: if you uncomment cursor loading please hide the cursor */
+    struct nk_font_atlas *atlas;
+    nk_sfml_font_stash_begin(&atlas);
+    /*struct nk_font *droid = nk_font_atlas_add_from_file(atlas, "../../../extra_font/DroidSans.ttf", 14, 0);*/
+    /*struct nk_font *roboto = nk_font_atlas_add_from_file(atlas, "../../../extra_font/Roboto-Regular.ttf", 14, 0);*/
+    /*struct nk_font *future = nk_font_atlas_add_from_file(atlas, "../../../extra_font/kenvector_future_thin.ttf", 13, 0);*/
+    /*struct nk_font *clean = nk_font_atlas_add_from_file(atlas, "../../../extra_font/ProggyClean.ttf", 12, 0);*/
+    /*struct nk_font *tiny = nk_font_atlas_add_from_file(atlas, "../../../extra_font/ProggyTiny.ttf", 10, 0);*/
+    /*struct nk_font *cousine = nk_font_atlas_add_from_file(atlas, "../../../extra_font/Cousine-Regular.ttf", 13, 0);*/
+    nk_sfml_font_stash_end();
+    /*nk_style_load_all_cursors(ctx, atlas->cursors);*/
+    /*nk_style_set_font(ctx, &droid->handle);*/
+
+    /* style.c */
+    /*set_style(ctx, THEME_WHITE);*/
+    /*set_style(ctx, THEME_RED);*/
+    /*set_style(ctx, THEME_BLUE);*/
+    /*set_style(ctx, THEME_DARK);*/
+
+    struct nk_color background;
+    background = nk_rgb(28,48,62);
+    while (win.isOpen())
+    {
+        /* Input */
+        sf::Event evt;
+        nk_input_begin(ctx);
+        while(win.pollEvent(evt)) {
+            if(evt.type == sf::Event::Closed)
+                win.close();
+            else if(evt.type == sf::Event::Resized)
+                glViewport(0, 0, evt.size.width, evt.size.height);
+
+            nk_sfml_handle_event(&evt);
+        }
+        nk_input_end(ctx);
+
+        /* GUI */
+        if (nk_begin(ctx, "Demo", nk_rect(50, 50, 230, 250),
+            NK_WINDOW_BORDER|NK_WINDOW_MOVABLE|NK_WINDOW_SCALABLE|
+            NK_WINDOW_MINIMIZABLE|NK_WINDOW_TITLE))
+        {
+            enum {EASY, HARD};
+            static int op = EASY;
+            static int property = 20;
+            nk_layout_row_static(ctx, 30, 80, 1);
+            if (nk_button_label(ctx, "button"))
+                fprintf(stdout, "button pressed\n");
+
+            nk_layout_row_dynamic(ctx, 30, 2);
+            if (nk_option_label(ctx, "easy", op == EASY)) op = EASY;
+            if (nk_option_label(ctx, "hard", op == HARD)) op = HARD;
+
+            nk_layout_row_dynamic(ctx, 25, 1);
+            nk_property_int(ctx, "Compression:", 0, &property, 100, 10, 1);
+
+            nk_layout_row_dynamic(ctx, 20, 1);
+            nk_label(ctx, "background:", NK_TEXT_LEFT);
+            nk_layout_row_dynamic(ctx, 25, 1);
+            if (nk_combo_begin_color(ctx, background, nk_vec2(nk_widget_width(ctx),400))) {
+                nk_layout_row_dynamic(ctx, 120, 1);
+                background = nk_color_picker(ctx, background, NK_RGBA);
+                nk_layout_row_dynamic(ctx, 25, 1);
+                background.r = (nk_byte)nk_propertyi(ctx, "#R:", 0, background.r, 255, 1,1);
+                background.g = (nk_byte)nk_propertyi(ctx, "#G:", 0, background.g, 255, 1,1);
+                background.b = (nk_byte)nk_propertyi(ctx, "#B:", 0, background.b, 255, 1,1);
+                background.a = (nk_byte)nk_propertyi(ctx, "#A:", 0, background.a, 255, 1,1);
+                nk_combo_end(ctx);
+            }
+        }
+        nk_end(ctx);
+
+        /* -------------- EXAMPLES ---------------- */
+        /*calculator(ctx);*/
+        /*overview(ctx);*/
+        /*node_editor(ctx);*/
+        /* ----------------------------------------- */
+
+        /* Draw */
+        float bg[4];
+        win.setActive(true);
+        nk_color_fv(bg, background);
+        glClear(GL_COLOR_BUFFER_BIT);
+        glClearColor(bg[0], bg[1], bg[2], bg[3]);
+        /* IMPORTANT: `nk_sfml_render` modifies some global OpenGL state
+        * with blending, scissor, face culling and depth test and defaults everything
+        * back into a default state. Make sure to either save and restore or
+        * reset your own state after drawing rendering the UI. */
+        nk_sfml_render(NK_ANTI_ALIASING_ON, MAX_VERTEX_BUFFER, MAX_ELEMENT_BUFFER);
+        win.display();
+    }
+    nk_sfml_shutdown();
+    return 0;
+}
+

+ 463 - 0
demo/sfml_opengl3/nuklear_sfml_gl3.h

@@ -0,0 +1,463 @@
+/*
+ * Nuklear - 1.32.0 - public domain
+ * no warrenty implied; use at your own risk.
+ * authored from 2015-2016 by Micha Mettke
+ */
+/*
+ * ==============================================================
+ *
+ *                              API
+ *
+ * ===============================================================
+ */
+#ifndef NK_SFML_GL3_H_
+#define NK_SFML_GL3_H_
+
+/* Feel free to edit here and include your own extension wrangler */
+#include <glad/glad.h>
+/* I use GLAD but you can use GLEW or what you like */
+
+#include <SFML/Window.hpp>
+
+NK_API struct nk_context*   nk_sfml_init(sf::Window* window);
+NK_API void                 nk_sfml_font_stash_begin(struct nk_font_atlas** atlas);
+NK_API void                 nk_sfml_font_stash_end(void);
+NK_API int                  nk_sfml_handle_event(sf::Event* event);
+NK_API void                 nk_sfml_render(enum nk_anti_aliasing, int max_vertex_buffer, int max_element_buffer);
+NK_API void                 nk_sfml_shutdown(void);
+
+NK_API void                 nk_sfml_device_create(void);
+NK_API void                 nk_sfml_device_destroy(void);
+
+#endif
+/*
+ * ==============================================================
+ *
+ *                          IMPLEMENTATION
+ *
+ * ===============================================================
+ */
+ #ifdef NK_SFML_GL3_IMPLEMENTATION
+
+#include <string>
+
+struct nk_sfml_device {
+    struct nk_buffer cmds;
+    struct nk_draw_null_texture null;
+    GLuint vbo, vao, ebo;
+    GLuint prog;
+    GLuint vert_shdr;
+    GLuint frag_shdr;
+    GLint attrib_pos;
+    GLint attrib_uv;
+    GLint attrib_col;
+    GLint uniform_tex;
+    GLint uniform_proj;
+    GLuint font_tex;
+};
+struct nk_sfml_vertex {
+    float position[2];
+    float uv[2];
+    nk_byte col[4];
+};
+static struct nk_sfml {
+    sf::Window* window;
+    struct nk_sfml_device ogl;
+    struct nk_context ctx;
+    struct nk_font_atlas atlas;
+} sfml;
+
+#ifdef __APPLE__
+  #define NK_SHADER_VERSION "#version 150\n"
+#else
+  #define NK_SHADER_VERSION "#version 300 es\n"
+#endif
+
+NK_API void
+nk_sfml_device_create(void)
+{
+    GLint status;
+    static const GLchar* vertex_shader =
+        NK_SHADER_VERSION
+        "uniform mat4 ProjMtx;\n"
+        "in vec2 Position;\n"
+        "in vec2 TexCoord;\n"
+        "in vec4 Color;\n"
+        "out vec2 Frag_UV;\n"
+        "out vec4 Frag_Color;\n"
+        "void main() {\n"
+        "   Frag_UV = TexCoord;\n"
+        "   Frag_Color = Color;\n"
+        "   gl_Position = ProjMtx * vec4(Position.xy, 0, 1);\n"
+        "}\n";
+    static const GLchar *fragment_shader =
+        NK_SHADER_VERSION
+        "precision mediump float;\n"
+        "uniform sampler2D Texture;\n"
+        "in vec2 Frag_UV;\n"
+        "in vec4 Frag_Color;\n"
+        "out vec4 Out_Color;\n"
+        "void main(){\n"
+        "   Out_Color = Frag_Color * texture(Texture, Frag_UV.st);\n"
+        "}\n";
+
+    struct nk_sfml_device* dev = &sfml.ogl;
+    nk_buffer_init_default(&dev->cmds);
+
+    dev->prog = glCreateProgram();
+    dev->vert_shdr = glCreateShader(GL_VERTEX_SHADER);
+    dev->frag_shdr = glCreateShader(GL_FRAGMENT_SHADER);
+
+    glShaderSource(dev->vert_shdr, 1, &vertex_shader, 0);
+    glShaderSource(dev->frag_shdr, 1, &fragment_shader, 0);
+    glCompileShader(dev->vert_shdr);
+    glCompileShader(dev->frag_shdr);
+
+    glGetShaderiv(dev->vert_shdr, GL_COMPILE_STATUS, &status);
+    assert(status == GL_TRUE);
+
+    glGetShaderiv(dev->frag_shdr, GL_COMPILE_STATUS, &status);
+    assert(status == GL_TRUE);
+
+    glAttachShader(dev->prog, dev->vert_shdr);
+    glAttachShader(dev->prog, dev->frag_shdr);
+    glLinkProgram(dev->prog);
+
+    glGetProgramiv(dev->prog, GL_LINK_STATUS, &status);
+    assert(status == GL_TRUE);
+
+    dev->uniform_tex = glGetUniformLocation(dev->prog, "Texture");
+    dev->uniform_proj = glGetUniformLocation(dev->prog, "ProjMtx");
+    dev->attrib_pos = glGetAttribLocation(dev->prog, "Position");
+    dev->attrib_uv = glGetAttribLocation(dev->prog, "TexCoord");
+    dev->attrib_col = glGetAttribLocation(dev->prog, "Color");
+    {
+        /* buffer setup */
+        GLsizei vs = sizeof(struct nk_sfml_vertex);
+        size_t vp = offsetof(struct nk_sfml_vertex, position);
+        size_t vt = offsetof(struct nk_sfml_vertex, uv);
+        size_t vc = offsetof(struct nk_sfml_vertex, col);
+
+        glGenBuffers(1, &dev->vbo);
+        glGenBuffers(1, &dev->ebo);
+        glGenVertexArrays(1, &dev->vao);
+
+        glBindVertexArray(dev->vao);
+        glBindBuffer(GL_ARRAY_BUFFER, dev->vbo);
+        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, dev->ebo);
+
+        glEnableVertexAttribArray((GLuint)dev->attrib_pos);
+        glEnableVertexAttribArray((GLuint)dev->attrib_uv);
+        glEnableVertexAttribArray((GLuint)dev->attrib_col);
+
+        glVertexAttribPointer((GLuint)dev->attrib_pos, 2, GL_FLOAT, GL_FALSE, vs, (void*)vp);
+        glVertexAttribPointer((GLuint)dev->attrib_uv, 2, GL_FLOAT, GL_FALSE, vs, (void*)vt);
+        glVertexAttribPointer((GLuint)dev->attrib_col, 4, GL_UNSIGNED_BYTE, GL_TRUE, vs, (void*)vc);
+    }
+    glBindTexture(GL_TEXTURE_2D, 0);
+    glBindBuffer(GL_ARRAY_BUFFER, 0);
+    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
+    glBindVertexArray(0);
+}
+
+NK_API void
+nk_sfml_device_destroy(void)
+{
+    struct nk_sfml_device* dev = &sfml.ogl;
+
+    glDetachShader(dev->prog, dev->vert_shdr);
+    glDetachShader(dev->prog, dev->frag_shdr);
+    glDeleteShader(dev->vert_shdr);
+    glDeleteShader(dev->vert_shdr);
+    glDeleteProgram(dev->prog);
+    glDeleteTextures(1, &dev->font_tex);
+    glDeleteBuffers(1, &dev->vbo);
+    glDeleteBuffers(1, &dev->ebo);
+    nk_buffer_free(&dev->cmds);
+}
+
+NK_INTERN void
+nk_sfml_device_upload_atlas(const void* image, int width, int height)
+{
+    struct nk_sfml_device* dev = &sfml.ogl;
+    glGenTextures(1, &dev->font_tex);
+    glBindTexture(GL_TEXTURE_2D, dev->font_tex);
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, (GLsizei)width, (GLsizei)height, 0,
+                GL_RGBA, GL_UNSIGNED_BYTE, image);
+}
+
+NK_API void
+nk_sfml_render(enum nk_anti_aliasing AA, int max_vertex_buffer, int max_element_buffer)
+{
+    /* setup global state */
+    struct nk_sfml_device* dev = &sfml.ogl;
+    int window_width = sfml.window->getSize().x;
+    int window_height = sfml.window->getSize().y;
+    GLfloat ortho[4][4] = {
+        {2.0f, 0.0f, 0.0f, 0.0f},
+        {0.0f,-2.0f, 0.0f, 0.0f},
+        {0.0f, 0.0f,-1.0f, 0.0f},
+        {-1.0f,1.0f, 0.0f, 1.0f},
+    };
+    ortho[0][0] /= (GLfloat)window_width;
+    ortho[1][1] /= (GLfloat)window_height;
+
+    glViewport(0, 0, window_width, window_height);
+    glEnable(GL_BLEND);
+    glBlendEquation(GL_FUNC_ADD);
+    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+    glDisable(GL_CULL_FACE);
+    glDisable(GL_DEPTH_TEST);
+    glEnable(GL_SCISSOR_TEST);
+    glActiveTexture(GL_TEXTURE0);
+
+    /* setup program */
+    glUseProgram(dev->prog);
+    glUniform1i(dev->uniform_tex, 0);
+    glUniformMatrix4fv(dev->uniform_proj, 1, GL_FALSE, &ortho[0][0]);
+    {
+        /* convert from command queue into draw list and draw to screen */
+        const struct nk_draw_command *cmd;
+        void *vertices, *elements;
+        const nk_draw_index *offset = NULL;
+
+        /* allocate vertex and element buffer */
+        glBindVertexArray(dev->vao);
+        glBindBuffer(GL_ARRAY_BUFFER, dev->vbo);
+        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, dev->ebo);
+
+        glBufferData(GL_ARRAY_BUFFER, max_vertex_buffer, NULL, GL_STREAM_DRAW);
+        glBufferData(GL_ELEMENT_ARRAY_BUFFER, max_element_buffer, NULL, GL_STREAM_DRAW);
+
+        /* load vertices/elements directly into vertex/element buffer */
+        vertices = glMapBuffer(GL_ARRAY_BUFFER, GL_WRITE_ONLY);
+        elements = glMapBuffer(GL_ELEMENT_ARRAY_BUFFER, GL_WRITE_ONLY);
+        {
+            /* fill convert configuration */
+            struct nk_convert_config config;
+            static const struct nk_draw_vertex_layout_element vertex_layout[] =  {
+                {NK_VERTEX_POSITION, NK_FORMAT_FLOAT, NK_OFFSETOF(struct nk_sfml_vertex, position)},
+                {NK_VERTEX_TEXCOORD, NK_FORMAT_FLOAT, NK_OFFSETOF(struct nk_sfml_vertex, uv)},
+                {NK_VERTEX_COLOR, NK_FORMAT_R8G8B8A8, NK_OFFSETOF(struct nk_sfml_vertex, col)},
+                {NK_VERTEX_LAYOUT_END}
+            };
+
+            NK_MEMSET(&config, 0, sizeof(config));
+            config.vertex_layout = vertex_layout;
+            config.vertex_size = sizeof(struct nk_sfml_vertex);
+            config.vertex_alignment = NK_ALIGNOF(struct nk_sfml_vertex);
+            config.null = dev->null;
+            config.circle_segment_count = 22;
+            config.curve_segment_count = 22;
+            config.arc_segment_count = 22;
+            config.global_alpha = 1.0f;
+            config.shape_AA = AA;
+            config.line_AA = AA;
+
+            /* setup buffers to load vertices and elements */
+            struct nk_buffer vbuf, ebuf;
+            nk_buffer_init_fixed(&vbuf, vertices, (nk_size)max_vertex_buffer);
+            nk_buffer_init_fixed(&ebuf, elements, (nk_size)max_element_buffer);
+            nk_convert(&sfml.ctx, &dev->cmds, &vbuf, &ebuf, &config);
+        }
+        glUnmapBuffer(GL_ARRAY_BUFFER);
+        glUnmapBuffer(GL_ELEMENT_ARRAY_BUFFER);
+
+        /* iterate over and execute each draw command */
+        nk_draw_foreach(cmd, &sfml.ctx, &dev->cmds)
+        {
+            if (!cmd->elem_count) continue;
+            glBindTexture(GL_TEXTURE_2D, (GLuint)cmd->texture.id);
+            glScissor(
+                (GLint)(cmd->clip_rect.x),
+                (GLint)((window_height - (GLint)(cmd->clip_rect.y + cmd->clip_rect.h))),
+                (GLint)(cmd->clip_rect.w),
+                (GLint)(cmd->clip_rect.h));
+            glDrawElements(GL_TRIANGLES, (GLsizei)cmd->elem_count, GL_UNSIGNED_SHORT, offset);
+            offset += cmd->elem_count;
+        }
+        nk_clear(&sfml.ctx);
+    }
+    glUseProgram(0);
+    glBindBuffer(GL_ARRAY_BUFFER, 0);
+    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
+    glBindVertexArray(0);
+    glDisable(GL_BLEND);
+    glDisable(GL_SCISSOR_TEST);
+}
+
+static void
+nk_sfml_clipboard_paste(nk_handle usr, struct nk_text_edit* edit)
+{
+#if 0
+    /* Not Implemented in SFML */
+    (void)usr;
+    sf::Clipboard clipboard(sfml.window);
+    const char* text = clipboard.getText();
+    if(text) nk_textedit_paste(edit, text, nk_strlen(text));
+#endif
+}
+static void
+nk_sfml_clipboard_copy(nk_handle usr, const char* text, int len)
+{
+#if 0
+    char* str = 0;
+    (void)usr;
+    if(!len) return;
+    str = (char*)malloc((size_t)len+1);
+    if(!str) return;
+    memcpy(str, text, (size_t)len);
+    str[len] = '\0';
+
+    /* Not Implemented in SFML */
+    sf::Clipboard clipboard(sfml.window);
+    clipboard.setText(str);
+    free(str);
+#endif
+}
+
+NK_API struct nk_context*
+nk_sfml_init(sf::Window* window)
+{
+    sfml.window = window;
+    nk_init_default(&sfml.ctx, 0);
+    sfml.ctx.clip.copy = nk_sfml_clipboard_copy;
+    sfml.ctx.clip.paste = nk_sfml_clipboard_paste;
+    sfml.ctx.clip.userdata = nk_handle_ptr(0);
+    nk_sfml_device_create();
+    return &sfml.ctx;
+}
+
+NK_API void
+nk_sfml_font_stash_begin(struct nk_font_atlas** atlas)
+{
+    nk_font_atlas_init_default(&sfml.atlas);
+    nk_font_atlas_begin(&sfml.atlas);
+    *atlas = &sfml.atlas;
+}
+
+NK_API void
+nk_sfml_font_stash_end()
+{
+    const void* image;
+    int w, h;
+    image = nk_font_atlas_bake(&sfml.atlas, &w, &h, NK_FONT_ATLAS_RGBA32);
+    nk_sfml_device_upload_atlas(image, w, h);
+    nk_font_atlas_end(&sfml.atlas, nk_handle_id((int)sfml.ogl.font_tex), &sfml.ogl.null);
+    if(sfml.atlas.default_font)
+        nk_style_set_font(&sfml.ctx, &sfml.atlas.default_font->handle);
+}
+
+NK_API int
+nk_sfml_handle_event(sf::Event* evt)
+{
+    struct nk_context* ctx = &sfml.ctx;
+    /* optional grabbing behavior */
+    if(ctx->input.mouse.grab)
+        ctx->input.mouse.grab = 0;
+    else if(ctx->input.mouse.ungrab) {
+        int x = (int)ctx->input.mouse.prev.x;
+        int y = (int)ctx->input.mouse.prev.y;
+        sf::Mouse::setPosition(sf::Vector2i(x, y), *sfml.window);
+        ctx->input.mouse.ungrab = 0;
+    }
+    if(evt->type == sf::Event::KeyReleased || evt->type == sf::Event::KeyPressed)
+    {
+        int down = evt->type == sf::Event::KeyPressed;
+        sf::Keyboard::Key key = evt->key.code;
+        if(key == sf::Keyboard::RShift || key == sf::Keyboard::LShift)
+            nk_input_key(ctx, NK_KEY_SHIFT, down);
+        else if(key == sf::Keyboard::Delete)
+            nk_input_key(ctx, NK_KEY_DEL, down);
+        else if(key == sf::Keyboard::Return)
+            nk_input_key(ctx, NK_KEY_ENTER, down);
+        else if(key == sf::Keyboard::Tab)
+            nk_input_key(ctx, NK_KEY_TAB, down);
+        else if(key == sf::Keyboard::BackSpace)
+            nk_input_key(ctx, NK_KEY_BACKSPACE, down);
+        else if(key == sf::Keyboard::Home) {
+            nk_input_key(ctx, NK_KEY_TEXT_START, down);
+            nk_input_key(ctx, NK_KEY_SCROLL_START, down);
+        } else if(key == sf::Keyboard::End) {
+            nk_input_key(ctx, NK_KEY_TEXT_END, down);
+            nk_input_key(ctx, NK_KEY_SCROLL_END, down);
+        } else if(key == sf::Keyboard::PageDown)
+            nk_input_key(ctx, NK_KEY_SCROLL_DOWN, down);
+        else if(key == sf::Keyboard::PageUp)
+            nk_input_key(ctx, NK_KEY_SCROLL_DOWN, down);
+        else if(key == sf::Keyboard::Z)
+            nk_input_key(ctx, NK_KEY_TEXT_UNDO, down && sf::Keyboard::isKeyPressed(sf::Keyboard::LControl));
+        else if(key == sf::Keyboard::R)
+            nk_input_key(ctx, NK_KEY_TEXT_REDO, down && sf::Keyboard::isKeyPressed(sf::Keyboard::LControl));
+        else if(key == sf::Keyboard::C)
+            nk_input_key(ctx, NK_KEY_COPY, down && sf::Keyboard::isKeyPressed(sf::Keyboard::LControl));
+        else if(key == sf::Keyboard::V)
+            nk_input_key(ctx, NK_KEY_PASTE, down && sf::Keyboard::isKeyPressed(sf::Keyboard::LControl));
+        else if(key == sf::Keyboard::X)
+            nk_input_key(ctx, NK_KEY_CUT, down && sf::Keyboard::isKeyPressed(sf::Keyboard::LControl));
+        else if(key == sf::Keyboard::B)
+            nk_input_key(ctx, NK_KEY_TEXT_LINE_START, down && sf::Keyboard::isKeyPressed(sf::Keyboard::LControl));
+        else if(key == sf::Keyboard::E)
+            nk_input_key(ctx, NK_KEY_TEXT_LINE_END, down && sf::Keyboard::isKeyPressed(sf::Keyboard::LControl));
+        else if(key == sf::Keyboard::Up)
+            nk_input_key(ctx, NK_KEY_UP, down);
+        else if(key == sf::Keyboard::Down)
+            nk_input_key(ctx, NK_KEY_DOWN, down);
+        else if(key == sf::Keyboard::Left) {
+            if(sf::Keyboard::isKeyPressed(sf::Keyboard::LControl))
+                nk_input_key(ctx, NK_KEY_TEXT_WORD_LEFT, down);
+            else nk_input_key(ctx, NK_KEY_LEFT, down);
+        } else if(key == sf::Keyboard::Right) {
+            if(sf::Keyboard::isKeyPressed(sf::Keyboard::LControl))
+                nk_input_key(ctx, NK_KEY_TEXT_WORD_RIGHT, down);
+            else nk_input_key(ctx, NK_KEY_RIGHT, down);
+        } else return 0;
+        return 1;
+    } else if(evt->type == sf::Event::MouseButtonPressed || evt->type == sf::Event::MouseButtonReleased) {
+        int down = evt->type == sf::Event::MouseButtonPressed;
+        const int x = evt->mouseButton.x, y = evt->mouseButton.y;
+        if(evt->mouseButton.button == sf::Mouse::Left)
+            nk_input_button(ctx, NK_BUTTON_LEFT, x, y, down);
+        if(evt->mouseButton.button == sf::Mouse::Middle)
+            nk_input_button(ctx, NK_BUTTON_MIDDLE, x, y, down);
+        if(evt->mouseButton.button == sf::Mouse::Right)
+            nk_input_button(ctx, NK_BUTTON_RIGHT, x, y, down);
+        else return 0;
+        return 1;
+    } else if(evt->type == sf::Event::MouseMoved) {
+        nk_input_motion(ctx, evt->mouseMove.x, evt->mouseMove.y);
+        return 1;
+    } else if(evt->type == sf::Event::TouchBegan || evt->type == sf::Event::TouchEnded) {
+        int down = evt->type == sf::Event::TouchBegan;
+        const int x = evt->touch.x, y = evt->touch.y;
+        nk_input_button(ctx, NK_BUTTON_LEFT, x, y, down);
+        return 1;
+    } else if(evt->type == sf::Event::TouchMoved) {
+        if(ctx->input.mouse.grabbed) {
+            int x = (int)ctx->input.mouse.prev.x;
+            int y = (int)ctx->input.mouse.prev.y;
+            nk_input_motion(ctx, x + evt->touch.x, y + evt->touch.y);
+        } else nk_input_motion(ctx, evt->touch.x, evt->touch.y);
+        return 1;
+    } else if(evt->type == sf::Event::TextEntered) {
+        nk_input_unicode(ctx, evt->text.unicode);
+        return 1;
+    } else if(evt->type == sf::Event::MouseWheelScrolled) {
+        nk_input_scroll(ctx, nk_vec2(0,evt->mouseWheelScroll.delta));
+        return 1;
+    }
+    return 0;
+}
+
+NK_API
+void nk_sfml_shutdown()
+{
+    nk_font_atlas_clear(&sfml.atlas);
+    nk_free(&sfml.ctx);
+    nk_sfml_device_destroy();
+    memset(&sfml, 0, sizeof(sfml));
+}
+
+#endif

+ 5 - 4
demo/x11/main.c

@@ -87,7 +87,7 @@ sleep_for(long t)
  *                          EXAMPLE
  *
  * ===============================================================*/
-/* This are some code examples to provide a small overview of what can be
+/* These are some code examples to provide a small overview of what can be
  * done with this library. To try out an example uncomment the include
  * and the corresponding function. */
 /*#include "../style.c"*/
@@ -113,11 +113,11 @@ main(void)
     memset(&xw, 0, sizeof xw);
     xw.dpy = XOpenDisplay(NULL);
     if (!xw.dpy) die("Could not open a display; perhaps $DISPLAY is not set?");
-
     xw.root = DefaultRootWindow(xw.dpy);
     xw.screen = XDefaultScreen(xw.dpy);
     xw.vis = XDefaultVisual(xw.dpy, xw.screen);
     xw.cmap = XCreateColormap(xw.dpy,xw.root,xw.vis,AllocNone);
+
     xw.swa.colormap = xw.cmap;
     xw.swa.event_mask =
         ExposureMask | KeyPressMask | KeyReleaseMask |
@@ -127,11 +127,11 @@ main(void)
     xw.win = XCreateWindow(xw.dpy, xw.root, 0, 0, WINDOW_WIDTH, WINDOW_HEIGHT, 0,
         XDefaultDepth(xw.dpy, xw.screen), InputOutput,
         xw.vis, CWEventMask | CWColormap, &xw.swa);
+
     XStoreName(xw.dpy, xw.win, "X11");
     XMapWindow(xw.dpy, xw.win);
     xw.wm_delete_window = XInternAtom(xw.dpy, "WM_DELETE_WINDOW", False);
     XSetWMProtocols(xw.dpy, xw.win, &xw.wm_delete_window, 1);
-
     XGetWindowAttributes(xw.dpy, xw.win, &xw.attr);
     xw.width = (unsigned int)xw.attr.width;
     xw.height = (unsigned int)xw.attr.height;
@@ -145,6 +145,7 @@ main(void)
     /*set_style(ctx, THEME_RED);*/
     /*set_style(ctx, THEME_BLUE);*/
     /*set_style(ctx, THEME_DARK);*/
+
     while (running)
     {
         /* Input */
@@ -178,7 +179,7 @@ main(void)
             nk_property_int(ctx, "Compression:", 0, &property, 100, 10, 1);
         }
         nk_end(ctx);
-        if (nk_window_is_closed(ctx, "Demo")) break;
+        if (nk_window_is_hidden(ctx, "Demo")) break;
 
         /* -------------- EXAMPLES ---------------- */
         /*calculator(ctx);*/

+ 240 - 116
demo/x11/nuklear_xlib.h

@@ -1,7 +1,7 @@
 /*
  * Nuklear - v1.32.0 - public domain
  * no warrenty implied; use at your own risk.
- * authored from 2015-2016 by Micha Mettke
+ * authored from 2015-2017 by Micha Mettke
  */
 /*
  * ==============================================================
@@ -14,16 +14,20 @@
 #define NK_XLIB_H_
 
 #include <X11/Xlib.h>
-/* Font */
-typedef struct XFont XFont;
-NK_API XFont*               nk_xfont_create(Display *dpy, const char *name);
-NK_API void                 nk_xfont_del(Display *dpy, XFont *font);
 
-NK_API struct nk_context*   nk_xlib_init(XFont *font, Display *dpy, int screen, Window root, unsigned int w, unsigned int h);
-NK_API int                  nk_xlib_handle_event(Display *dpy, int screen, Window win, XEvent *evt);
+typedef struct XFont XFont;
+NK_API struct nk_context*   nk_xlib_init(XFont*, Display*, int scrn, Window root, unsigned w, unsigned h);
+NK_API int                  nk_xlib_handle_event(Display*, int scrn, Window, XEvent*);
 NK_API void                 nk_xlib_render(Drawable screen, struct nk_color clear);
 NK_API void                 nk_xlib_shutdown(void);
-NK_API void                 nk_xlib_set_font(XFont *font);
+NK_API void                 nk_xlib_set_font(XFont*);
+NK_API void                 nk_xlib_push_font(XFont*);
+NK_API void                 nk_xlib_paste(nk_handle, struct nk_text_edit*);
+NK_API void                 nk_xlib_copy(nk_handle, const char*, int len);
+
+/* Font */
+NK_API XFont*               nk_xfont_create(Display *dpy, const char *name);
+NK_API void                 nk_xfont_del(Display *dpy, XFont *font);
 
 #endif
 /*
@@ -38,6 +42,18 @@ NK_API void                 nk_xlib_set_font(XFont *font);
 #include <X11/Xutil.h>
 #include <X11/Xresource.h>
 #include <X11/Xlocale.h>
+#include <X11/Xatom.h>
+
+#include <sys/time.h>
+#include <unistd.h>
+#include <time.h>
+
+#ifndef NK_X11_DOUBLE_CLICK_LO
+#define NK_X11_DOUBLE_CLICK_LO 20
+#endif
+#ifndef NK_X11_DOUBLE_CLICK_HI
+#define NK_X11_DOUBLE_CLICK_HI 200
+#endif
 
 typedef struct XSurface XSurface;
 struct XFont {
@@ -57,21 +73,32 @@ struct XSurface {
     unsigned int w, h;
 };
 static struct  {
+    char *clipboard_data;
+    int clipboard_len;
+    struct nk_text_edit* clipboard_target;
+
+    Atom xa_clipboard;
+    Atom xa_targets;
+    Atom xa_text;
+    Atom xa_utf8_string;
+
     struct nk_context ctx;
     struct XSurface *surf;
     Cursor cursor;
     Display *dpy;
     Window root;
+    long last_button_click;
 } xlib;
 
-#ifndef MIN
-#define MIN(a,b) ((a) < (b) ? (a) : (b))
-#endif
-#ifndef MAX
-#define MAX(a,b) ((a) < (b) ? (b) : (a))
-#endif
+NK_INTERN long
+nk_timestamp(void)
+{
+    struct timeval tv;
+    if (gettimeofday(&tv, NULL) < 0) return 0;
+    return (long)((long)tv.tv_sec * 1000 + (long)tv.tv_usec/1000);
+}
 
-static unsigned long
+NK_INTERN unsigned long
 nk_color_from_byte(const nk_byte *c)
 {
     unsigned long res = 0;
@@ -81,7 +108,7 @@ nk_color_from_byte(const nk_byte *c)
     return (res);
 }
 
-static XSurface*
+NK_INTERN XSurface*
 nk_xsurf_create(int screen, unsigned int w, unsigned int h)
 {
     XSurface *surface = (XSurface*)calloc(1, sizeof(XSurface));
@@ -97,7 +124,7 @@ nk_xsurf_create(int screen, unsigned int w, unsigned int h)
     return surface;
 }
 
-static void
+NK_INTERN void
 nk_xsurf_resize(XSurface *surf, unsigned int w, unsigned int h)
 {
     if(!surf) return;
@@ -108,7 +135,7 @@ nk_xsurf_resize(XSurface *surf, unsigned int w, unsigned int h)
         (unsigned int)DefaultDepth(surf->dpy, surf->screen));
 }
 
-static void
+NK_INTERN void
 nk_xsurf_scissor(XSurface *surf, float x, float y, float w, float h)
 {
     XRectangle clip_rect;
@@ -119,7 +146,7 @@ nk_xsurf_scissor(XSurface *surf, float x, float y, float w, float h)
     XSetClipRectangles(surf->dpy, surf->gc, 0, 0, &clip_rect, 1, Unsorted);
 }
 
-static void
+NK_INTERN void
 nk_xsurf_stroke_line(XSurface *surf, short x0, short y0, short x1,
     short y1, unsigned int line_thickness, struct nk_color col)
 {
@@ -130,94 +157,90 @@ nk_xsurf_stroke_line(XSurface *surf, short x0, short y0, short x1,
     XSetLineAttributes(surf->dpy, surf->gc, 1, LineSolid, CapButt, JoinMiter);
 }
 
-static void
+NK_INTERN void
 nk_xsurf_stroke_rect(XSurface* surf, short x, short y, unsigned short w,
     unsigned short h, unsigned short r, unsigned short line_thickness, struct nk_color col)
 {
     unsigned long c = nk_color_from_byte(&col.r);
     XSetForeground(surf->dpy, surf->gc, c);
     XSetLineAttributes(surf->dpy, surf->gc, line_thickness, LineSolid, CapButt, JoinMiter);
-    if (r == 0) {
-        XDrawRectangle(surf->dpy, surf->drawable, surf->gc, x, y, w, h);
-    } else {
-        short xc = x + r;
-        short yc = y + r;
-        short wc = (short)(w - 2 * r);
-        short hc = (short)(h - 2 * r);
-
-        XDrawLine(surf->dpy, surf->drawable, surf->gc, xc, y, xc+wc, y);
-        XDrawLine(surf->dpy, surf->drawable, surf->gc, x+w, yc, x+w, yc+hc);
-        XDrawLine(surf->dpy, surf->drawable, surf->gc, xc, y+h, xc+wc, y+h);
-        XDrawLine(surf->dpy, surf->drawable, surf->gc, x, yc, x, yc+hc);
-
-        XDrawArc(surf->dpy, surf->drawable, surf->gc, xc + wc - r, y,
-            (unsigned)r*2, (unsigned)r*2, 0 * 64, 90 * 64);
-        XDrawArc(surf->dpy, surf->drawable, surf->gc, x, y,
-            (unsigned)r*2, (unsigned)r*2, 90 * 64, 90 * 64);
-        XDrawArc(surf->dpy, surf->drawable, surf->gc, x, yc + hc - r,
-            (unsigned)r*2, (unsigned)2*r, 180 * 64, 90 * 64);
-        XDrawArc(surf->dpy, surf->drawable, surf->gc, xc + wc - r, yc + hc - r,
-            (unsigned)r*2, (unsigned)2*r, -90 * 64, 90 * 64);
-    }
+    if (r == 0) {XDrawRectangle(surf->dpy, surf->drawable, surf->gc, x, y, w, h);return;}
+
+    {short xc = x + r;
+    short yc = y + r;
+    short wc = (short)(w - 2 * r);
+    short hc = (short)(h - 2 * r);
+
+    XDrawLine(surf->dpy, surf->drawable, surf->gc, xc, y, xc+wc, y);
+    XDrawLine(surf->dpy, surf->drawable, surf->gc, x+w, yc, x+w, yc+hc);
+    XDrawLine(surf->dpy, surf->drawable, surf->gc, xc, y+h, xc+wc, y+h);
+    XDrawLine(surf->dpy, surf->drawable, surf->gc, x, yc, x, yc+hc);
+
+    XDrawArc(surf->dpy, surf->drawable, surf->gc, xc + wc - r, y,
+        (unsigned)r*2, (unsigned)r*2, 0 * 64, 90 * 64);
+    XDrawArc(surf->dpy, surf->drawable, surf->gc, x, y,
+        (unsigned)r*2, (unsigned)r*2, 90 * 64, 90 * 64);
+    XDrawArc(surf->dpy, surf->drawable, surf->gc, x, yc + hc - r,
+        (unsigned)r*2, (unsigned)2*r, 180 * 64, 90 * 64);
+    XDrawArc(surf->dpy, surf->drawable, surf->gc, xc + wc - r, yc + hc - r,
+        (unsigned)r*2, (unsigned)2*r, -90 * 64, 90 * 64);}
     XSetLineAttributes(surf->dpy, surf->gc, 1, LineSolid, CapButt, JoinMiter);
 }
 
-static void
+NK_INTERN void
 nk_xsurf_fill_rect(XSurface* surf, short x, short y, unsigned short w,
     unsigned short h, unsigned short r, struct nk_color col)
 {
     unsigned long c = nk_color_from_byte(&col.r);
     XSetForeground(surf->dpy, surf->gc, c);
-    if (r == 0) {
-        XFillRectangle(surf->dpy, surf->drawable, surf->gc, x, y, w, h);
-    } else {
-        short xc = x + r;
-        short yc = y + r;
-        short wc = (short)(w - 2 * r);
-        short hc = (short)(h - 2 * r);
-
-        XPoint pnts[12];
-        pnts[0].x = x;
-        pnts[0].y = yc;
-        pnts[1].x = xc;
-        pnts[1].y = yc;
-        pnts[2].x = xc;
-        pnts[2].y = y;
-
-        pnts[3].x = xc + wc;
-        pnts[3].y = y;
-        pnts[4].x = xc + wc;
-        pnts[4].y = yc;
-        pnts[5].x = x + w;
-        pnts[5].y = yc;
-
-        pnts[6].x = x + w;
-        pnts[6].y = yc + hc;
-        pnts[7].x = xc + wc;
-        pnts[7].y = yc + hc;
-        pnts[8].x = xc + wc;
-        pnts[8].y = y + h;
-
-        pnts[9].x = xc;
-        pnts[9].y = y + h;
-        pnts[10].x = xc;
-        pnts[10].y = yc + hc;
-        pnts[11].x = x;
-        pnts[11].y = yc + hc;
-
-        XFillPolygon(surf->dpy, surf->drawable, surf->gc, pnts, 12, Convex, CoordModeOrigin);
-        XFillArc(surf->dpy, surf->drawable, surf->gc, xc + wc - r, y,
-            (unsigned)r*2, (unsigned)r*2, 0 * 64, 90 * 64);
-        XFillArc(surf->dpy, surf->drawable, surf->gc, x, y,
-            (unsigned)r*2, (unsigned)r*2, 90 * 64, 90 * 64);
-        XFillArc(surf->dpy, surf->drawable, surf->gc, x, yc + hc - r,
-            (unsigned)r*2, (unsigned)2*r, 180 * 64, 90 * 64);
-        XFillArc(surf->dpy, surf->drawable, surf->gc, xc + wc - r, yc + hc - r,
-            (unsigned)r*2, (unsigned)2*r, -90 * 64, 90 * 64);
-    }
+    if (r == 0) {XFillRectangle(surf->dpy, surf->drawable, surf->gc, x, y, w, h); return;}
+
+    {short xc = x + r;
+    short yc = y + r;
+    short wc = (short)(w - 2 * r);
+    short hc = (short)(h - 2 * r);
+
+    XPoint pnts[12];
+    pnts[0].x = x;
+    pnts[0].y = yc;
+    pnts[1].x = xc;
+    pnts[1].y = yc;
+    pnts[2].x = xc;
+    pnts[2].y = y;
+
+    pnts[3].x = xc + wc;
+    pnts[3].y = y;
+    pnts[4].x = xc + wc;
+    pnts[4].y = yc;
+    pnts[5].x = x + w;
+    pnts[5].y = yc;
+
+    pnts[6].x = x + w;
+    pnts[6].y = yc + hc;
+    pnts[7].x = xc + wc;
+    pnts[7].y = yc + hc;
+    pnts[8].x = xc + wc;
+    pnts[8].y = y + h;
+
+    pnts[9].x = xc;
+    pnts[9].y = y + h;
+    pnts[10].x = xc;
+    pnts[10].y = yc + hc;
+    pnts[11].x = x;
+    pnts[11].y = yc + hc;
+
+    XFillPolygon(surf->dpy, surf->drawable, surf->gc, pnts, 12, Convex, CoordModeOrigin);
+    XFillArc(surf->dpy, surf->drawable, surf->gc, xc + wc - r, y,
+        (unsigned)r*2, (unsigned)r*2, 0 * 64, 90 * 64);
+    XFillArc(surf->dpy, surf->drawable, surf->gc, x, y,
+        (unsigned)r*2, (unsigned)r*2, 90 * 64, 90 * 64);
+    XFillArc(surf->dpy, surf->drawable, surf->gc, x, yc + hc - r,
+        (unsigned)r*2, (unsigned)2*r, 180 * 64, 90 * 64);
+    XFillArc(surf->dpy, surf->drawable, surf->gc, xc + wc - r, yc + hc - r,
+        (unsigned)r*2, (unsigned)2*r, -90 * 64, 90 * 64);}
 }
 
-static void
+NK_INTERN void
 nk_xsurf_fill_triangle(XSurface *surf, short x0, short y0, short x1,
     short y1, short x2, short y2, struct nk_color col)
 {
@@ -233,7 +256,7 @@ nk_xsurf_fill_triangle(XSurface *surf, short x0, short y0, short x1,
     XFillPolygon(surf->dpy, surf->drawable, surf->gc, pnts, 3, Convex, CoordModeOrigin);
 }
 
-static void
+NK_INTERN void
 nk_xsurf_stroke_triangle(XSurface *surf, short x0, short y0, short x1,
     short y1, short x2, short y2, unsigned short line_thickness, struct nk_color col)
 {
@@ -247,12 +270,12 @@ nk_xsurf_stroke_triangle(XSurface *surf, short x0, short y0, short x1,
     XSetLineAttributes(surf->dpy, surf->gc, 1, LineSolid, CapButt, JoinMiter);
 }
 
-static void
+NK_INTERN void
 nk_xsurf_fill_polygon(XSurface *surf,  const struct nk_vec2i *pnts, int count,
     struct nk_color col)
 {
     int i = 0;
-    #define MAX_POINTS 64
+    #define MAX_POINTS 128
     XPoint xpnts[MAX_POINTS];
     unsigned long c = nk_color_from_byte(&col.r);
     XSetForeground(surf->dpy, surf->gc, c);
@@ -264,7 +287,7 @@ nk_xsurf_fill_polygon(XSurface *surf,  const struct nk_vec2i *pnts, int count,
     #undef MAX_POINTS
 }
 
-static void
+NK_INTERN void
 nk_xsurf_stroke_polygon(XSurface *surf, const struct nk_vec2i *pnts, int count,
     unsigned short line_thickness, struct nk_color col)
 {
@@ -278,7 +301,7 @@ nk_xsurf_stroke_polygon(XSurface *surf, const struct nk_vec2i *pnts, int count,
     XSetLineAttributes(surf->dpy, surf->gc, 1, LineSolid, CapButt, JoinMiter);
 }
 
-static void
+NK_INTERN void
 nk_xsurf_stroke_polyline(XSurface *surf, const struct nk_vec2i *pnts,
     int count, unsigned short line_thickness, struct nk_color col)
 {
@@ -291,7 +314,7 @@ nk_xsurf_stroke_polyline(XSurface *surf, const struct nk_vec2i *pnts,
     XSetLineAttributes(surf->dpy, surf->gc, 1, LineSolid, CapButt, JoinMiter);
 }
 
-static void
+NK_INTERN void
 nk_xsurf_fill_circle(XSurface *surf, short x, short y, unsigned short w,
     unsigned short h, struct nk_color col)
 {
@@ -301,7 +324,7 @@ nk_xsurf_fill_circle(XSurface *surf, short x, short y, unsigned short w,
         (unsigned)w, (unsigned)h, 0, 360 * 64);
 }
 
-static void
+NK_INTERN void
 nk_xsurf_stroke_circle(XSurface *surf, short x, short y, unsigned short w,
     unsigned short h, unsigned short line_thickness, struct nk_color col)
 {
@@ -313,7 +336,7 @@ nk_xsurf_stroke_circle(XSurface *surf, short x, short y, unsigned short w,
     XSetLineAttributes(surf->dpy, surf->gc, 1, LineSolid, CapButt, JoinMiter);
 }
 
-static void
+NK_INTERN void
 nk_xsurf_stroke_curve(XSurface *surf, struct nk_vec2i p1,
     struct nk_vec2i p2, struct nk_vec2i p3, struct nk_vec2i p4,
     unsigned int num_segments, unsigned short line_thickness, struct nk_color col)
@@ -323,7 +346,7 @@ nk_xsurf_stroke_curve(XSurface *surf, struct nk_vec2i p1,
     struct nk_vec2i last = p1;
 
     XSetLineAttributes(surf->dpy, surf->gc, line_thickness, LineSolid, CapButt, JoinMiter);
-    num_segments = MAX(num_segments, 1);
+    num_segments = NK_MAX(num_segments, 1);
     t_step = 1.0f/(float)num_segments;
     for (i_step = 1; i_step <= num_segments; ++i_step) {
         float t = t_step * (float)i_step;
@@ -340,7 +363,7 @@ nk_xsurf_stroke_curve(XSurface *surf, struct nk_vec2i p1,
     XSetLineAttributes(surf->dpy, surf->gc, 1, LineSolid, CapButt, JoinMiter);
 }
 
-static void
+NK_INTERN void
 nk_xsurf_draw_text(XSurface *surf, short x, short y, unsigned short w, unsigned short h,
     const char *text, int len, XFont *font, struct nk_color cbg, struct nk_color cfg)
 {
@@ -357,24 +380,23 @@ nk_xsurf_draw_text(XSurface *surf, short x, short y, unsigned short w, unsigned
     XSetForeground(surf->dpy, surf->gc, fg);
     if(font->set)
         XmbDrawString(surf->dpy,surf->drawable,font->set,surf->gc,tx,ty,(const char*)text,(int)len);
-    else
-        XDrawString(surf->dpy, surf->drawable, surf->gc, tx, ty, (const char*)text, (int)len);
+    else XDrawString(surf->dpy, surf->drawable, surf->gc, tx, ty, (const char*)text, (int)len);
 }
 
-static void
+NK_INTERN void
 nk_xsurf_clear(XSurface *surf, unsigned long color)
 {
     XSetForeground(surf->dpy, surf->gc, color);
     XFillRectangle(surf->dpy, surf->drawable, surf->gc, 0, 0, surf->w, surf->h);
 }
 
-static void
+NK_INTERN void
 nk_xsurf_blit(Drawable target, XSurface *surf, unsigned int w, unsigned int h)
 {
     XCopyArea(surf->dpy, surf->drawable, target, surf->gc, 0, 0, w, h, 0, 0);
 }
 
-static void
+NK_INTERN void
 nk_xsurf_del(XSurface *surf)
 {
     XFreePixmap(surf->dpy, surf->drawable);
@@ -382,7 +404,7 @@ nk_xsurf_del(XSurface *surf)
     free(surf);
 }
 
-XFont*
+NK_API XFont*
 nk_xfont_create(Display *dpy, const char *name)
 {
     int n;
@@ -394,15 +416,14 @@ nk_xfont_create(Display *dpy, const char *name)
             fprintf(stderr, "missing fontset: %s\n", missing[n]);
         XFreeStringList(missing);
     }
-
     if(font->set) {
         XFontStruct **xfonts;
         char **font_names;
         XExtentsOfFontSet(font->set);
         n = XFontsOfFontSet(font->set, &xfonts, &font_names);
         while(n--) {
-            font->ascent = MAX(font->ascent, (*xfonts)->ascent);
-            font->descent = MAX(font->descent,(*xfonts)->descent);
+            font->ascent = NK_MAX(font->ascent, (*xfonts)->ascent);
+            font->descent = NK_MAX(font->descent,(*xfonts)->descent);
             xfonts++;
         }
     } else {
@@ -418,7 +439,7 @@ nk_xfont_create(Display *dpy, const char *name)
     return font;
 }
 
-static float
+NK_INTERN float
 nk_xfont_get_text_width(nk_handle handle, float height, const char *text, int len)
 {
     XFont *font = (XFont*)handle.ptr;
@@ -435,7 +456,7 @@ nk_xfont_get_text_width(nk_handle handle, float height, const char *text, int le
     }
 }
 
-void
+NK_API void
 nk_xfont_del(Display *dpy, XFont *font)
 {
     if(!font) return;
@@ -461,6 +482,11 @@ nk_xlib_init(XFont *xfont, Display *dpy, int screen, Window root,
     if (!XSupportsLocale()) return 0;
     if (!XSetLocaleModifiers("@im=none")) return 0;
 
+    xlib.xa_clipboard = XInternAtom(dpy, "CLIPBOARD", False);
+    xlib.xa_targets = XInternAtom(dpy, "TARGETS", False);
+    xlib.xa_text = XInternAtom(dpy, "TEXT", False);
+    xlib.xa_utf8_string = XInternAtom(dpy, "UTF8_STRING", False);
+
     /* create invisible cursor */
     {static XColor dummy; char data[1] = {0};
     Pixmap blank = XCreateBitmapFromData(dpy, root, data, 1, 1);
@@ -483,6 +509,42 @@ nk_xlib_set_font(XFont *xfont)
     nk_style_set_font(&xlib.ctx, font);
 }
 
+NK_API void
+nk_xlib_push_font(XFont *xfont)
+{
+    struct nk_user_font *font = &xfont->handle;
+    font->userdata = nk_handle_ptr(xfont);
+    font->height = (float)xfont->height;
+    font->width = nk_xfont_get_text_width;
+    nk_style_push_font(&xlib.ctx, font);
+}
+
+NK_API void
+nk_xlib_paste(nk_handle handle, struct nk_text_edit* edit)
+{
+    NK_UNUSED(handle);
+    /* Paste in X is asynchronous, so can not use a temporary text edit */
+    NK_ASSERT(edit != &xlib.ctx.text_edit && "Paste not supported for temporary editors");
+    xlib.clipboard_target = edit;
+    /* Request the contents of the primary buffer */
+    XConvertSelection(xlib.dpy, XA_PRIMARY, XA_STRING, XA_PRIMARY, xlib.root, CurrentTime);
+}
+
+NK_API void
+nk_xlib_copy(nk_handle handle, const char* str, int len)
+{
+    NK_UNUSED(handle);
+    free(xlib.clipboard_data);
+    xlib.clipboard_len = 0;
+    xlib.clipboard_data = malloc((size_t)len);
+    if (xlib.clipboard_data) {
+        memcpy(xlib.clipboard_data, str, (size_t)len);
+        xlib.clipboard_len = len;
+        XSetSelectionOwner(xlib.dpy, XA_PRIMARY, xlib.root, CurrentTime);
+        XSetSelectionOwner(xlib.dpy, xlib.xa_clipboard, xlib.root, CurrentTime);
+    }
+}
+
 NK_API int
 nk_xlib_handle_event(Display *dpy, int screen, Window win, XEvent *evt)
 {
@@ -560,16 +622,22 @@ nk_xlib_handle_event(Display *dpy, int screen, Window win, XEvent *evt)
         /* Button handler */
         int down = (evt->type == ButtonPress);
         const int x = evt->xbutton.x, y = evt->xbutton.y;
-        if (evt->xbutton.button == Button1)
+        if (evt->xbutton.button == Button1) {
+            if (down) { /* Double-Click Button handler */
+                long dt = nk_timestamp() - xlib.last_button_click;
+                if (dt > NK_X11_DOUBLE_CLICK_LO && dt < NK_X11_DOUBLE_CLICK_HI)
+                    nk_input_button(ctx, NK_BUTTON_DOUBLE, x, y, nk_true);
+                xlib.last_button_click = nk_timestamp();
+            } else nk_input_button(ctx, NK_BUTTON_DOUBLE, x, y, nk_false);
             nk_input_button(ctx, NK_BUTTON_LEFT, x, y, down);
-        if (evt->xbutton.button == Button2)
+        } else if (evt->xbutton.button == Button2)
             nk_input_button(ctx, NK_BUTTON_MIDDLE, x, y, down);
         else if (evt->xbutton.button == Button3)
             nk_input_button(ctx, NK_BUTTON_RIGHT, x, y, down);
         else if (evt->xbutton.button == Button4)
-            nk_input_scroll(ctx, 1.0f);
+            nk_input_scroll(ctx, nk_vec2(0, 1.0f));
         else if (evt->xbutton.button == Button5)
-            nk_input_scroll(ctx, -1.0f);
+            nk_input_scroll(ctx, nk_vec2(0, -1.0f));
         else return 0;
         return 1;
     } else if (evt->type == MotionNotify) {
@@ -594,6 +662,60 @@ nk_xlib_handle_event(Display *dpy, int screen, Window win, XEvent *evt)
     } else if (evt->type == KeymapNotify) {
         XRefreshKeyboardMapping(&evt->xmapping);
         return 1;
+    } else if (evt->type == SelectionClear) {
+        free(xlib.clipboard_data);
+        xlib.clipboard_data = NULL;
+        xlib.clipboard_len = 0;
+        return 1;
+    } else if (evt->type == SelectionRequest) {
+        XEvent reply;
+        reply.xselection.type = SelectionNotify;
+        reply.xselection.requestor = evt->xselectionrequest.requestor;
+        reply.xselection.selection = evt->xselectionrequest.selection;
+        reply.xselection.target = evt->xselectionrequest.target;
+        reply.xselection.property = None; /* Default refuse */
+        reply.xselection.time = evt->xselectionrequest.time;
+
+        if (reply.xselection.target == xlib.xa_targets) {
+            Atom target_list[4];
+            target_list[0] = xlib.xa_targets;
+            target_list[1] = xlib.xa_text;
+            target_list[2] = xlib.xa_utf8_string;
+            target_list[3] = XA_STRING;
+
+            reply.xselection.property = evt->xselectionrequest.property;
+            XChangeProperty(evt->xselection.display,evt->xselectionrequest.requestor,
+                reply.xselection.property, XA_ATOM, 32, PropModeReplace,
+                (unsigned char*)&target_list, 4);
+        } else if (xlib.clipboard_data && (reply.xselection.target == xlib.xa_text ||
+            reply.xselection.target == xlib.xa_utf8_string || reply.xselection.target == XA_STRING)) {
+            reply.xselection.property = evt->xselectionrequest.property;
+            XChangeProperty(evt->xselection.display,evt->xselectionrequest.requestor,
+                reply.xselection.property, reply.xselection.target, 8, PropModeReplace,
+                (unsigned char*)xlib.clipboard_data, xlib.clipboard_len);
+        }
+        XSendEvent(evt->xselection.display, evt->xselectionrequest.requestor, True, 0, &reply);
+        XFlush(evt->xselection.display);
+        return 1;
+    } else if (evt->type == SelectionNotify && xlib.clipboard_target) {
+        if ((evt->xselection.target != XA_STRING) &&
+            (evt->xselection.target != xlib.xa_utf8_string) &&
+            (evt->xselection.target != xlib.xa_text))
+            return 1;
+
+        {Atom actual_type;
+        int actual_format;
+        unsigned long pos = 0, len, remain;
+        unsigned char* data = 0;
+        do {
+            XGetWindowProperty(dpy, win, XA_PRIMARY, (int)pos, 1024, False,
+                AnyPropertyType, &actual_type, &actual_format, &len, &remain, &data);
+            if (len && data)
+                nk_textedit_text(xlib.clipboard_target, (char*)data, (int)len);
+            if (data != 0) XFree(data);
+            pos += (len * (unsigned long)actual_format) / 32;
+        } while (remain != 0);}
+        return 1;
     }
     return 0;
 }
@@ -684,6 +806,7 @@ nk_xlib_render(Drawable screen, struct nk_color clear)
         case NK_COMMAND_IMAGE:
         case NK_COMMAND_ARC:
         case NK_COMMAND_ARC_FILLED:
+        case NK_COMMAND_CUSTOM:
         default: break;
         }
     }
@@ -691,3 +814,4 @@ nk_xlib_render(Drawable screen, struct nk_color clear)
     nk_xsurf_blit(screen, surf, surf->w, surf->h);
 }
 #endif
+

+ 7 - 8
demo/x11_opengl2/main.c

@@ -65,9 +65,9 @@ struct XWindow {
     Atom wm_delete_window;
     int width, height;
 };
-static int gl_err = FALSE;
+static int gl_err = nk_false;
 static int gl_error_handler(Display *dpy, XErrorEvent *ev)
-{UNUSED((dpy, ev)); gl_err = TRUE;return 0;}
+{UNUSED((dpy, ev)); gl_err = nk_true; return 0;}
 
 static void
 die(const char *fmt, ...)
@@ -86,7 +86,7 @@ has_extension(const char *string, const char *ext)
     const char *start, *where, *term;
     where = strchr(ext, ' ');
     if (where || *ext == '\0')
-        return FALSE;
+        return nk_false;
 
     for (start = string;;) {
         where = strstr((const char*)start, ext);
@@ -94,11 +94,11 @@ has_extension(const char *string, const char *ext)
         term = where + strlen(ext);
         if (where == start || *(where - 1) == ' ') {
             if (*term == ' ' || *term == '\0')
-                return TRUE;
+                return nk_true;
         }
         start = term;
     }
-    return FALSE;
+    return nk_false;
 }
 
 int main(int argc, char **argv)
@@ -189,7 +189,7 @@ int main(int argc, char **argv)
         glxCreateContext create_context = (glxCreateContext)
             glXGetProcAddressARB((const GLubyte*)"glXCreateContextAttribsARB");
 
-        gl_err = FALSE;
+        gl_err = nk_false;
         if (!has_extension(extensions_str, "GLX_ARB_create_context") || !create_context) {
             fprintf(stdout, "[X11]: glXCreateContextAttribARB() not found...\n");
             fprintf(stdout, "[X11]: ... using old-style GLX context\n");
@@ -208,7 +208,7 @@ int main(int argc, char **argv)
                  * return the newest context version compatible with OpenGL
                  * version less than version 3.0.*/
                 attr[1] = 1; attr[3] = 0;
-                gl_err = FALSE;
+                gl_err = nk_false;
                 fprintf(stdout, "[X11] Failed to create OpenGL 3.0 context\n");
                 fprintf(stdout, "[X11] ... using old-style GLX context!\n");
                 glContext = create_context(win.dpy, win.fbc, 0, True, attr);
@@ -289,7 +289,6 @@ int main(int argc, char **argv)
             }
         }
         nk_end(ctx);
-        if (nk_window_is_closed(ctx, "Demo")) break;
 
         /* -------------- EXAMPLES ---------------- */
         /*calculator(ctx);*/

+ 27 - 8
demo/x11_opengl2/nuklear_xlib_gl2.h

@@ -34,6 +34,10 @@ NK_API void                 nk_x11_shutdown(void);
 #include <stdlib.h>
 #include <string.h>
 
+#include <sys/time.h>
+#include <unistd.h>
+#include <time.h>
+
 #include <X11/Xlib.h>
 #include <X11/Xutil.h>
 #include <X11/Xresource.h>
@@ -41,11 +45,11 @@ NK_API void                 nk_x11_shutdown(void);
 
 #include <GL/gl.h>
 
-#ifndef FALSE
-#define FALSE 0
+#ifndef NK_X11_DOUBLE_CLICK_LO
+#define NK_X11_DOUBLE_CLICK_LO 20
 #endif
-#ifndef TRUE
-#define TRUE 1
+#ifndef NK_X11_DOUBLE_CLICK_HI
+#define NK_X11_DOUBLE_CLICK_HI 200
 #endif
 
 struct nk_x11_vertex {
@@ -67,8 +71,17 @@ static struct nk_x11 {
     Cursor cursor;
     Display *dpy;
     Window win;
+    long last_button_click;
 } x11;
 
+NK_INTERN long
+nk_timestamp(void)
+{
+    struct timeval tv;
+    if (gettimeofday(&tv, NULL) < 0) return 0;
+    return (long)((long)tv.tv_sec * 1000 + (long)tv.tv_usec/1000);
+}
+
 NK_INTERN void
 nk_x11_device_upload_atlas(const void *image, int width, int height)
 {
@@ -291,16 +304,22 @@ nk_x11_handle_event(XEvent *evt)
         /* Button handler */
         int down = (evt->type == ButtonPress);
         const int x = evt->xbutton.x, y = evt->xbutton.y;
-        if (evt->xbutton.button == Button1)
+        if (evt->xbutton.button == Button1) {
+            if (down) { /* Double-Click Button handler */
+                long dt = nk_timestamp() - x11.last_button_click;
+                if (dt > NK_X11_DOUBLE_CLICK_LO && dt < NK_X11_DOUBLE_CLICK_HI)
+                    nk_input_button(ctx, NK_BUTTON_DOUBLE, x, y, nk_true);
+                x11.last_button_click = nk_timestamp();
+            } else nk_input_button(ctx, NK_BUTTON_DOUBLE, x, y, nk_false);
             nk_input_button(ctx, NK_BUTTON_LEFT, x, y, down);
-        if (evt->xbutton.button == Button2)
+        } else if (evt->xbutton.button == Button2)
             nk_input_button(ctx, NK_BUTTON_MIDDLE, x, y, down);
         else if (evt->xbutton.button == Button3)
             nk_input_button(ctx, NK_BUTTON_RIGHT, x, y, down);
         else if (evt->xbutton.button == Button4)
-            nk_input_scroll(ctx, 1.0f);
+            nk_input_scroll(ctx, nk_vec2(0,1.0f));
         else if (evt->xbutton.button == Button5)
-            nk_input_scroll(ctx, -1.0f);
+            nk_input_scroll(ctx, nk_vec2(0,-1.0f));
         else return 0;
         return 1;
     } else if (evt->type == MotionNotify) {

+ 7 - 8
demo/x11_opengl3/main.c

@@ -63,9 +63,9 @@ struct XWindow {
     Atom wm_delete_window;
     int width, height;
 };
-static int gl_err = FALSE;
+static int gl_err = nk_false;
 static int gl_error_handler(Display *dpy, XErrorEvent *ev)
-{UNUSED((dpy, ev)); gl_err = TRUE;return 0;}
+{UNUSED((dpy, ev)); gl_err = nk_true;return 0;}
 
 static void
 die(const char *fmt, ...)
@@ -84,7 +84,7 @@ has_extension(const char *string, const char *ext)
     const char *start, *where, *term;
     where = strchr(ext, ' ');
     if (where || *ext == '\0')
-        return FALSE;
+        return nk_false;
 
     for (start = string;;) {
         where = strstr((const char*)start, ext);
@@ -92,11 +92,11 @@ has_extension(const char *string, const char *ext)
         term = where + strlen(ext);
         if (where == start || *(where - 1) == ' ') {
             if (*term == ' ' || *term == '\0')
-                return TRUE;
+                return nk_true;
         }
         start = term;
     }
-    return FALSE;
+    return nk_false;
 }
 
 int main(int argc, char **argv)
@@ -187,7 +187,7 @@ int main(int argc, char **argv)
         glxCreateContext create_context = (glxCreateContext)
             glXGetProcAddressARB((const GLubyte*)"glXCreateContextAttribsARB");
 
-        gl_err = FALSE;
+        gl_err = nk_false;
         if (!has_extension(extensions_str, "GLX_ARB_create_context") || !create_context) {
             fprintf(stdout, "[X11]: glXCreateContextAttribARB() not found...\n");
             fprintf(stdout, "[X11]: ... using old-style GLX context\n");
@@ -206,7 +206,7 @@ int main(int argc, char **argv)
                  * return the newest context version compatible with OpenGL
                  * version less than version 3.0.*/
                 attr[1] = 1; attr[3] = 0;
-                gl_err = FALSE;
+                gl_err = nk_false;
                 fprintf(stdout, "[X11] Failed to create OpenGL 3.0 context\n");
                 fprintf(stdout, "[X11] ... using old-style GLX context!\n");
                 glContext = create_context(win.dpy, win.fbc, 0, True, attr);
@@ -286,7 +286,6 @@ int main(int argc, char **argv)
             }
         }
         nk_end(ctx);
-        if (nk_window_is_closed(ctx, "Demo")) break;
 
         /* -------------- EXAMPLES ---------------- */
         /*calculator(ctx);*/

+ 35 - 17
demo/x11_opengl3/nuklear_xlib_gl3.h

@@ -36,6 +36,10 @@ NK_API void                 nk_x11_device_destroy(void);
 #include <stdlib.h>
 #include <string.h>
 
+#include <sys/time.h>
+#include <unistd.h>
+#include <time.h>
+
 #include <X11/Xlib.h>
 #include <X11/Xutil.h>
 #include <X11/Xresource.h>
@@ -44,11 +48,11 @@ NK_API void                 nk_x11_device_destroy(void);
 #include <GL/gl.h>
 #include <GL/glx.h>
 
-#ifndef FALSE
-#define FALSE 0
+#ifndef NK_X11_DOUBLE_CLICK_LO
+#define NK_X11_DOUBLE_CLICK_LO 20
 #endif
-#ifndef TRUE
-#define TRUE 1
+#ifndef NK_X11_DOUBLE_CLICK_HI
+#define NK_X11_DOUBLE_CLICK_HI 200
 #endif
 
 #ifdef NK_XLIB_LOAD_OPENGL_EXTENSIONS
@@ -189,6 +193,7 @@ static struct nk_x11 {
     Cursor cursor;
     Display *dpy;
     Window win;
+    long last_button_click;
 } x11;
 
 #ifdef __APPLE__
@@ -200,6 +205,14 @@ static struct nk_x11 {
 #ifdef NK_XLIB_LOAD_OPENGL_EXTENSIONS
 #include <GL/glx.h>
 
+NK_INTERN long
+nk_timestamp(void)
+{
+    struct timeval tv;
+    if (gettimeofday(&tv, NULL) < 0) return 0;
+    return (long)((long)tv.tv_sec * 1000 + (long)tv.tv_usec/1000);
+}
+
 NK_INTERN int
 nk_x11_stricmpn(const char *a, const char *b, int len)
 {
@@ -216,7 +229,7 @@ nk_x11_check_extension(struct opengl_info *GL, const char *ext)
     const char *start, *where, *term;
     where = strchr(ext, ' ');
     if (where || *ext == '\0')
-        return FALSE;
+        return nk_false;
 
     for (start = GL->extensions_str;;) {
         where = strstr((const char*)start, ext);
@@ -224,11 +237,11 @@ nk_x11_check_extension(struct opengl_info *GL, const char *ext)
         term = where + strlen(ext);
         if (where == start || *(where - 1) == ' ') {
             if (*term == ' ' || *term == '\0')
-                return TRUE;
+                return nk_true;
         }
         start = term;
     }
-    return FALSE;
+    return nk_false;
 }
 
 #define GL_EXT(name) (nk##name)nk_gl_ext(#name)
@@ -247,7 +260,7 @@ nk_gl_ext(const char *name)
 NK_INTERN int
 nk_load_opengl(struct opengl_info *gl)
 {
-    int failed = FALSE;
+    int failed = nk_false;
     gl->version_str = (const char*)glGetString(GL_VERSION);
     glGetIntegerv(GL_MAJOR_VERSION, &gl->major_version);
     glGetIntegerv(GL_MINOR_VERSION, &gl->minor_version);
@@ -255,7 +268,6 @@ nk_load_opengl(struct opengl_info *gl)
         fprintf(stderr, "[GL]: Graphics card does not fullfill minimum OpenGL 2.0 support\n");
         return 0;
     }
-
     gl->version = (float)gl->major_version + (float)gl->minor_version * 0.1f;
     gl->renderer_str = (const char*)glGetString(GL_RENDERER);
     gl->extensions_str = (const char*)glGetString(GL_EXTENSIONS);
@@ -327,19 +339,19 @@ nk_load_opengl(struct opengl_info *gl)
     }
     if (!gl->vertex_buffer_obj_available) {
         fprintf(stdout, "[GL] Error: GL_ARB_vertex_buffer_object is not available!\n");
-        failed = TRUE;
+        failed = nk_true;
     }
     if (!gl->fragment_program_available) {
         fprintf(stdout, "[GL] Error: GL_ARB_fragment_program is not available!\n");
-        failed = TRUE;
+        failed = nk_true;
     }
     if (!gl->vertex_array_obj_available) {
         fprintf(stdout, "[GL] Error: GL_ARB_vertex_array_object is not available!\n");
-        failed = TRUE;
+        failed = nk_true;
     }
     if (!gl->frame_buffer_object_available) {
         fprintf(stdout, "[GL] Error: GL_ARB_framebuffer_object is not available!\n");
-        failed = TRUE;
+        failed = nk_true;
     }
     return !failed;
 }
@@ -661,16 +673,22 @@ nk_x11_handle_event(XEvent *evt)
         /* Button handler */
         int down = (evt->type == ButtonPress);
         const int x = evt->xbutton.x, y = evt->xbutton.y;
-        if (evt->xbutton.button == Button1)
+        if (evt->xbutton.button == Button1) {
+            if (down) { /* Double-Click Button handler */
+                long dt = nk_timestamp() - x11.last_button_click;
+                if (dt > NK_X11_DOUBLE_CLICK_LO && dt < NK_X11_DOUBLE_CLICK_HI)
+                    nk_input_button(ctx, NK_BUTTON_DOUBLE, x, y, nk_true);
+                x11.last_button_click = nk_timestamp();
+            } else nk_input_button(ctx, NK_BUTTON_DOUBLE, x, y, nk_false);
             nk_input_button(ctx, NK_BUTTON_LEFT, x, y, down);
-        if (evt->xbutton.button == Button2)
+        } else if (evt->xbutton.button == Button2)
             nk_input_button(ctx, NK_BUTTON_MIDDLE, x, y, down);
         else if (evt->xbutton.button == Button3)
             nk_input_button(ctx, NK_BUTTON_RIGHT, x, y, down);
         else if (evt->xbutton.button == Button4)
-            nk_input_scroll(ctx, 1.0f);
+            nk_input_scroll(ctx, nk_vec2(0,1.0f));
         else if (evt->xbutton.button == Button5)
-            nk_input_scroll(ctx, -1.0f);
+            nk_input_scroll(ctx, nk_vec2(0,-1.0f));
         else return 0;
         return 1;
     } else if (evt->type == MotionNotify) {

+ 1 - 1
example/canvas.c

@@ -307,7 +307,7 @@ static void error_callback(int e, const char *d){printf("Error %d: %s\n", e, d);
 static void text_input(GLFWwindow *win, unsigned int codepoint)
 {nk_input_unicode((struct nk_context*)glfwGetWindowUserPointer(win), codepoint);}
 static void scroll_input(GLFWwindow *win, double _, double yoff)
-{UNUSED(_);nk_input_scroll((struct nk_context*)glfwGetWindowUserPointer(win), (float)yoff);}
+{UNUSED(_);nk_input_scroll((struct nk_context*)glfwGetWindowUserPointer(win), nk_vec2(0, (float)yoff));}
 
 static void
 pump_input(struct nk_context *ctx, GLFWwindow *win)

+ 1 - 1
example/extended.c

@@ -734,7 +734,7 @@ static void error_callback(int e, const char *d){printf("Error %d: %s\n", e, d);
 static void text_input(GLFWwindow *win, unsigned int codepoint)
 {nk_input_unicode((struct nk_context*)glfwGetWindowUserPointer(win), codepoint);}
 static void scroll_input(GLFWwindow *win, double _, double yoff)
-{UNUSED(_);nk_input_scroll((struct nk_context*)glfwGetWindowUserPointer(win), (float)yoff);}
+{UNUSED(_);nk_input_scroll((struct nk_context*)glfwGetWindowUserPointer(win), nk_vec2(0, (float)yoff));}
 
 int main(int argc, char *argv[])
 {

+ 1 - 1
example/file_browser.c

@@ -765,7 +765,7 @@ static void error_callback(int e, const char *d){printf("Error %d: %s\n", e, d);
 static void text_input(GLFWwindow *win, unsigned int codepoint)
 {nk_input_unicode((struct nk_context*)glfwGetWindowUserPointer(win), codepoint);}
 static void scroll_input(GLFWwindow *win, double _, double yoff)
-{UNUSED(_);nk_input_scroll((struct nk_context*)glfwGetWindowUserPointer(win), (float)yoff);}
+{UNUSED(_);nk_input_scroll((struct nk_context*)glfwGetWindowUserPointer(win), nk_vec2(0, (float)yoff));}
 
 int main(int argc, char *argv[])
 {

+ 1 - 1
example/skinning.c

@@ -334,7 +334,7 @@ static void error_callback(int e, const char *d){printf("Error %d: %s\n", e, d);
 static void text_input(GLFWwindow *win, unsigned int codepoint)
 {nk_input_unicode((struct nk_context*)glfwGetWindowUserPointer(win), codepoint);}
 static void scroll_input(GLFWwindow *win, double _, double yoff)
-{UNUSED(_);nk_input_scroll((struct nk_context*)glfwGetWindowUserPointer(win), (float)yoff);}
+{UNUSED(_);nk_input_scroll((struct nk_context*)glfwGetWindowUserPointer(win), nk_vec2(0, (float)yoff));}
 
 int main(int argc, char *argv[])
 {

Diferenças do arquivo suprimidas por serem muito extensas
+ 1300 - 92
nuklear.h


Alguns arquivos não foram mostrados porque muitos arquivos mudaram nesse diff