├── README.md ├── borderless-window-rendering.cpp ├── borderless-window-rendering.h ├── borderless-window.cpp ├── borderless-window.exe.manifest ├── imgui_winapi_gl2 ├── LICENSE.txt ├── imconfig.h ├── imgui.cpp ├── imgui.h ├── imgui_demo.cpp ├── imgui_draw.cpp ├── imgui_impl_gl2.cpp ├── imgui_impl_gl2.h ├── imgui_internal.h ├── stb_rect_pack.h ├── stb_textedit.h └── stb_truetype.h ├── resources.rc ├── screenshots └── imgui_with_alpha_on_win32.png ├── vs2013_build.bat ├── vs2013_debug.bat ├── vs2015_build.bat └── vs2015_debug.bat /README.md: -------------------------------------------------------------------------------- 1 | # borderless-window-opengl 2 | Demonstration of alpha blended compositing of opengl contexts via borderless windows using the Win32 API 3 | 4 | 5 | Based on https://github.com/rossy/borderless-window and https://github.com/ocornut/imgui . 6 | 7 | ![ImGui alpha blended onto a Windows desktop](https://github.com/ands/borderless-window-opengl/raw/master/screenshots/imgui_with_alpha_on_win32.png) 8 | 9 | The application only creates an OpenGL 2 context, because creating a modern context is a PITA and out of scope here. 10 | -------------------------------------------------------------------------------- /borderless-window-rendering.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "borderless-window-rendering.h" 4 | #include "imgui.h" 5 | #include "imgui_impl_gl2.h" 6 | 7 | void handle_init(struct window *data) 8 | { 9 | ImGui::CreateContext(); 10 | ImGui_ImplGL2_Init(data->hwnd); 11 | ImGui::StyleColorsDark(); 12 | 13 | // Try to hide remaining 1px row of windows border in the corners 14 | // which needs to be there to not get other artifacts :( 15 | ImGui::GetStyle().WindowRounding = 0.0f; 16 | } 17 | 18 | static void imgui(struct window *data) 19 | { 20 | ImGui::SetNextWindowPos(ImVec2(0.0f, 0.0f)); 21 | ImGui::SetNextWindowSize(ImVec2((float)data->width, (float)data->height)); 22 | bool show = true; 23 | if (!ImGui::Begin("Borderless OpenGL Window Example", &show, ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoCollapse) || !show) 24 | PostQuitMessage(0); 25 | 26 | ImGui::ShowStyleEditor(); // TODO: Replace this with your UI 27 | 28 | ImGui::End(); 29 | } 30 | 31 | static void handle_paint(struct window *data) 32 | { 33 | ImGui_ImplGL2_NewFrame(data->width, data->height, data->width, data->height); 34 | imgui(data); 35 | glViewport(0, 0, data->width, data->height); 36 | glClearColor(0.0f, 0.0f, 0.0f, 0.0f); 37 | glClear(GL_COLOR_BUFFER_BIT); 38 | ImGui::Render(); 39 | ImGui_ImplGL2_RenderDrawData(ImGui::GetDrawData()); 40 | Sleep(15); // Optional. Reduce CPU usage that shows up in the task manager. Should depend on your frame duration and refresh interval! 41 | SwapBuffers(GetDC(data->hwnd)); 42 | } 43 | 44 | bool handle_message(struct window *data, UINT msg, WPARAM wparam, LPARAM lparam) 45 | { 46 | // TODO: Get title bar dimensions from imgui: 47 | if (HIWORD(lparam) < 19 && LOWORD(lparam) < data->width - 17) 48 | { 49 | if (msg == WM_LBUTTONDOWN) // drag window 50 | { 51 | SendMessageW(data->hwnd, WM_NCLBUTTONDOWN, HTCAPTION, 0); 52 | return true; 53 | } 54 | 55 | if (msg == WM_LBUTTONDBLCLK) // toggle maximize 56 | { 57 | ShowWindow(data->hwnd, data->maximized ? SW_RESTORE : SW_MAXIMIZE); 58 | return true; 59 | } 60 | } 61 | 62 | if (msg == WM_PAINT) 63 | { 64 | handle_paint(data); 65 | return true; 66 | } 67 | 68 | return ImGui_ImplGL2_Handle_Message(msg, wparam, lparam); 69 | } 70 | 71 | void handle_shutdown(struct window * /*data*/) 72 | { 73 | ImGui_ImplGL2_Shutdown(); 74 | ImGui::DestroyContext(); 75 | } -------------------------------------------------------------------------------- /borderless-window-rendering.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | struct window 4 | { 5 | HWND hwnd; 6 | 7 | unsigned width; 8 | unsigned height; 9 | 10 | RECT rgn; 11 | 12 | bool minimized; 13 | bool maximized; 14 | bool theme_enabled; 15 | bool composition_enabled; 16 | }; 17 | 18 | void handle_init(struct window *data); 19 | bool handle_message(struct window *data, UINT msg, WPARAM wparam, LPARAM lparam); 20 | void handle_shutdown(struct window *data); 21 | -------------------------------------------------------------------------------- /borderless-window.cpp: -------------------------------------------------------------------------------- 1 | /* borderless-window - a minimal borderless window with the Windows API 2 | * 3 | * Written in 2016 by James Ross-Gowan, modified in 2018 by Andreas Mantler 4 | * 5 | * To the extent possible under law, the author(s) have dedicated all copyright 6 | * and related and neighboring rights to this software to the public domain 7 | * worldwide. This software is distributed without any warranty. 8 | * 9 | * See for a copy of the 10 | * CC0 Public Domain Dedication, which applies to this software. 11 | */ 12 | 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include "borderless-window-rendering.h" 22 | 23 | #pragma comment(lib, "user32.lib") 24 | #pragma comment(lib, "gdi32.lib") 25 | #pragma comment(lib, "shell32.lib") 26 | #pragma comment(lib, "uxtheme.lib") 27 | #pragma comment(lib, "dwmapi.lib") 28 | #pragma comment(lib, "opengl32.lib") 29 | 30 | #define HINST_THISCOMPONENT GetModuleHandle(NULL) 31 | 32 | #ifndef WM_NCUAHDRAWCAPTION 33 | #define WM_NCUAHDRAWCAPTION (0x00AE) 34 | #endif 35 | #ifndef WM_NCUAHDRAWFRAME 36 | #define WM_NCUAHDRAWFRAME (0x00AF) 37 | #endif 38 | 39 | static void update_region(struct window *data) 40 | { 41 | RECT old_rgn = data->rgn; 42 | RECT r = {0}; 43 | 44 | if (IsMaximized(data->hwnd)) { 45 | WINDOWINFO wi = {}; 46 | wi.cbSize = sizeof(wi); 47 | GetWindowInfo(data->hwnd, &wi); 48 | 49 | /* For maximized windows, a region is needed to cut off the non-client 50 | borders that hang over the edge of the screen */ 51 | data->rgn.left = wi.rcClient.left - wi.rcWindow.left; 52 | data->rgn.top = wi.rcClient.top - wi.rcWindow.top; 53 | data->rgn.right = wi.rcClient.right - wi.rcWindow.left; 54 | data->rgn.bottom = wi.rcClient.bottom - wi.rcWindow.top; 55 | } else if (!data->composition_enabled) { 56 | /* For ordinary themed windows when composition is disabled, a region 57 | is needed to remove the rounded top corners. Make it as large as 58 | possible to avoid having to change it when the window is resized. */ 59 | data->rgn.left = 0; 60 | data->rgn.top = 0; 61 | data->rgn.right = 32767; 62 | data->rgn.bottom = 32767; 63 | } else { 64 | /* Don't mess with the region when composition is enabled and the 65 | window is not maximized, otherwise it will lose its shadow */ 66 | data->rgn = r; 67 | } 68 | 69 | /* Avoid unnecessarily updating the region to avoid unnecessary redraws */ 70 | if (EqualRect(&data->rgn, &old_rgn)) 71 | return; 72 | /* Treat empty regions as NULL regions */ 73 | if (EqualRect(&data->rgn, &r)) 74 | SetWindowRgn(data->hwnd, NULL, TRUE); 75 | else 76 | SetWindowRgn(data->hwnd, CreateRectRgnIndirect(&data->rgn), TRUE); 77 | } 78 | 79 | static void handle_nccreate(HWND window, CREATESTRUCTW *cs) 80 | { 81 | struct window *data = (struct window*)cs->lpCreateParams; 82 | SetWindowLongPtrW(window, GWLP_USERDATA, (LONG_PTR)data); 83 | } 84 | 85 | static void handle_compositionchanged(struct window *data) 86 | { 87 | BOOL enabled = FALSE; 88 | DwmIsCompositionEnabled(&enabled); 89 | data->composition_enabled = enabled == TRUE; 90 | 91 | if (enabled) { 92 | /* The window needs a frame to show a shadow, so give it the smallest 93 | amount of frame possible */ 94 | MARGINS m = {0}; 95 | m.cyTopHeight = 1; 96 | DwmExtendFrameIntoClientArea(data->hwnd, &m); 97 | DWORD state = DWMNCRP_ENABLED; 98 | DwmSetWindowAttribute(data->hwnd, DWMWA_NCRENDERING_POLICY, &state, sizeof(DWORD)); 99 | } 100 | 101 | update_region(data); 102 | } 103 | 104 | static bool has_autohide_appbar(UINT edge, RECT mon) 105 | { 106 | APPBARDATA abd = {}; 107 | abd.cbSize = sizeof(APPBARDATA); 108 | abd.uEdge = edge; 109 | if (IsWindows8Point1OrGreater()) { 110 | abd.rc = mon; 111 | return SHAppBarMessage(ABM_GETAUTOHIDEBAREX, &abd) == TRUE; 112 | } 113 | 114 | /* Before Windows 8.1, it was not possible to specify a monitor when 115 | checking for hidden appbars, so check only on the primary monitor */ 116 | if (mon.left != 0 || mon.top != 0) 117 | return false; 118 | return SHAppBarMessage(ABM_GETAUTOHIDEBAR, &abd) == TRUE; 119 | } 120 | 121 | static void handle_nccalcsize(struct window *data, WPARAM wparam, 122 | LPARAM lparam) 123 | { 124 | union { 125 | LPARAM lparam; 126 | RECT* rect; 127 | } params = { lparam }; 128 | 129 | /* DefWindowProc must be called in both the maximized and non-maximized 130 | cases, otherwise tile/cascade windows won't work */ 131 | RECT nonclient = *params.rect; 132 | DefWindowProcW(data->hwnd, WM_NCCALCSIZE, wparam, params.lparam); 133 | RECT client = *params.rect; 134 | 135 | if (IsMaximized(data->hwnd)) { 136 | WINDOWINFO wi = {0}; 137 | wi.cbSize = sizeof(wi); 138 | GetWindowInfo(data->hwnd, &wi); 139 | 140 | /* Maximized windows always have a non-client border that hangs over 141 | the edge of the screen, so the size proposed by WM_NCCALCSIZE is 142 | fine. Just adjust the top border to remove the window title. */ 143 | RECT r; 144 | r.left = client.left; 145 | r.top = nonclient.top + wi.cyWindowBorders; 146 | r.right = client.right; 147 | r.bottom = client.bottom; 148 | *params.rect = r; 149 | 150 | HMONITOR mon = MonitorFromWindow(data->hwnd, MONITOR_DEFAULTTOPRIMARY); 151 | MONITORINFO mi = {0}; 152 | mi.cbSize = sizeof(mi); 153 | GetMonitorInfoW(mon, &mi); 154 | 155 | /* If the client rectangle is the same as the monitor's rectangle, 156 | the shell assumes that the window has gone fullscreen, so it removes 157 | the topmost attribute from any auto-hide appbars, making them 158 | inaccessible. To avoid this, reduce the size of the client area by 159 | one pixel on a certain edge. The edge is chosen based on which side 160 | of the monitor is likely to contain an auto-hide appbar, so the 161 | missing client area is covered by it. */ 162 | if (EqualRect(params.rect, &mi.rcMonitor)) { 163 | if (has_autohide_appbar(ABE_BOTTOM, mi.rcMonitor)) 164 | params.rect->bottom--; 165 | else if (has_autohide_appbar(ABE_LEFT, mi.rcMonitor)) 166 | params.rect->left++; 167 | else if (has_autohide_appbar(ABE_TOP, mi.rcMonitor)) 168 | params.rect->top++; 169 | else if (has_autohide_appbar(ABE_RIGHT, mi.rcMonitor)) 170 | params.rect->right--; 171 | } 172 | } else { 173 | /* For the non-maximized case, set the output RECT to what it was 174 | before WM_NCCALCSIZE modified it. This will make the client size the 175 | same as the non-client size. */ 176 | *params.rect = nonclient; 177 | } 178 | } 179 | 180 | static LRESULT handle_nchittest(struct window *data, int x, int y) 181 | { 182 | if (IsMaximized(data->hwnd)) 183 | return HTCLIENT; 184 | 185 | POINT mouse = { x, y }; 186 | ScreenToClient(data->hwnd, &mouse); 187 | 188 | /* The horizontal frame should be the same size as the vertical frame, 189 | since the NONCLIENTMETRICS structure does not distinguish between them */ 190 | int frame_size = GetSystemMetrics(SM_CXFRAME); // + GetSystemMetrics(SM_CXPADDEDBORDER); 191 | /* The diagonal size handles are wider than the frame */ 192 | int diagonal_width = frame_size * 2 + GetSystemMetrics(SM_CXBORDER); 193 | 194 | if (mouse.y < frame_size) { 195 | if (mouse.x < diagonal_width) 196 | return HTTOPLEFT; 197 | if (mouse.x >= (int)data->width - diagonal_width) 198 | return HTTOPRIGHT; 199 | return HTTOP; 200 | } 201 | 202 | if (mouse.y >= (int)data->height - frame_size) { 203 | if (mouse.x < diagonal_width) 204 | return HTBOTTOMLEFT; 205 | if (mouse.x >= (int)data->width - (int)diagonal_width) 206 | return HTBOTTOMRIGHT; 207 | return HTBOTTOM; 208 | } 209 | 210 | if (mouse.x < frame_size) 211 | return HTLEFT; 212 | if (mouse.x >= (int)data->width - frame_size) 213 | return HTRIGHT; 214 | return HTCLIENT; 215 | } 216 | 217 | static void handle_themechanged(struct window *data) 218 | { 219 | data->theme_enabled = IsThemeActive() == TRUE; 220 | } 221 | 222 | static void handle_windowposchanged(struct window *data, const WINDOWPOS *pos) 223 | { 224 | RECT client; 225 | GetClientRect(data->hwnd, &client); 226 | unsigned old_width = data->width; 227 | unsigned old_height = data->height; 228 | data->width = client.right; 229 | data->height = client.bottom; 230 | bool client_changed = data->width != old_width || data->height != old_height; 231 | 232 | if (client_changed || (pos->flags & SWP_FRAMECHANGED)) 233 | update_region(data); 234 | 235 | if (client_changed) { 236 | /* Invalidate the changed parts of the rectangle drawn in WM_PAINT */ 237 | if (data->width > old_width) { 238 | RECT r = { (LONG)(old_width - 1), (LONG)0, (LONG)old_width, (LONG)old_height }; 239 | InvalidateRect(data->hwnd, &r, TRUE); 240 | } else { 241 | RECT r = { (LONG)(data->width - 1), (LONG)0, (LONG)data->width, (LONG)data->height }; 242 | InvalidateRect(data->hwnd, &r, TRUE); 243 | } 244 | if (data->height > old_height) { 245 | RECT r = { (LONG)0, (LONG)(old_height - 1), (LONG)old_width, (LONG)old_height }; 246 | InvalidateRect(data->hwnd, &r, TRUE); 247 | } else { 248 | RECT r = { (LONG)0, (LONG)(data->height - 1), (LONG)data->width, (LONG)data->height }; 249 | InvalidateRect(data->hwnd, &r, TRUE); 250 | } 251 | } 252 | } 253 | 254 | static LRESULT handle_message_invisible(HWND window, UINT msg, WPARAM wparam, LPARAM lparam) 255 | { 256 | LONG_PTR old_style = GetWindowLongPtrW(window, GWL_STYLE); 257 | 258 | /* Prevent Windows from drawing the default title bar by temporarily 259 | toggling the WS_VISIBLE style. This is recommended in: 260 | https://blogs.msdn.microsoft.com/wpfsdk/2008/09/08/custom-window-chrome-in-wpf/ */ 261 | SetWindowLongPtrW(window, GWL_STYLE, old_style & ~WS_VISIBLE); 262 | LRESULT result = DefWindowProcW(window, msg, wparam, lparam); 263 | SetWindowLongPtrW(window, GWL_STYLE, old_style); 264 | 265 | return result; 266 | } 267 | 268 | static LRESULT CALLBACK borderless_window_proc(HWND window, UINT msg, WPARAM wparam, LPARAM lparam) 269 | { 270 | struct window *data = (struct window*)GetWindowLongPtrW(window, GWLP_USERDATA); 271 | if (!data) { 272 | /* Due to a longstanding Windows bug, overlapped windows will receive a 273 | WM_GETMINMAXINFO message before WM_NCCREATE. This is safe to ignore. 274 | It doesn't need any special handling anyway. */ 275 | if (msg == WM_NCCREATE) 276 | handle_nccreate(window, (CREATESTRUCTW*)lparam); 277 | return DefWindowProcW(window, msg, wparam, lparam); 278 | } 279 | 280 | switch (msg) { 281 | case WM_CLOSE: 282 | DestroyWindow(window); 283 | return 0; 284 | case WM_DESTROY: 285 | PostQuitMessage(0); 286 | return 0; 287 | case WM_DWMCOMPOSITIONCHANGED: 288 | handle_compositionchanged(data); 289 | return 0; 290 | case WM_NCACTIVATE: 291 | /* DefWindowProc won't repaint the window border if lParam (normally a HRGN) is -1. This is recommended in: 292 | https://blogs.msdn.microsoft.com/wpfsdk/2008/09/08/custom-window-chrome-in-wpf/ */ 293 | return DefWindowProcW(window, msg, wparam, -1); 294 | case WM_NCCALCSIZE: 295 | handle_nccalcsize(data, wparam, lparam); 296 | return 0; 297 | case WM_NCHITTEST: 298 | return handle_nchittest(data, GET_X_LPARAM(lparam), GET_Y_LPARAM(lparam)); 299 | case WM_NCPAINT: 300 | /* Only block WM_NCPAINT when composition is disabled. If it's blocked 301 | when composition is enabled, the window shadow won't be drawn. */ 302 | if (!data->composition_enabled) 303 | return 0; 304 | break; 305 | case WM_NCUAHDRAWCAPTION: 306 | case WM_NCUAHDRAWFRAME: 307 | /* These undocumented messages are sent to draw themed window borders. 308 | Block them to prevent drawing borders over the client area. */ 309 | return 0; 310 | case WM_SETICON: 311 | case WM_SETTEXT: 312 | /* Disable painting while these messages are handled to prevent them 313 | from drawing a window caption over the client area, but only when 314 | composition and theming are disabled. These messages don't paint 315 | when composition is enabled and blocking WM_NCUAHDRAWCAPTION should 316 | be enough to prevent painting when theming is enabled. */ 317 | if (!data->composition_enabled && !data->theme_enabled) 318 | return handle_message_invisible(window, msg, wparam, lparam); 319 | break; 320 | case WM_SIZE: 321 | data->minimized = wparam == SIZE_MINIMIZED; 322 | data->maximized = wparam == SIZE_MAXIMIZED; 323 | return 0; 324 | case WM_THEMECHANGED: 325 | handle_themechanged(data); 326 | break; 327 | case WM_WINDOWPOSCHANGED: 328 | handle_windowposchanged(data, (WINDOWPOS*)lparam); 329 | return DefWindowProcW(window, msg, wparam, lparam); // Must be executed so that WM_SIZE and WM_MOVE get sent properly! 330 | } 331 | 332 | if (handle_message(data, msg, wparam, lparam)) 333 | return 0; 334 | 335 | return DefWindowProcW(window, msg, wparam, lparam); 336 | } 337 | 338 | // We're just setting up some oldschool opengl context for testing here, 339 | // because setting up a modern opengl context is a PITA. 340 | HGLRC setup_opengl2(HWND window) 341 | { 342 | HDC hdc = GetDC(window); 343 | if (!hdc) 344 | { 345 | MessageBoxA(window, "GetDC failed", "ERROR", MB_OK); 346 | return NULL; 347 | } 348 | 349 | static PIXELFORMATDESCRIPTOR pfd = 350 | { 351 | sizeof(PIXELFORMATDESCRIPTOR), 352 | 1, 353 | PFD_DRAW_TO_WINDOW|PFD_SUPPORT_OPENGL|PFD_DOUBLEBUFFER, 354 | PFD_TYPE_RGBA, 355 | 32, 356 | 0, 0, 0, 0, 0, 0, 8, 0, 357 | 0, 0, 0, 0, 0, // accum 358 | 32, // zbuffer 359 | 0, // stencil! 360 | 0, // aux 361 | PFD_MAIN_PLANE, 362 | 0, 0, 0, 0 363 | }; 364 | 365 | unsigned int pf = ChoosePixelFormat(hdc, &pfd); 366 | if (!pf) 367 | { 368 | MessageBoxA(window, "ChoosePixelFormat failed", "ERROR", MB_OK); 369 | return NULL; 370 | } 371 | 372 | if (!SetPixelFormat(hdc, pf, &pfd)) 373 | { 374 | MessageBoxA(window, "SetPixelFormat failed", "ERROR", MB_OK); 375 | return NULL; 376 | } 377 | 378 | HGLRC hglrc = wglCreateContext(hdc); 379 | if (!hglrc) 380 | { 381 | MessageBoxA(window, "wglCreateContext failed", "ERROR", MB_OK); 382 | return NULL; 383 | } 384 | 385 | if (!wglMakeCurrent(hdc, hglrc)) 386 | { 387 | wglDeleteContext(hglrc); 388 | MessageBoxA(window, "wglMakeCurrent failed", "ERROR", MB_OK); 389 | return NULL; 390 | } 391 | 392 | return hglrc; 393 | } 394 | 395 | void shutdown_opengl2(HWND window, HGLRC hglrc) 396 | { 397 | HDC hdc = GetDC(window); 398 | if (!hdc) 399 | { 400 | MessageBoxA(window, "GetDC failed", "ERROR", MB_OK); 401 | return; 402 | } 403 | 404 | wglMakeCurrent(hdc, NULL); 405 | wglDeleteContext(hglrc); 406 | } 407 | 408 | int CALLBACK wWinMain(HINSTANCE /*inst*/, HINSTANCE /*prev*/, LPWSTR /*cmd*/, int /*show*/) 409 | { 410 | WNDCLASSEXW wc = {0}; 411 | wc.cbSize = sizeof(WNDCLASSEXW); 412 | wc.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC | CS_DBLCLKS; 413 | wc.lpfnWndProc = borderless_window_proc; 414 | wc.hInstance = HINST_THISCOMPONENT; 415 | wc.hCursor = LoadCursor(NULL, IDC_ARROW); 416 | wc.hbrBackground = NULL; 417 | wc.lpszClassName = L"borderless-window"; 418 | ATOM cls = RegisterClassExW(&wc); 419 | 420 | struct window *data = (struct window*)calloc(1, sizeof(struct window)); 421 | data->hwnd = CreateWindowExW( 422 | WS_EX_APPWINDOW | WS_EX_LAYERED, 423 | (LPWSTR)MAKEINTATOM(cls), 424 | L"Borderless Window", 425 | WS_OVERLAPPEDWINDOW | WS_SIZEBOX, 426 | CW_USEDEFAULT, CW_USEDEFAULT, 1280, 960, 427 | NULL, NULL, HINST_THISCOMPONENT, data); 428 | 429 | /* Make the window a layered window so the legacy GDI API can be used to 430 | draw to it without messing up the area on top of the DWM frame. Note: 431 | This is not necessary if other drawing APIs are used, eg. GDI+, OpenGL, 432 | Direct2D, Direct3D, DirectComposition, etc. */ 433 | 434 | // Apparently it actually is necessary if you want compositing to work properly with alpha blending!? 435 | SetLayeredWindowAttributes(data->hwnd, RGB(255, 255, 255), 255, LWA_COLORKEY); 436 | 437 | handle_compositionchanged(data); 438 | handle_themechanged(data); 439 | 440 | HGLRC hglrc = setup_opengl2(data->hwnd); 441 | MSG message = {0}; 442 | if (hglrc) 443 | { 444 | handle_init(data); 445 | 446 | ShowWindow(data->hwnd, SW_SHOWDEFAULT); 447 | UpdateWindow(data->hwnd); 448 | 449 | while (GetMessageW(&message, NULL, 0, 0)) { 450 | TranslateMessage(&message); 451 | DispatchMessageW(&message); 452 | } 453 | 454 | handle_shutdown(data); 455 | shutdown_opengl2(data->hwnd, hglrc); 456 | } 457 | 458 | free(data); 459 | UnregisterClassW((LPWSTR)MAKEINTATOM(cls), HINST_THISCOMPONENT); 460 | return (int)message.wParam; 461 | } 462 | -------------------------------------------------------------------------------- /borderless-window.exe.manifest: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | borderless-window 5 | 6 | 7 | True/PM 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /imgui_winapi_gl2/LICENSE.txt: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014-2018 Omar Cornut 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /imgui_winapi_gl2/imconfig.h: -------------------------------------------------------------------------------- 1 | //----------------------------------------------------------------------------- 2 | // COMPILE-TIME OPTIONS FOR DEAR IMGUI 3 | // Most options (memory allocation, clipboard callbacks, etc.) can be set at runtime via the ImGuiIO structure - ImGui::GetIO(). 4 | //----------------------------------------------------------------------------- 5 | // A) You may edit imconfig.h (and not overwrite it when updating imgui, or maintain a patch/branch with your modifications to imconfig.h) 6 | // B) or add configuration directives in your own file and compile with #define IMGUI_USER_CONFIG "myfilename.h" 7 | // Note that options such as IMGUI_API, IM_VEC2_CLASS_EXTRA or ImDrawIdx needs to be defined consistently everywhere you include imgui.h, not only for the imgui*.cpp compilation units. 8 | //----------------------------------------------------------------------------- 9 | 10 | #pragma once 11 | 12 | //---- Define assertion handler. Defaults to calling assert(). 13 | //#define IM_ASSERT(_EXPR) MyAssert(_EXPR) 14 | 15 | //---- Define attributes of all API symbols declarations, e.g. for DLL under Windows. 16 | //#define IMGUI_API __declspec( dllexport ) 17 | //#define IMGUI_API __declspec( dllimport ) 18 | 19 | //---- Don't define obsolete functions names. Consider enabling from time to time or when updating to reduce likelihood of using already obsolete function/names 20 | //#define IMGUI_DISABLE_OBSOLETE_FUNCTIONS 21 | 22 | //---- Don't implement default handlers for Windows (so as not to link with certain functions) 23 | //#define IMGUI_DISABLE_WIN32_DEFAULT_CLIPBOARD_FUNCTIONS // Don't use and link with OpenClipboard/GetClipboardData/CloseClipboard etc. 24 | //#define IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCTIONS // Don't use and link with ImmGetContext/ImmSetCompositionWindow. 25 | 26 | //---- Don't implement demo windows functionality (ShowDemoWindow()/ShowStyleEditor()/ShowUserGuide() methods will be empty) 27 | //---- It is very strongly recommended to NOT disable the demo windows. Please read the comment at the top of imgui_demo.cpp. 28 | //#define IMGUI_DISABLE_DEMO_WINDOWS 29 | 30 | //---- Don't implement ImFormatString(), ImFormatStringV() so you can reimplement them yourself. 31 | //#define IMGUI_DISABLE_FORMAT_STRING_FUNCTIONS 32 | 33 | //---- Include imgui_user.h at the end of imgui.h as a convenience 34 | //#define IMGUI_INCLUDE_IMGUI_USER_H 35 | 36 | //---- Pack colors to BGRA8 instead of RGBA8 (if you needed to convert from one to another anyway) 37 | //#define IMGUI_USE_BGRA_PACKED_COLOR 38 | 39 | //---- Implement STB libraries in a namespace to avoid linkage conflicts (defaults to global namespace) 40 | //#define IMGUI_STB_NAMESPACE ImGuiStb 41 | 42 | //---- Define constructor and implicit cast operators to convert back<>forth from your math types and ImVec2/ImVec4. 43 | // This will be inlined as part of ImVec2 and ImVec4 class declarations. 44 | /* 45 | #define IM_VEC2_CLASS_EXTRA \ 46 | ImVec2(const MyVec2& f) { x = f.x; y = f.y; } \ 47 | operator MyVec2() const { return MyVec2(x,y); } 48 | 49 | #define IM_VEC4_CLASS_EXTRA \ 50 | ImVec4(const MyVec4& f) { x = f.x; y = f.y; z = f.z; w = f.w; } \ 51 | operator MyVec4() const { return MyVec4(x,y,z,w); } 52 | */ 53 | 54 | //---- Use 32-bit vertex indices (instead of default 16-bit) to allow meshes with more than 64K vertices. Render function needs to support it. 55 | //#define ImDrawIdx unsigned int 56 | 57 | //---- Tip: You can add extra functions within the ImGui:: namespace, here or in your own headers files. 58 | /* 59 | namespace ImGui 60 | { 61 | void MyFunction(const char* name, const MyMatrix44& v); 62 | } 63 | */ 64 | -------------------------------------------------------------------------------- /imgui_winapi_gl2/imgui_impl_gl2.cpp: -------------------------------------------------------------------------------- 1 | // Incomplete WinAPI ImGui binding with OpenGL (legacy, fixed pipeline) without any user input. 2 | 3 | // Implemented features: 4 | // [X] User texture binding. Cast 'GLuint' OpenGL texture identifier as void*/ImTextureID. Read the FAQ about ImTextureID in imgui.cpp. 5 | 6 | // **DO NOT USE THIS CODE IF YOUR CODE/ENGINE IS USING MODERN OPENGL (SHADERS, VBO, VAO, etc.)** 7 | // **Prefer using the code in the opengl3_example/ folder** 8 | // If your code is using GL3+ context or any semi modern OpenGL calls, using this is likely to make everything more 9 | // complicated, will require your code to reset every single OpenGL attributes to their initial state, and might 10 | // confuse your GPU driver. 11 | // The GL2 code is unable to reset attributes or even call e.g. "glUseProgram(0)" because they don't exist in that API. 12 | 13 | // You can copy and use unmodified imgui_impl_* files in your project. See main.cpp for an example of using this. 14 | // If you use this binding you'll need to call 4 functions: ImGui_ImplXXXX_Init(), ImGui_ImplXXXX_NewFrame(), ImGui::Render() and ImGui_ImplXXXX_Shutdown(). 15 | // If you are new to ImGui, see examples/README.txt and documentation at the top of imgui.cpp. 16 | // https://github.com/ocornut/imgui 17 | 18 | #include "windows.h" 19 | #include "GL/gl.h" 20 | #include "imgui.h" 21 | #include "imgui_impl_gl2.h" 22 | 23 | // TODO: Add cursor support 24 | 25 | // WinAPI data 26 | static HWND g_Window; 27 | static double g_RcpQueryPerformanceFrequency; 28 | static LARGE_INTEGER g_QueryPerformanceCounterStart; 29 | static double g_Time; 30 | 31 | // OpenGL data 32 | static GLuint g_FontTexture = 0; 33 | 34 | // OpenGL2 Render function. 35 | // (this used to be set in io.RenderDrawListsFn and called by ImGui::Render(), but you can now call this directly from your main loop) 36 | // Note that this implementation is little overcomplicated because we are saving/setting up/restoring every OpenGL state explicitly, in order to be able to run within any OpenGL engine that doesn't do so. 37 | void ImGui_ImplGL2_RenderDrawData(ImDrawData* draw_data) 38 | { 39 | // Avoid rendering when minimized, scale coordinates for retina displays (screen coordinates != framebuffer coordinates) 40 | ImGuiIO& io = ImGui::GetIO(); 41 | int fb_width = (int)(io.DisplaySize.x * io.DisplayFramebufferScale.x); 42 | int fb_height = (int)(io.DisplaySize.y * io.DisplayFramebufferScale.y); 43 | if (fb_width == 0 || fb_height == 0) 44 | return; 45 | draw_data->ScaleClipRects(io.DisplayFramebufferScale); 46 | 47 | // We are using the OpenGL fixed pipeline to make the example code simpler to read! 48 | // Setup render state: alpha-blending enabled, no face culling, no depth testing, scissor enabled, vertex/texcoord/color pointers, polygon fill. 49 | GLint last_texture; glGetIntegerv(GL_TEXTURE_BINDING_2D, &last_texture); 50 | GLint last_polygon_mode[2]; glGetIntegerv(GL_POLYGON_MODE, last_polygon_mode); 51 | GLint last_viewport[4]; glGetIntegerv(GL_VIEWPORT, last_viewport); 52 | GLint last_scissor_box[4]; glGetIntegerv(GL_SCISSOR_BOX, last_scissor_box); 53 | glPushAttrib(GL_ENABLE_BIT | GL_COLOR_BUFFER_BIT | GL_TRANSFORM_BIT); 54 | glEnable(GL_BLEND); 55 | glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); 56 | glDisable(GL_CULL_FACE); 57 | glDisable(GL_DEPTH_TEST); 58 | glEnable(GL_SCISSOR_TEST); 59 | glEnableClientState(GL_VERTEX_ARRAY); 60 | glEnableClientState(GL_TEXTURE_COORD_ARRAY); 61 | glEnableClientState(GL_COLOR_ARRAY); 62 | glEnable(GL_TEXTURE_2D); 63 | glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); 64 | //glUseProgram(0); // You may want this if using this code in an OpenGL 3+ context where shaders may be bound 65 | 66 | // Setup viewport, orthographic projection matrix 67 | glViewport(0, 0, (GLsizei)fb_width, (GLsizei)fb_height); 68 | glMatrixMode(GL_PROJECTION); 69 | glPushMatrix(); 70 | glLoadIdentity(); 71 | glOrtho(0.0f, io.DisplaySize.x, io.DisplaySize.y, 0.0f, -1.0f, +1.0f); 72 | glMatrixMode(GL_MODELVIEW); 73 | glPushMatrix(); 74 | glLoadIdentity(); 75 | 76 | // Render command lists 77 | for (int n = 0; n < draw_data->CmdListsCount; n++) 78 | { 79 | const ImDrawList* cmd_list = draw_data->CmdLists[n]; 80 | const ImDrawVert* vtx_buffer = cmd_list->VtxBuffer.Data; 81 | const ImDrawIdx* idx_buffer = cmd_list->IdxBuffer.Data; 82 | glVertexPointer(2, GL_FLOAT, sizeof(ImDrawVert), (const GLvoid*)((const char*)vtx_buffer + IM_OFFSETOF(ImDrawVert, pos))); 83 | glTexCoordPointer(2, GL_FLOAT, sizeof(ImDrawVert), (const GLvoid*)((const char*)vtx_buffer + IM_OFFSETOF(ImDrawVert, uv))); 84 | glColorPointer(4, GL_UNSIGNED_BYTE, sizeof(ImDrawVert), (const GLvoid*)((const char*)vtx_buffer + IM_OFFSETOF(ImDrawVert, col))); 85 | 86 | for (int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.Size; cmd_i++) 87 | { 88 | const ImDrawCmd* pcmd = &cmd_list->CmdBuffer[cmd_i]; 89 | if (pcmd->UserCallback) 90 | { 91 | pcmd->UserCallback(cmd_list, pcmd); 92 | } 93 | else 94 | { 95 | glBindTexture(GL_TEXTURE_2D, (GLuint)(intptr_t)pcmd->TextureId); 96 | glScissor((int)pcmd->ClipRect.x, (int)(fb_height - pcmd->ClipRect.w), (int)(pcmd->ClipRect.z - pcmd->ClipRect.x), (int)(pcmd->ClipRect.w - pcmd->ClipRect.y)); 97 | glDrawElements(GL_TRIANGLES, (GLsizei)pcmd->ElemCount, sizeof(ImDrawIdx) == 2 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT, idx_buffer); 98 | } 99 | idx_buffer += pcmd->ElemCount; 100 | } 101 | } 102 | 103 | // Restore modified state 104 | glDisableClientState(GL_COLOR_ARRAY); 105 | glDisableClientState(GL_TEXTURE_COORD_ARRAY); 106 | glDisableClientState(GL_VERTEX_ARRAY); 107 | glBindTexture(GL_TEXTURE_2D, (GLuint)last_texture); 108 | glMatrixMode(GL_MODELVIEW); 109 | glPopMatrix(); 110 | glMatrixMode(GL_PROJECTION); 111 | glPopMatrix(); 112 | glPopAttrib(); 113 | glPolygonMode(GL_FRONT, (GLenum)last_polygon_mode[0]); glPolygonMode(GL_BACK, (GLenum)last_polygon_mode[1]); 114 | glViewport(last_viewport[0], last_viewport[1], (GLsizei)last_viewport[2], (GLsizei)last_viewport[3]); 115 | glScissor(last_scissor_box[0], last_scissor_box[1], (GLsizei)last_scissor_box[2], (GLsizei)last_scissor_box[3]); 116 | } 117 | 118 | static const char* ImGui_ImplGL2_GetClipboardText(void* /*user_data*/) 119 | { 120 | static char buffer[65536]; 121 | if (OpenClipboard(NULL)) 122 | { 123 | const char* text = (const char*)GetClipboardData(CF_TEXT); 124 | strncpy_s(buffer, text, sizeof(buffer)); 125 | CloseClipboard(); 126 | } 127 | return buffer; 128 | } 129 | 130 | static void ImGui_ImplGL2_SetClipboardText(void* /*user_data*/, const char* text) 131 | { 132 | const size_t len = strlen(text) + 1; 133 | HGLOBAL hMem = GlobalAlloc(GMEM_MOVEABLE, len); 134 | if (hMem) 135 | { 136 | memcpy(GlobalLock(hMem), text, len); 137 | GlobalUnlock(hMem); 138 | if (OpenClipboard(NULL)) 139 | { 140 | EmptyClipboard(); 141 | SetClipboardData(CF_TEXT, hMem); 142 | CloseClipboard(); 143 | } 144 | } 145 | } 146 | 147 | bool ImGui_ImplGL2_CreateDeviceObjects() 148 | { 149 | // Build texture atlas 150 | ImGuiIO& io = ImGui::GetIO(); 151 | unsigned char* pixels; 152 | int width, height; 153 | io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height); // Load as RGBA 32-bits (75% of the memory is wasted, but default font is so small) because it is more likely to be compatible with user's existing shaders. If your ImTextureId represent a higher-level concept than just a GL texture id, consider calling GetTexDataAsAlpha8() instead to save on GPU memory. 154 | 155 | // Upload texture to graphics system 156 | GLint last_texture; 157 | glGetIntegerv(GL_TEXTURE_BINDING_2D, &last_texture); 158 | glGenTextures(1, &g_FontTexture); 159 | glBindTexture(GL_TEXTURE_2D, g_FontTexture); 160 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); 161 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); 162 | glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); 163 | glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels); 164 | 165 | // Store our identifier 166 | io.Fonts->TexID = (void *)(intptr_t)g_FontTexture; 167 | 168 | // Restore state 169 | glBindTexture(GL_TEXTURE_2D, last_texture); 170 | 171 | return true; 172 | } 173 | 174 | void ImGui_ImplGL2_InvalidateDeviceObjects() 175 | { 176 | if (g_FontTexture) 177 | { 178 | glDeleteTextures(1, &g_FontTexture); 179 | ImGui::GetIO().Fonts->TexID = 0; 180 | g_FontTexture = 0; 181 | } 182 | } 183 | 184 | bool ImGui_ImplGL2_Init(HWND window) 185 | { 186 | g_Window = window; 187 | 188 | ImGuiIO& io = ImGui::GetIO(); 189 | io.KeyMap[ImGuiKey_Tab] = VK_TAB; // Keyboard mapping. ImGui will use those indices to peek into the io.KeyDown[] array that we will update during the application lifetime. 190 | io.KeyMap[ImGuiKey_LeftArrow] = VK_LEFT; 191 | io.KeyMap[ImGuiKey_RightArrow] = VK_RIGHT; 192 | io.KeyMap[ImGuiKey_UpArrow] = VK_UP; 193 | io.KeyMap[ImGuiKey_DownArrow] = VK_DOWN; 194 | io.KeyMap[ImGuiKey_PageUp] = VK_PRIOR; 195 | io.KeyMap[ImGuiKey_PageDown] = VK_NEXT; 196 | io.KeyMap[ImGuiKey_Home] = VK_HOME; 197 | io.KeyMap[ImGuiKey_End] = VK_END; 198 | io.KeyMap[ImGuiKey_Delete] = VK_DELETE; 199 | io.KeyMap[ImGuiKey_Backspace] = VK_BACK; 200 | io.KeyMap[ImGuiKey_Enter] = VK_RETURN; 201 | io.KeyMap[ImGuiKey_Escape] = VK_ESCAPE; 202 | io.KeyMap[ImGuiKey_A] = 'A'; 203 | io.KeyMap[ImGuiKey_C] = 'C'; 204 | io.KeyMap[ImGuiKey_V] = 'V'; 205 | io.KeyMap[ImGuiKey_X] = 'X'; 206 | io.KeyMap[ImGuiKey_Y] = 'Y'; 207 | io.KeyMap[ImGuiKey_Z] = 'Z'; 208 | 209 | io.SetClipboardTextFn = ImGui_ImplGL2_SetClipboardText; 210 | io.GetClipboardTextFn = ImGui_ImplGL2_GetClipboardText; 211 | //io.ClipboardUserData = window; 212 | io.ImeWindowHandle = window; 213 | 214 | LARGE_INTEGER qpf; 215 | QueryPerformanceFrequency(&qpf); 216 | g_RcpQueryPerformanceFrequency = 1.0 / (double)qpf.QuadPart; 217 | QueryPerformanceCounter(&g_QueryPerformanceCounterStart); 218 | 219 | return true; 220 | } 221 | 222 | void ImGui_ImplGL2_Shutdown() 223 | { 224 | // Destroy OpenGL objects 225 | ImGui_ImplGL2_InvalidateDeviceObjects(); 226 | } 227 | 228 | bool ImGui_ImplGL2_Handle_Message(UINT msg, WPARAM wparam, LPARAM lparam) 229 | { 230 | if (!ImGui::GetCurrentContext()) 231 | return false; 232 | 233 | ImGuiIO& io = ImGui::GetIO(); 234 | switch(msg) 235 | { 236 | case WM_KEYDOWN: 237 | case WM_KEYUP: 238 | { 239 | bool isDown = ((lparam & (1 << 31)) == 0); 240 | unsigned int vkCode = (unsigned int)wparam; 241 | if (vkCode < 256) 242 | { 243 | io.KeysDown[vkCode] = isDown ? 1 : 0; 244 | return true; 245 | } 246 | } break; 247 | 248 | case WM_CHAR: 249 | { 250 | unsigned short ch = (unsigned short)wparam; 251 | if (ch > 0 && ch < 0x10000) 252 | { 253 | io.AddInputCharacter(ch); 254 | return true; 255 | } 256 | } break; 257 | 258 | case WM_MOUSEMOVE: 259 | { 260 | io.MousePos.x = (float)LOWORD(lparam); 261 | io.MousePos.y = (float)HIWORD(lparam); 262 | return true; 263 | } break; 264 | 265 | case WM_MOUSEWHEEL: 266 | { 267 | int mouseZ = GET_WHEEL_DELTA_WPARAM(wparam); 268 | io.MouseWheel = mouseZ > 0 ? 1.0f : -1.0f; 269 | return true; 270 | } break; 271 | 272 | case WM_LBUTTONDOWN: 273 | case WM_MBUTTONDOWN: 274 | case WM_RBUTTONDOWN: 275 | { 276 | int button = 0; 277 | if (msg == WM_LBUTTONDOWN) button = 0; 278 | if (msg == WM_RBUTTONDOWN) button = 1; 279 | if (msg == WM_MBUTTONDOWN) button = 2; 280 | io.MouseDown[button] = true; 281 | SetCapture(g_Window); 282 | return true; 283 | } break; 284 | 285 | case WM_LBUTTONUP: 286 | case WM_MBUTTONUP: 287 | case WM_RBUTTONUP: 288 | { 289 | int button = 0; 290 | if (msg == WM_LBUTTONUP) button = 0; 291 | if (msg == WM_RBUTTONUP) button = 1; 292 | if (msg == WM_MBUTTONUP) button = 2; 293 | io.MouseDown[button] = false; 294 | ReleaseCapture(); 295 | return true; 296 | } break; 297 | 298 | case WM_LBUTTONDBLCLK: 299 | case WM_MBUTTONDBLCLK: 300 | case WM_RBUTTONDBLCLK: 301 | { 302 | int button = 0; 303 | if (msg == WM_LBUTTONDBLCLK) button = 0; 304 | if (msg == WM_RBUTTONDBLCLK) button = 1; 305 | if (msg == WM_MBUTTONDBLCLK) button = 2; 306 | 307 | // Force a double click: 308 | io.MouseDown[button] = true; 309 | io.MouseClickedTime[button] = ImGui::GetTime(); 310 | return true; 311 | } break; 312 | } 313 | return false; 314 | } 315 | 316 | void ImGui_ImplGL2_NewFrame(int w, int h, int display_w, int display_h) 317 | { 318 | if (!g_FontTexture) 319 | ImGui_ImplGL2_CreateDeviceObjects(); 320 | 321 | ImGuiIO& io = ImGui::GetIO(); 322 | 323 | io.KeyCtrl = (GetKeyState(VK_CONTROL) & 0x8000) != 0; 324 | io.KeyShift = (GetKeyState(VK_SHIFT) & 0x8000) != 0; 325 | io.KeyAlt = (GetKeyState(VK_MENU) & 0x8000) != 0; 326 | io.KeySuper = false; 327 | 328 | // Setup display size (every frame to accommodate for window resizing) 329 | io.DisplaySize = ImVec2((float)w, (float)h); 330 | io.DisplayFramebufferScale = ImVec2(w > 0 ? ((float)display_w / w) : 0, h > 0 ? ((float)display_h / h) : 0); 331 | 332 | // Setup time step 333 | LARGE_INTEGER qpc; 334 | QueryPerformanceCounter(&qpc); 335 | double current_time = (double)(qpc.QuadPart - g_QueryPerformanceCounterStart.QuadPart) * g_RcpQueryPerformanceFrequency; 336 | io.DeltaTime = g_Time > 0.0 ? (float)(current_time - g_Time) : (float)(1.0f/60.0f); 337 | g_Time = current_time; 338 | 339 | // Start the frame. This call will update the io.WantCaptureMouse, io.WantCaptureKeyboard flag that you can use to dispatch inputs (or not) to your application. 340 | ImGui::NewFrame(); 341 | } 342 | -------------------------------------------------------------------------------- /imgui_winapi_gl2/imgui_impl_gl2.h: -------------------------------------------------------------------------------- 1 | // Incomplete WinAPI ImGui binding with OpenGL (legacy, fixed pipeline) without any user input. 2 | 3 | // Implemented features: 4 | // [X] User texture binding. Cast 'GLuint' OpenGL texture identifier as void*/ImTextureID. Read the FAQ about ImTextureID in imgui.cpp. 5 | 6 | // **DO NOT USE THIS CODE IF YOUR CODE/ENGINE IS USING MODERN OPENGL (SHADERS, VBO, VAO, etc.)** 7 | // **Prefer using the code in the opengl3_example/ folder** 8 | // See imgui_impl.cpp for details. 9 | 10 | // You can copy and use unmodified imgui_impl_* files in your project. See main.cpp for an example of using this. 11 | // If you use this binding you'll need to call 4 functions: ImGui_ImplXXXX_Init(), ImGui_ImplXXXX_NewFrame(), ImGui::Render() and ImGui_ImplXXXX_Shutdown(). 12 | // If you are new to ImGui, see examples/README.txt and documentation at the top of imgui.cpp. 13 | // https://github.com/ocornut/imgui 14 | 15 | IMGUI_API bool ImGui_ImplGL2_Init(HWND window); 16 | IMGUI_API void ImGui_ImplGL2_Shutdown(); 17 | IMGUI_API void ImGui_ImplGL2_NewFrame(int w, int h, int display_w, int display_h); 18 | IMGUI_API bool ImGui_ImplGL2_Handle_Message(UINT msg, WPARAM wparam, LPARAM lparam); 19 | IMGUI_API void ImGui_ImplGL2_RenderDrawData(ImDrawData* draw_data); 20 | 21 | // Use if you want to reset your rendering device without losing ImGui state. 22 | IMGUI_API void ImGui_ImplGL2_InvalidateDeviceObjects(); 23 | IMGUI_API bool ImGui_ImplGL2_CreateDeviceObjects(); 24 | -------------------------------------------------------------------------------- /imgui_winapi_gl2/imgui_internal.h: -------------------------------------------------------------------------------- 1 | // dear imgui, v1.60 WIP 2 | // (internals) 3 | 4 | // You may use this file to debug, understand or extend ImGui features but we don't provide any guarantee of forward compatibility! 5 | // Set: 6 | // #define IMGUI_DEFINE_MATH_OPERATORS 7 | // To implement maths operators for ImVec2 (disabled by default to not collide with using IM_VEC2_CLASS_EXTRA along with your own math types+operators) 8 | 9 | #pragma once 10 | 11 | #ifndef IMGUI_VERSION 12 | #error Must include imgui.h before imgui_internal.h 13 | #endif 14 | 15 | #include // FILE* 16 | #include // sqrtf, fabsf, fmodf, powf, floorf, ceilf, cosf, sinf 17 | #include // INT_MIN, INT_MAX 18 | 19 | #ifdef _MSC_VER 20 | #pragma warning (push) 21 | #pragma warning (disable: 4251) // class 'xxx' needs to have dll-interface to be used by clients of struct 'xxx' // when IMGUI_API is set to__declspec(dllexport) 22 | #endif 23 | 24 | #ifdef __clang__ 25 | #pragma clang diagnostic push 26 | #pragma clang diagnostic ignored "-Wunused-function" // for stb_textedit.h 27 | #pragma clang diagnostic ignored "-Wmissing-prototypes" // for stb_textedit.h 28 | #pragma clang diagnostic ignored "-Wold-style-cast" 29 | #endif 30 | 31 | //----------------------------------------------------------------------------- 32 | // Forward Declarations 33 | //----------------------------------------------------------------------------- 34 | 35 | struct ImRect; 36 | struct ImGuiColMod; 37 | struct ImGuiStyleMod; 38 | struct ImGuiGroupData; 39 | struct ImGuiMenuColumns; 40 | struct ImGuiDrawContext; 41 | struct ImGuiTextEditState; 42 | struct ImGuiPopupRef; 43 | struct ImGuiWindow; 44 | struct ImGuiWindowSettings; 45 | 46 | typedef int ImGuiLayoutType; // enum: horizontal or vertical // enum ImGuiLayoutType_ 47 | typedef int ImGuiButtonFlags; // flags: for ButtonEx(), ButtonBehavior() // enum ImGuiButtonFlags_ 48 | typedef int ImGuiItemFlags; // flags: for PushItemFlag() // enum ImGuiItemFlags_ 49 | typedef int ImGuiItemStatusFlags; // flags: storage for DC.LastItemXXX // enum ImGuiItemStatusFlags_ 50 | typedef int ImGuiNavHighlightFlags; // flags: for RenderNavHighlight() // enum ImGuiNavHighlightFlags_ 51 | typedef int ImGuiNavDirSourceFlags; // flags: for GetNavInputAmount2d() // enum ImGuiNavDirSourceFlags_ 52 | typedef int ImGuiSeparatorFlags; // flags: for Separator() - internal // enum ImGuiSeparatorFlags_ 53 | typedef int ImGuiSliderFlags; // flags: for SliderBehavior() // enum ImGuiSliderFlags_ 54 | 55 | //------------------------------------------------------------------------- 56 | // STB libraries 57 | //------------------------------------------------------------------------- 58 | 59 | namespace ImGuiStb 60 | { 61 | 62 | #undef STB_TEXTEDIT_STRING 63 | #undef STB_TEXTEDIT_CHARTYPE 64 | #define STB_TEXTEDIT_STRING ImGuiTextEditState 65 | #define STB_TEXTEDIT_CHARTYPE ImWchar 66 | #define STB_TEXTEDIT_GETWIDTH_NEWLINE -1.0f 67 | #include "stb_textedit.h" 68 | 69 | } // namespace ImGuiStb 70 | 71 | //----------------------------------------------------------------------------- 72 | // Context 73 | //----------------------------------------------------------------------------- 74 | 75 | #ifndef GImGui 76 | extern IMGUI_API ImGuiContext* GImGui; // Current implicit ImGui context pointer 77 | #endif 78 | 79 | //----------------------------------------------------------------------------- 80 | // Helpers 81 | //----------------------------------------------------------------------------- 82 | 83 | #define IM_PI 3.14159265358979323846f 84 | #ifdef _WIN32 85 | #define IM_NEWLINE "\r\n" // Play it nice with Windows users (2018: Notepad _still_ doesn't display files properly when they use Unix-style carriage returns) 86 | #else 87 | #define IM_NEWLINE "\n" 88 | #endif 89 | 90 | // Helpers: UTF-8 <> wchar 91 | IMGUI_API int ImTextStrToUtf8(char* buf, int buf_size, const ImWchar* in_text, const ImWchar* in_text_end); // return output UTF-8 bytes count 92 | IMGUI_API int ImTextCharFromUtf8(unsigned int* out_char, const char* in_text, const char* in_text_end); // return input UTF-8 bytes count 93 | IMGUI_API int ImTextStrFromUtf8(ImWchar* buf, int buf_size, const char* in_text, const char* in_text_end, const char** in_remaining = NULL); // return input UTF-8 bytes count 94 | IMGUI_API int ImTextCountCharsFromUtf8(const char* in_text, const char* in_text_end); // return number of UTF-8 code-points (NOT bytes count) 95 | IMGUI_API int ImTextCountUtf8BytesFromStr(const ImWchar* in_text, const ImWchar* in_text_end); // return number of bytes to express string as UTF-8 code-points 96 | 97 | // Helpers: Misc 98 | IMGUI_API ImU32 ImHash(const void* data, int data_size, ImU32 seed = 0); // Pass data_size==0 for zero-terminated strings 99 | IMGUI_API void* ImFileLoadToMemory(const char* filename, const char* file_open_mode, int* out_file_size = NULL, int padding_bytes = 0); 100 | IMGUI_API FILE* ImFileOpen(const char* filename, const char* file_open_mode); 101 | static inline bool ImCharIsSpace(int c) { return c == ' ' || c == '\t' || c == 0x3000; } 102 | static inline bool ImIsPowerOfTwo(int v) { return v != 0 && (v & (v - 1)) == 0; } 103 | static inline int ImUpperPowerOfTwo(int v) { v--; v |= v >> 1; v |= v >> 2; v |= v >> 4; v |= v >> 8; v |= v >> 16; v++; return v; } 104 | 105 | // Helpers: Geometry 106 | IMGUI_API ImVec2 ImLineClosestPoint(const ImVec2& a, const ImVec2& b, const ImVec2& p); 107 | IMGUI_API bool ImTriangleContainsPoint(const ImVec2& a, const ImVec2& b, const ImVec2& c, const ImVec2& p); 108 | IMGUI_API ImVec2 ImTriangleClosestPoint(const ImVec2& a, const ImVec2& b, const ImVec2& c, const ImVec2& p); 109 | IMGUI_API void ImTriangleBarycentricCoords(const ImVec2& a, const ImVec2& b, const ImVec2& c, const ImVec2& p, float& out_u, float& out_v, float& out_w); 110 | 111 | // Helpers: String 112 | IMGUI_API int ImStricmp(const char* str1, const char* str2); 113 | IMGUI_API int ImStrnicmp(const char* str1, const char* str2, size_t count); 114 | IMGUI_API void ImStrncpy(char* dst, const char* src, size_t count); 115 | IMGUI_API char* ImStrdup(const char* str); 116 | IMGUI_API char* ImStrchrRange(const char* str_begin, const char* str_end, char c); 117 | IMGUI_API int ImStrlenW(const ImWchar* str); 118 | IMGUI_API const ImWchar*ImStrbolW(const ImWchar* buf_mid_line, const ImWchar* buf_begin); // Find beginning-of-line 119 | IMGUI_API const char* ImStristr(const char* haystack, const char* haystack_end, const char* needle, const char* needle_end); 120 | IMGUI_API int ImFormatString(char* buf, size_t buf_size, const char* fmt, ...) IM_FMTARGS(3); 121 | IMGUI_API int ImFormatStringV(char* buf, size_t buf_size, const char* fmt, va_list args) IM_FMTLIST(3); 122 | 123 | // Helpers: Math 124 | // We are keeping those not leaking to the user by default, in the case the user has implicit cast operators between ImVec2 and its own types (when IM_VEC2_CLASS_EXTRA is defined) 125 | #ifdef IMGUI_DEFINE_MATH_OPERATORS 126 | static inline ImVec2 operator*(const ImVec2& lhs, const float rhs) { return ImVec2(lhs.x*rhs, lhs.y*rhs); } 127 | static inline ImVec2 operator/(const ImVec2& lhs, const float rhs) { return ImVec2(lhs.x/rhs, lhs.y/rhs); } 128 | static inline ImVec2 operator+(const ImVec2& lhs, const ImVec2& rhs) { return ImVec2(lhs.x+rhs.x, lhs.y+rhs.y); } 129 | static inline ImVec2 operator-(const ImVec2& lhs, const ImVec2& rhs) { return ImVec2(lhs.x-rhs.x, lhs.y-rhs.y); } 130 | static inline ImVec2 operator*(const ImVec2& lhs, const ImVec2& rhs) { return ImVec2(lhs.x*rhs.x, lhs.y*rhs.y); } 131 | static inline ImVec2 operator/(const ImVec2& lhs, const ImVec2& rhs) { return ImVec2(lhs.x/rhs.x, lhs.y/rhs.y); } 132 | static inline ImVec2& operator+=(ImVec2& lhs, const ImVec2& rhs) { lhs.x += rhs.x; lhs.y += rhs.y; return lhs; } 133 | static inline ImVec2& operator-=(ImVec2& lhs, const ImVec2& rhs) { lhs.x -= rhs.x; lhs.y -= rhs.y; return lhs; } 134 | static inline ImVec2& operator*=(ImVec2& lhs, const float rhs) { lhs.x *= rhs; lhs.y *= rhs; return lhs; } 135 | static inline ImVec2& operator/=(ImVec2& lhs, const float rhs) { lhs.x /= rhs; lhs.y /= rhs; return lhs; } 136 | static inline ImVec4 operator+(const ImVec4& lhs, const ImVec4& rhs) { return ImVec4(lhs.x+rhs.x, lhs.y+rhs.y, lhs.z+rhs.z, lhs.w+rhs.w); } 137 | static inline ImVec4 operator-(const ImVec4& lhs, const ImVec4& rhs) { return ImVec4(lhs.x-rhs.x, lhs.y-rhs.y, lhs.z-rhs.z, lhs.w-rhs.w); } 138 | static inline ImVec4 operator*(const ImVec4& lhs, const ImVec4& rhs) { return ImVec4(lhs.x*rhs.x, lhs.y*rhs.y, lhs.z*rhs.z, lhs.w*rhs.w); } 139 | #endif 140 | 141 | static inline int ImMin(int lhs, int rhs) { return lhs < rhs ? lhs : rhs; } 142 | static inline int ImMax(int lhs, int rhs) { return lhs >= rhs ? lhs : rhs; } 143 | static inline float ImMin(float lhs, float rhs) { return lhs < rhs ? lhs : rhs; } 144 | static inline float ImMax(float lhs, float rhs) { return lhs >= rhs ? lhs : rhs; } 145 | static inline ImVec2 ImMin(const ImVec2& lhs, const ImVec2& rhs) { return ImVec2(lhs.x < rhs.x ? lhs.x : rhs.x, lhs.y < rhs.y ? lhs.y : rhs.y); } 146 | static inline ImVec2 ImMax(const ImVec2& lhs, const ImVec2& rhs) { return ImVec2(lhs.x >= rhs.x ? lhs.x : rhs.x, lhs.y >= rhs.y ? lhs.y : rhs.y); } 147 | static inline int ImClamp(int v, int mn, int mx) { return (v < mn) ? mn : (v > mx) ? mx : v; } 148 | static inline float ImClamp(float v, float mn, float mx) { return (v < mn) ? mn : (v > mx) ? mx : v; } 149 | static inline ImVec2 ImClamp(const ImVec2& f, const ImVec2& mn, ImVec2 mx) { return ImVec2(ImClamp(f.x,mn.x,mx.x), ImClamp(f.y,mn.y,mx.y)); } 150 | static inline float ImSaturate(float f) { return (f < 0.0f) ? 0.0f : (f > 1.0f) ? 1.0f : f; } 151 | static inline void ImSwap(int& a, int& b) { int tmp = a; a = b; b = tmp; } 152 | static inline void ImSwap(float& a, float& b) { float tmp = a; a = b; b = tmp; } 153 | static inline int ImLerp(int a, int b, float t) { return (int)(a + (b - a) * t); } 154 | static inline float ImLerp(float a, float b, float t) { return a + (b - a) * t; } 155 | static inline ImVec2 ImLerp(const ImVec2& a, const ImVec2& b, float t) { return ImVec2(a.x + (b.x - a.x) * t, a.y + (b.y - a.y) * t); } 156 | static inline ImVec2 ImLerp(const ImVec2& a, const ImVec2& b, const ImVec2& t) { return ImVec2(a.x + (b.x - a.x) * t.x, a.y + (b.y - a.y) * t.y); } 157 | static inline ImVec4 ImLerp(const ImVec4& a, const ImVec4& b, float t) { return ImVec4(a.x + (b.x - a.x) * t, a.y + (b.y - a.y) * t, a.z + (b.z - a.z) * t, a.w + (b.w - a.w) * t); } 158 | static inline float ImLengthSqr(const ImVec2& lhs) { return lhs.x*lhs.x + lhs.y*lhs.y; } 159 | static inline float ImLengthSqr(const ImVec4& lhs) { return lhs.x*lhs.x + lhs.y*lhs.y + lhs.z*lhs.z + lhs.w*lhs.w; } 160 | static inline float ImInvLength(const ImVec2& lhs, float fail_value) { float d = lhs.x*lhs.x + lhs.y*lhs.y; if (d > 0.0f) return 1.0f / sqrtf(d); return fail_value; } 161 | static inline float ImFloor(float f) { return (float)(int)f; } 162 | static inline ImVec2 ImFloor(const ImVec2& v) { return ImVec2((float)(int)v.x, (float)(int)v.y); } 163 | static inline float ImDot(const ImVec2& a, const ImVec2& b) { return a.x * b.x + a.y * b.y; } 164 | static inline ImVec2 ImRotate(const ImVec2& v, float cos_a, float sin_a) { return ImVec2(v.x * cos_a - v.y * sin_a, v.x * sin_a + v.y * cos_a); } 165 | static inline float ImLinearSweep(float current, float target, float speed) { if (current < target) return ImMin(current + speed, target); if (current > target) return ImMax(current - speed, target); return current; } 166 | static inline ImVec2 ImMul(const ImVec2& lhs, const ImVec2& rhs) { return ImVec2(lhs.x * rhs.x, lhs.y * rhs.y); } 167 | 168 | // We call C++ constructor on own allocated memory via the placement "new(ptr) Type()" syntax. 169 | // Defining a custom placement new() with a dummy parameter allows us to bypass including which on some platforms complains when user has disabled exceptions. 170 | struct ImNewPlacementDummy {}; 171 | inline void* operator new(size_t, ImNewPlacementDummy, void* ptr) { return ptr; } 172 | inline void operator delete(void*, ImNewPlacementDummy, void*) {} // This is only required so we can use the symetrical new() 173 | #define IM_PLACEMENT_NEW(_PTR) new(ImNewPlacementDummy(), _PTR) 174 | #define IM_NEW(_TYPE) new(ImNewPlacementDummy(), ImGui::MemAlloc(sizeof(_TYPE))) _TYPE 175 | template void IM_DELETE(T*& p) { if (p) { p->~T(); ImGui::MemFree(p); p = NULL; } } 176 | 177 | //----------------------------------------------------------------------------- 178 | // Types 179 | //----------------------------------------------------------------------------- 180 | 181 | enum ImGuiButtonFlags_ 182 | { 183 | ImGuiButtonFlags_Repeat = 1 << 0, // hold to repeat 184 | ImGuiButtonFlags_PressedOnClickRelease = 1 << 1, // return true on click + release on same item [DEFAULT if no PressedOn* flag is set] 185 | ImGuiButtonFlags_PressedOnClick = 1 << 2, // return true on click (default requires click+release) 186 | ImGuiButtonFlags_PressedOnRelease = 1 << 3, // return true on release (default requires click+release) 187 | ImGuiButtonFlags_PressedOnDoubleClick = 1 << 4, // return true on double-click (default requires click+release) 188 | ImGuiButtonFlags_FlattenChildren = 1 << 5, // allow interactions even if a child window is overlapping 189 | ImGuiButtonFlags_AllowItemOverlap = 1 << 6, // require previous frame HoveredId to either match id or be null before being usable, use along with SetItemAllowOverlap() 190 | ImGuiButtonFlags_DontClosePopups = 1 << 7, // disable automatically closing parent popup on press // [UNUSED] 191 | ImGuiButtonFlags_Disabled = 1 << 8, // disable interactions 192 | ImGuiButtonFlags_AlignTextBaseLine = 1 << 9, // vertically align button to match text baseline - ButtonEx() only // FIXME: Should be removed and handled by SmallButton(), not possible currently because of DC.CursorPosPrevLine 193 | ImGuiButtonFlags_NoKeyModifiers = 1 << 10, // disable interaction if a key modifier is held 194 | ImGuiButtonFlags_NoHoldingActiveID = 1 << 11, // don't set ActiveId while holding the mouse (ImGuiButtonFlags_PressedOnClick only) 195 | ImGuiButtonFlags_PressedOnDragDropHold = 1 << 12, // press when held into while we are drag and dropping another item (used by e.g. tree nodes, collapsing headers) 196 | ImGuiButtonFlags_NoNavFocus = 1 << 13 // don't override navigation focus when activated 197 | }; 198 | 199 | enum ImGuiSliderFlags_ 200 | { 201 | ImGuiSliderFlags_Vertical = 1 << 0 202 | }; 203 | 204 | enum ImGuiColumnsFlags_ 205 | { 206 | // Default: 0 207 | ImGuiColumnsFlags_NoBorder = 1 << 0, // Disable column dividers 208 | ImGuiColumnsFlags_NoResize = 1 << 1, // Disable resizing columns when clicking on the dividers 209 | ImGuiColumnsFlags_NoPreserveWidths = 1 << 2, // Disable column width preservation when adjusting columns 210 | ImGuiColumnsFlags_NoForceWithinWindow = 1 << 3, // Disable forcing columns to fit within window 211 | ImGuiColumnsFlags_GrowParentContentsSize= 1 << 4 // (WIP) Restore pre-1.51 behavior of extending the parent window contents size but _without affecting the columns width at all_. Will eventually remove. 212 | }; 213 | 214 | enum ImGuiSelectableFlagsPrivate_ 215 | { 216 | // NB: need to be in sync with last value of ImGuiSelectableFlags_ 217 | ImGuiSelectableFlags_Menu = 1 << 3, // -> PressedOnClick 218 | ImGuiSelectableFlags_MenuItem = 1 << 4, // -> PressedOnRelease 219 | ImGuiSelectableFlags_Disabled = 1 << 5, 220 | ImGuiSelectableFlags_DrawFillAvailWidth = 1 << 6 221 | }; 222 | 223 | enum ImGuiSeparatorFlags_ 224 | { 225 | ImGuiSeparatorFlags_Horizontal = 1 << 0, // Axis default to current layout type, so generally Horizontal unless e.g. in a menu bar 226 | ImGuiSeparatorFlags_Vertical = 1 << 1 227 | }; 228 | 229 | // Storage for LastItem data 230 | enum ImGuiItemStatusFlags_ 231 | { 232 | ImGuiItemStatusFlags_HoveredRect = 1 << 0, 233 | ImGuiItemStatusFlags_HasDisplayRect = 1 << 1 234 | }; 235 | 236 | // FIXME: this is in development, not exposed/functional as a generic feature yet. 237 | enum ImGuiLayoutType_ 238 | { 239 | ImGuiLayoutType_Vertical, 240 | ImGuiLayoutType_Horizontal 241 | }; 242 | 243 | enum ImGuiAxis 244 | { 245 | ImGuiAxis_None = -1, 246 | ImGuiAxis_X = 0, 247 | ImGuiAxis_Y = 1 248 | }; 249 | 250 | enum ImGuiPlotType 251 | { 252 | ImGuiPlotType_Lines, 253 | ImGuiPlotType_Histogram 254 | }; 255 | 256 | enum ImGuiDataType 257 | { 258 | ImGuiDataType_Int, 259 | ImGuiDataType_Float, 260 | ImGuiDataType_Float2 261 | }; 262 | 263 | enum ImGuiInputSource 264 | { 265 | ImGuiInputSource_None = 0, 266 | ImGuiInputSource_Mouse, 267 | ImGuiInputSource_Nav, 268 | ImGuiInputSource_NavKeyboard, // Only used occasionally for storage, not tested/handled by most code 269 | ImGuiInputSource_NavGamepad, // " 270 | ImGuiInputSource_COUNT, 271 | }; 272 | 273 | // FIXME-NAV: Clarify/expose various repeat delay/rate 274 | enum ImGuiInputReadMode 275 | { 276 | ImGuiInputReadMode_Down, 277 | ImGuiInputReadMode_Pressed, 278 | ImGuiInputReadMode_Released, 279 | ImGuiInputReadMode_Repeat, 280 | ImGuiInputReadMode_RepeatSlow, 281 | ImGuiInputReadMode_RepeatFast 282 | }; 283 | 284 | enum ImGuiNavHighlightFlags_ 285 | { 286 | ImGuiNavHighlightFlags_TypeDefault = 1 << 0, 287 | ImGuiNavHighlightFlags_TypeThin = 1 << 1, 288 | ImGuiNavHighlightFlags_AlwaysDraw = 1 << 2, 289 | ImGuiNavHighlightFlags_NoRounding = 1 << 3 290 | }; 291 | 292 | enum ImGuiNavDirSourceFlags_ 293 | { 294 | ImGuiNavDirSourceFlags_Keyboard = 1 << 0, 295 | ImGuiNavDirSourceFlags_PadDPad = 1 << 1, 296 | ImGuiNavDirSourceFlags_PadLStick = 1 << 2 297 | }; 298 | 299 | enum ImGuiNavForward 300 | { 301 | ImGuiNavForward_None, 302 | ImGuiNavForward_ForwardQueued, 303 | ImGuiNavForward_ForwardActive 304 | }; 305 | 306 | // 2D axis aligned bounding-box 307 | // NB: we can't rely on ImVec2 math operators being available here 308 | struct IMGUI_API ImRect 309 | { 310 | ImVec2 Min; // Upper-left 311 | ImVec2 Max; // Lower-right 312 | 313 | ImRect() : Min(FLT_MAX,FLT_MAX), Max(-FLT_MAX,-FLT_MAX) {} 314 | ImRect(const ImVec2& min, const ImVec2& max) : Min(min), Max(max) {} 315 | ImRect(const ImVec4& v) : Min(v.x, v.y), Max(v.z, v.w) {} 316 | ImRect(float x1, float y1, float x2, float y2) : Min(x1, y1), Max(x2, y2) {} 317 | 318 | ImVec2 GetCenter() const { return ImVec2((Min.x + Max.x) * 0.5f, (Min.y + Max.y) * 0.5f); } 319 | ImVec2 GetSize() const { return ImVec2(Max.x - Min.x, Max.y - Min.y); } 320 | float GetWidth() const { return Max.x - Min.x; } 321 | float GetHeight() const { return Max.y - Min.y; } 322 | ImVec2 GetTL() const { return Min; } // Top-left 323 | ImVec2 GetTR() const { return ImVec2(Max.x, Min.y); } // Top-right 324 | ImVec2 GetBL() const { return ImVec2(Min.x, Max.y); } // Bottom-left 325 | ImVec2 GetBR() const { return Max; } // Bottom-right 326 | bool Contains(const ImVec2& p) const { return p.x >= Min.x && p.y >= Min.y && p.x < Max.x && p.y < Max.y; } 327 | bool Contains(const ImRect& r) const { return r.Min.x >= Min.x && r.Min.y >= Min.y && r.Max.x <= Max.x && r.Max.y <= Max.y; } 328 | bool Overlaps(const ImRect& r) const { return r.Min.y < Max.y && r.Max.y > Min.y && r.Min.x < Max.x && r.Max.x > Min.x; } 329 | void Add(const ImVec2& p) { if (Min.x > p.x) Min.x = p.x; if (Min.y > p.y) Min.y = p.y; if (Max.x < p.x) Max.x = p.x; if (Max.y < p.y) Max.y = p.y; } 330 | void Add(const ImRect& r) { if (Min.x > r.Min.x) Min.x = r.Min.x; if (Min.y > r.Min.y) Min.y = r.Min.y; if (Max.x < r.Max.x) Max.x = r.Max.x; if (Max.y < r.Max.y) Max.y = r.Max.y; } 331 | void Expand(const float amount) { Min.x -= amount; Min.y -= amount; Max.x += amount; Max.y += amount; } 332 | void Expand(const ImVec2& amount) { Min.x -= amount.x; Min.y -= amount.y; Max.x += amount.x; Max.y += amount.y; } 333 | void Translate(const ImVec2& v) { Min.x += v.x; Min.y += v.y; Max.x += v.x; Max.y += v.y; } 334 | void ClipWith(const ImRect& r) { Min = ImMax(Min, r.Min); Max = ImMin(Max, r.Max); } // Simple version, may lead to an inverted rectangle, which is fine for Contains/Overlaps test but not for display. 335 | void ClipWithFull(const ImRect& r) { Min = ImClamp(Min, r.Min, r.Max); Max = ImClamp(Max, r.Min, r.Max); } // Full version, ensure both points are fully clipped. 336 | void Floor() { Min.x = (float)(int)Min.x; Min.y = (float)(int)Min.y; Max.x = (float)(int)Max.x; Max.y = (float)(int)Max.y; } 337 | void FixInverted() { if (Min.x > Max.x) ImSwap(Min.x, Max.x); if (Min.y > Max.y) ImSwap(Min.y, Max.y); } 338 | bool IsInverted() const { return Min.x > Max.x || Min.y > Max.y; } 339 | }; 340 | 341 | // Stacked color modifier, backup of modified data so we can restore it 342 | struct ImGuiColMod 343 | { 344 | ImGuiCol Col; 345 | ImVec4 BackupValue; 346 | }; 347 | 348 | // Stacked style modifier, backup of modified data so we can restore it. Data type inferred from the variable. 349 | struct ImGuiStyleMod 350 | { 351 | ImGuiStyleVar VarIdx; 352 | union { int BackupInt[2]; float BackupFloat[2]; }; 353 | ImGuiStyleMod(ImGuiStyleVar idx, int v) { VarIdx = idx; BackupInt[0] = v; } 354 | ImGuiStyleMod(ImGuiStyleVar idx, float v) { VarIdx = idx; BackupFloat[0] = v; } 355 | ImGuiStyleMod(ImGuiStyleVar idx, ImVec2 v) { VarIdx = idx; BackupFloat[0] = v.x; BackupFloat[1] = v.y; } 356 | }; 357 | 358 | // Stacked data for BeginGroup()/EndGroup() 359 | struct ImGuiGroupData 360 | { 361 | ImVec2 BackupCursorPos; 362 | ImVec2 BackupCursorMaxPos; 363 | float BackupIndentX; 364 | float BackupGroupOffsetX; 365 | float BackupCurrentLineHeight; 366 | float BackupCurrentLineTextBaseOffset; 367 | float BackupLogLinePosY; 368 | bool BackupActiveIdIsAlive; 369 | bool AdvanceCursor; 370 | }; 371 | 372 | // Simple column measurement currently used for MenuItem() only. This is very short-sighted/throw-away code and NOT a generic helper. 373 | struct IMGUI_API ImGuiMenuColumns 374 | { 375 | int Count; 376 | float Spacing; 377 | float Width, NextWidth; 378 | float Pos[4], NextWidths[4]; 379 | 380 | ImGuiMenuColumns(); 381 | void Update(int count, float spacing, bool clear); 382 | float DeclColumns(float w0, float w1, float w2); 383 | float CalcExtraSpace(float avail_w); 384 | }; 385 | 386 | // Internal state of the currently focused/edited text input box 387 | struct IMGUI_API ImGuiTextEditState 388 | { 389 | ImGuiID Id; // widget id owning the text state 390 | ImVector Text; // edit buffer, we need to persist but can't guarantee the persistence of the user-provided buffer. so we copy into own buffer. 391 | ImVector InitialText; // backup of end-user buffer at the time of focus (in UTF-8, unaltered) 392 | ImVector TempTextBuffer; 393 | int CurLenA, CurLenW; // we need to maintain our buffer length in both UTF-8 and wchar format. 394 | int BufSizeA; // end-user buffer size 395 | float ScrollX; 396 | ImGuiStb::STB_TexteditState StbState; 397 | float CursorAnim; 398 | bool CursorFollow; 399 | bool SelectedAllMouseLock; 400 | 401 | ImGuiTextEditState() { memset(this, 0, sizeof(*this)); } 402 | void CursorAnimReset() { CursorAnim = -0.30f; } // After a user-input the cursor stays on for a while without blinking 403 | void CursorClamp() { StbState.cursor = ImMin(StbState.cursor, CurLenW); StbState.select_start = ImMin(StbState.select_start, CurLenW); StbState.select_end = ImMin(StbState.select_end, CurLenW); } 404 | bool HasSelection() const { return StbState.select_start != StbState.select_end; } 405 | void ClearSelection() { StbState.select_start = StbState.select_end = StbState.cursor; } 406 | void SelectAll() { StbState.select_start = 0; StbState.cursor = StbState.select_end = CurLenW; StbState.has_preferred_x = false; } 407 | void OnKeyPressed(int key); 408 | }; 409 | 410 | // Data saved in imgui.ini file 411 | struct ImGuiWindowSettings 412 | { 413 | char* Name; 414 | ImGuiID Id; 415 | ImVec2 Pos; 416 | ImVec2 Size; 417 | bool Collapsed; 418 | 419 | ImGuiWindowSettings() { Name = NULL; Id = 0; Pos = Size = ImVec2(0,0); Collapsed = false; } 420 | }; 421 | 422 | struct ImGuiSettingsHandler 423 | { 424 | const char* TypeName; // Short description stored in .ini file. Disallowed characters: '[' ']' 425 | ImGuiID TypeHash; // == ImHash(TypeName, 0, 0) 426 | void* (*ReadOpenFn)(ImGuiContext* ctx, ImGuiSettingsHandler* handler, const char* name); 427 | void (*ReadLineFn)(ImGuiContext* ctx, ImGuiSettingsHandler* handler, void* entry, const char* line); 428 | void (*WriteAllFn)(ImGuiContext* ctx, ImGuiSettingsHandler* handler, ImGuiTextBuffer* out_buf); 429 | void* UserData; 430 | 431 | ImGuiSettingsHandler() { memset(this, 0, sizeof(*this)); } 432 | }; 433 | 434 | // Storage for current popup stack 435 | struct ImGuiPopupRef 436 | { 437 | ImGuiID PopupId; // Set on OpenPopup() 438 | ImGuiWindow* Window; // Resolved on BeginPopup() - may stay unresolved if user never calls OpenPopup() 439 | ImGuiWindow* ParentWindow; // Set on OpenPopup() 440 | int OpenFrameCount; // Set on OpenPopup() 441 | ImGuiID OpenParentId; // Set on OpenPopup(), we need this to differenciate multiple menu sets from each others (e.g. inside menu bar vs loose menu items) 442 | ImVec2 OpenPopupPos; // Set on OpenPopup(), preferred popup position (typically == OpenMousePos when using mouse) 443 | ImVec2 OpenMousePos; // Set on OpenPopup(), copy of mouse position at the time of opening popup 444 | }; 445 | 446 | struct ImGuiColumnData 447 | { 448 | float OffsetNorm; // Column start offset, normalized 0.0 (far left) -> 1.0 (far right) 449 | float OffsetNormBeforeResize; 450 | ImGuiColumnsFlags Flags; // Not exposed 451 | ImRect ClipRect; 452 | 453 | ImGuiColumnData() { OffsetNorm = OffsetNormBeforeResize = 0.0f; Flags = 0; } 454 | }; 455 | 456 | struct ImGuiColumnsSet 457 | { 458 | ImGuiID ID; 459 | ImGuiColumnsFlags Flags; 460 | bool IsFirstFrame; 461 | bool IsBeingResized; 462 | int Current; 463 | int Count; 464 | float MinX, MaxX; 465 | float StartPosY; 466 | float StartMaxPosX; // Backup of CursorMaxPos 467 | float CellMinY, CellMaxY; 468 | ImVector Columns; 469 | 470 | ImGuiColumnsSet() { Clear(); } 471 | void Clear() 472 | { 473 | ID = 0; 474 | Flags = 0; 475 | IsFirstFrame = false; 476 | IsBeingResized = false; 477 | Current = 0; 478 | Count = 1; 479 | MinX = MaxX = 0.0f; 480 | StartPosY = 0.0f; 481 | StartMaxPosX = 0.0f; 482 | CellMinY = CellMaxY = 0.0f; 483 | Columns.clear(); 484 | } 485 | }; 486 | 487 | struct IMGUI_API ImDrawListSharedData 488 | { 489 | ImVec2 TexUvWhitePixel; // UV of white pixel in the atlas 490 | ImFont* Font; // Current/default font (optional, for simplified AddText overload) 491 | float FontSize; // Current/default font size (optional, for simplified AddText overload) 492 | float CurveTessellationTol; 493 | ImVec4 ClipRectFullscreen; // Value for PushClipRectFullscreen() 494 | 495 | // Const data 496 | // FIXME: Bake rounded corners fill/borders in atlas 497 | ImVec2 CircleVtx12[12]; 498 | 499 | ImDrawListSharedData(); 500 | }; 501 | 502 | struct ImDrawDataBuilder 503 | { 504 | ImVector Layers[2]; // Global layers for: regular, tooltip 505 | 506 | void Clear() { for (int n = 0; n < IM_ARRAYSIZE(Layers); n++) Layers[n].resize(0); } 507 | void ClearFreeMemory() { for (int n = 0; n < IM_ARRAYSIZE(Layers); n++) Layers[n].clear(); } 508 | IMGUI_API void FlattenIntoSingleLayer(); 509 | }; 510 | 511 | struct ImGuiNavMoveResult 512 | { 513 | ImGuiID ID; // Best candidate 514 | ImGuiID ParentID; // Best candidate window->IDStack.back() - to compare context 515 | ImGuiWindow* Window; // Best candidate window 516 | float DistBox; // Best candidate box distance to current NavId 517 | float DistCenter; // Best candidate center distance to current NavId 518 | float DistAxial; 519 | ImRect RectRel; // Best candidate bounding box in window relative space 520 | 521 | ImGuiNavMoveResult() { Clear(); } 522 | void Clear() { ID = ParentID = 0; Window = NULL; DistBox = DistCenter = DistAxial = FLT_MAX; RectRel = ImRect(); } 523 | }; 524 | 525 | // Storage for SetNexWindow** functions 526 | struct ImGuiNextWindowData 527 | { 528 | ImGuiCond PosCond; 529 | ImGuiCond SizeCond; 530 | ImGuiCond ContentSizeCond; 531 | ImGuiCond CollapsedCond; 532 | ImGuiCond SizeConstraintCond; 533 | ImGuiCond FocusCond; 534 | ImGuiCond BgAlphaCond; 535 | ImVec2 PosVal; 536 | ImVec2 PosPivotVal; 537 | ImVec2 SizeVal; 538 | ImVec2 ContentSizeVal; 539 | bool CollapsedVal; 540 | ImRect SizeConstraintRect; // Valid if 'SetNextWindowSizeConstraint' is true 541 | ImGuiSizeCallback SizeCallback; 542 | void* SizeCallbackUserData; 543 | float BgAlphaVal; 544 | 545 | ImGuiNextWindowData() 546 | { 547 | PosCond = SizeCond = ContentSizeCond = CollapsedCond = SizeConstraintCond = FocusCond = BgAlphaCond = 0; 548 | PosVal = PosPivotVal = SizeVal = ImVec2(0.0f, 0.0f); 549 | ContentSizeVal = ImVec2(0.0f, 0.0f); 550 | CollapsedVal = false; 551 | SizeConstraintRect = ImRect(); 552 | SizeCallback = NULL; 553 | SizeCallbackUserData = NULL; 554 | BgAlphaVal = FLT_MAX; 555 | } 556 | 557 | void Clear() 558 | { 559 | PosCond = SizeCond = ContentSizeCond = CollapsedCond = SizeConstraintCond = FocusCond = BgAlphaCond = 0; 560 | } 561 | }; 562 | 563 | // Main state for ImGui 564 | struct ImGuiContext 565 | { 566 | bool Initialized; 567 | bool FontAtlasOwnedByContext; // Io.Fonts-> is owned by the ImGuiContext and will be destructed along with it. 568 | ImGuiIO IO; 569 | ImGuiStyle Style; 570 | ImFont* Font; // (Shortcut) == FontStack.empty() ? IO.Font : FontStack.back() 571 | float FontSize; // (Shortcut) == FontBaseSize * g.CurrentWindow->FontWindowScale == window->FontSize(). Text height for current window. 572 | float FontBaseSize; // (Shortcut) == IO.FontGlobalScale * Font->Scale * Font->FontSize. Base text height. 573 | ImDrawListSharedData DrawListSharedData; 574 | 575 | float Time; 576 | int FrameCount; 577 | int FrameCountEnded; 578 | int FrameCountRendered; 579 | ImVector Windows; 580 | ImVector WindowsSortBuffer; 581 | ImVector CurrentWindowStack; 582 | ImGuiStorage WindowsById; 583 | int WindowsActiveCount; 584 | ImGuiWindow* CurrentWindow; // Being drawn into 585 | ImGuiWindow* HoveredWindow; // Will catch mouse inputs 586 | ImGuiWindow* HoveredRootWindow; // Will catch mouse inputs (for focus/move only) 587 | ImGuiID HoveredId; // Hovered widget 588 | bool HoveredIdAllowOverlap; 589 | ImGuiID HoveredIdPreviousFrame; 590 | float HoveredIdTimer; 591 | ImGuiID ActiveId; // Active widget 592 | ImGuiID ActiveIdPreviousFrame; 593 | float ActiveIdTimer; 594 | bool ActiveIdIsAlive; // Active widget has been seen this frame 595 | bool ActiveIdIsJustActivated; // Set at the time of activation for one frame 596 | bool ActiveIdAllowOverlap; // Active widget allows another widget to steal active id (generally for overlapping widgets, but not always) 597 | int ActiveIdAllowNavDirFlags; // Active widget allows using directional navigation (e.g. can activate a button and move away from it) 598 | ImVec2 ActiveIdClickOffset; // Clicked offset from upper-left corner, if applicable (currently only set by ButtonBehavior) 599 | ImGuiWindow* ActiveIdWindow; 600 | ImGuiInputSource ActiveIdSource; // Activating with mouse or nav (gamepad/keyboard) 601 | ImGuiWindow* MovingWindow; // Track the window we clicked on (in order to preserve focus). The actually window that is moved is generally MovingWindow->RootWindow. 602 | ImVector ColorModifiers; // Stack for PushStyleColor()/PopStyleColor() 603 | ImVector StyleModifiers; // Stack for PushStyleVar()/PopStyleVar() 604 | ImVector FontStack; // Stack for PushFont()/PopFont() 605 | ImVector OpenPopupStack; // Which popups are open (persistent) 606 | ImVector CurrentPopupStack; // Which level of BeginPopup() we are in (reset every frame) 607 | ImGuiNextWindowData NextWindowData; // Storage for SetNextWindow** functions 608 | bool NextTreeNodeOpenVal; // Storage for SetNextTreeNode** functions 609 | ImGuiCond NextTreeNodeOpenCond; 610 | 611 | // Navigation data (for gamepad/keyboard) 612 | ImGuiWindow* NavWindow; // Focused window for navigation. Could be called 'FocusWindow' 613 | ImGuiID NavId; // Focused item for navigation 614 | ImGuiID NavActivateId; // ~~ (g.ActiveId == 0) && IsNavInputPressed(ImGuiNavInput_Activate) ? NavId : 0, also set when calling ActivateItem() 615 | ImGuiID NavActivateDownId; // ~~ IsNavInputDown(ImGuiNavInput_Activate) ? NavId : 0 616 | ImGuiID NavActivatePressedId; // ~~ IsNavInputPressed(ImGuiNavInput_Activate) ? NavId : 0 617 | ImGuiID NavInputId; // ~~ IsNavInputPressed(ImGuiNavInput_Input) ? NavId : 0 618 | ImGuiID NavJustTabbedId; // Just tabbed to this id. 619 | ImGuiID NavNextActivateId; // Set by ActivateItem(), queued until next frame 620 | ImGuiID NavJustMovedToId; // Just navigated to this id (result of a successfully MoveRequest) 621 | ImRect NavScoringRectScreen; // Rectangle used for scoring, in screen space. Based of window->DC.NavRefRectRel[], modified for directional navigation scoring. 622 | int NavScoringCount; // Metrics for debugging 623 | ImGuiWindow* NavWindowingTarget; // When selecting a window (holding Menu+FocusPrev/Next, or equivalent of CTRL-TAB) this window is temporarily displayed front-most. 624 | float NavWindowingHighlightTimer; 625 | float NavWindowingHighlightAlpha; 626 | bool NavWindowingToggleLayer; 627 | ImGuiInputSource NavWindowingInputSource; // Gamepad or keyboard mode 628 | int NavLayer; // Layer we are navigating on. For now the system is hard-coded for 0=main contents and 1=menu/title bar, may expose layers later. 629 | int NavIdTabCounter; // == NavWindow->DC.FocusIdxTabCounter at time of NavId processing 630 | bool NavIdIsAlive; // Nav widget has been seen this frame ~~ NavRefRectRel is valid 631 | bool NavMousePosDirty; // When set we will update mouse position if (io.ConfigFlags & ImGuiConfigFlags_NavMoveMouse) if set (NB: this not enabled by default) 632 | bool NavDisableHighlight; // When user starts using mouse, we hide gamepad/keyboard highlight (NB: but they are still available, which is why NavDisableHighlight isn't always != NavDisableMouseHover) 633 | bool NavDisableMouseHover; // When user starts using gamepad/keyboard, we hide mouse hovering highlight until mouse is touched again. 634 | bool NavAnyRequest; // ~~ NavMoveRequest || NavInitRequest 635 | bool NavInitRequest; // Init request for appearing window to select first item 636 | bool NavInitRequestFromMove; 637 | ImGuiID NavInitResultId; 638 | ImRect NavInitResultRectRel; 639 | bool NavMoveFromClampedRefRect; // Set by manual scrolling, if we scroll to a point where NavId isn't visible we reset navigation from visible items 640 | bool NavMoveRequest; // Move request for this frame 641 | ImGuiNavForward NavMoveRequestForward; // None / ForwardQueued / ForwardActive (this is used to navigate sibling parent menus from a child menu) 642 | ImGuiDir NavMoveDir, NavMoveDirLast; // Direction of the move request (left/right/up/down), direction of the previous move request 643 | ImGuiNavMoveResult NavMoveResultLocal; // Best move request candidate within NavWindow 644 | ImGuiNavMoveResult NavMoveResultOther; // Best move request candidate within NavWindow's flattened hierarchy (when using the NavFlattened flag) 645 | 646 | // Render 647 | ImDrawData DrawData; // Main ImDrawData instance to pass render information to the user 648 | ImDrawDataBuilder DrawDataBuilder; 649 | float ModalWindowDarkeningRatio; 650 | ImDrawList OverlayDrawList; // Optional software render of mouse cursors, if io.MouseDrawCursor is set + a few debug overlays 651 | ImGuiMouseCursor MouseCursor; 652 | 653 | // Drag and Drop 654 | bool DragDropActive; 655 | ImGuiDragDropFlags DragDropSourceFlags; 656 | int DragDropMouseButton; 657 | ImGuiPayload DragDropPayload; 658 | ImRect DragDropTargetRect; 659 | ImGuiID DragDropTargetId; 660 | float DragDropAcceptIdCurrRectSurface; 661 | ImGuiID DragDropAcceptIdCurr; // Target item id (set at the time of accepting the payload) 662 | ImGuiID DragDropAcceptIdPrev; // Target item id from previous frame (we need to store this to allow for overlapping drag and drop targets) 663 | int DragDropAcceptFrameCount; // Last time a target expressed a desire to accept the source 664 | ImVector DragDropPayloadBufHeap; // We don't expose the ImVector<> directly 665 | unsigned char DragDropPayloadBufLocal[8]; // Local buffer for small payloads 666 | 667 | // Widget state 668 | ImGuiTextEditState InputTextState; 669 | ImFont InputTextPasswordFont; 670 | ImGuiID ScalarAsInputTextId; // Temporary text input when CTRL+clicking on a slider, etc. 671 | ImGuiColorEditFlags ColorEditOptions; // Store user options for color edit widgets 672 | ImVec4 ColorPickerRef; 673 | float DragCurrentValue; // Currently dragged value, always float, not rounded by end-user precision settings 674 | ImVec2 DragLastMouseDelta; 675 | float DragSpeedDefaultRatio; // If speed == 0.0f, uses (max-min) * DragSpeedDefaultRatio 676 | float DragSpeedScaleSlow; 677 | float DragSpeedScaleFast; 678 | ImVec2 ScrollbarClickDeltaToGrabCenter; // Distance between mouse and center of grab box, normalized in parent space. Use storage? 679 | int TooltipOverrideCount; 680 | ImVector PrivateClipboard; // If no custom clipboard handler is defined 681 | ImVec2 OsImePosRequest, OsImePosSet; // Cursor position request & last passed to the OS Input Method Editor 682 | 683 | // Settings 684 | bool SettingsLoaded; 685 | float SettingsDirtyTimer; // Save .ini Settings on disk when time reaches zero 686 | ImVector SettingsWindows; // .ini settings for ImGuiWindow 687 | ImVector SettingsHandlers; // List of .ini settings handlers 688 | 689 | // Logging 690 | bool LogEnabled; 691 | FILE* LogFile; // If != NULL log to stdout/ file 692 | ImGuiTextBuffer* LogClipboard; // Else log to clipboard. This is pointer so our GImGui static constructor doesn't call heap allocators. 693 | int LogStartDepth; 694 | int LogAutoExpandMaxDepth; 695 | 696 | // Misc 697 | float FramerateSecPerFrame[120]; // calculate estimate of framerate for user 698 | int FramerateSecPerFrameIdx; 699 | float FramerateSecPerFrameAccum; 700 | int WantCaptureMouseNextFrame; // explicit capture via CaptureInputs() sets those flags 701 | int WantCaptureKeyboardNextFrame; 702 | int WantTextInputNextFrame; 703 | char TempBuffer[1024*3+1]; // temporary text buffer 704 | 705 | ImGuiContext(ImFontAtlas* shared_font_atlas) : OverlayDrawList(NULL) 706 | { 707 | Initialized = false; 708 | Font = NULL; 709 | FontSize = FontBaseSize = 0.0f; 710 | FontAtlasOwnedByContext = shared_font_atlas ? false : true; 711 | IO.Fonts = shared_font_atlas ? shared_font_atlas : IM_NEW(ImFontAtlas)(); 712 | 713 | Time = 0.0f; 714 | FrameCount = 0; 715 | FrameCountEnded = FrameCountRendered = -1; 716 | WindowsActiveCount = 0; 717 | CurrentWindow = NULL; 718 | HoveredWindow = NULL; 719 | HoveredRootWindow = NULL; 720 | HoveredId = 0; 721 | HoveredIdAllowOverlap = false; 722 | HoveredIdPreviousFrame = 0; 723 | HoveredIdTimer = 0.0f; 724 | ActiveId = 0; 725 | ActiveIdPreviousFrame = 0; 726 | ActiveIdTimer = 0.0f; 727 | ActiveIdIsAlive = false; 728 | ActiveIdIsJustActivated = false; 729 | ActiveIdAllowOverlap = false; 730 | ActiveIdAllowNavDirFlags = 0; 731 | ActiveIdClickOffset = ImVec2(-1,-1); 732 | ActiveIdWindow = NULL; 733 | ActiveIdSource = ImGuiInputSource_None; 734 | MovingWindow = NULL; 735 | NextTreeNodeOpenVal = false; 736 | NextTreeNodeOpenCond = 0; 737 | 738 | NavWindow = NULL; 739 | NavId = NavActivateId = NavActivateDownId = NavActivatePressedId = NavInputId = 0; 740 | NavJustTabbedId = NavJustMovedToId = NavNextActivateId = 0; 741 | NavScoringRectScreen = ImRect(); 742 | NavScoringCount = 0; 743 | NavWindowingTarget = NULL; 744 | NavWindowingHighlightTimer = NavWindowingHighlightAlpha = 0.0f; 745 | NavWindowingToggleLayer = false; 746 | NavWindowingInputSource = ImGuiInputSource_None; 747 | NavLayer = 0; 748 | NavIdTabCounter = INT_MAX; 749 | NavIdIsAlive = false; 750 | NavMousePosDirty = false; 751 | NavDisableHighlight = true; 752 | NavDisableMouseHover = false; 753 | NavAnyRequest = false; 754 | NavInitRequest = false; 755 | NavInitRequestFromMove = false; 756 | NavInitResultId = 0; 757 | NavMoveFromClampedRefRect = false; 758 | NavMoveRequest = false; 759 | NavMoveRequestForward = ImGuiNavForward_None; 760 | NavMoveDir = NavMoveDirLast = ImGuiDir_None; 761 | 762 | ModalWindowDarkeningRatio = 0.0f; 763 | OverlayDrawList._Data = &DrawListSharedData; 764 | OverlayDrawList._OwnerName = "##Overlay"; // Give it a name for debugging 765 | MouseCursor = ImGuiMouseCursor_Arrow; 766 | 767 | DragDropActive = false; 768 | DragDropSourceFlags = 0; 769 | DragDropMouseButton = -1; 770 | DragDropTargetId = 0; 771 | DragDropAcceptIdCurrRectSurface = 0.0f; 772 | DragDropAcceptIdPrev = DragDropAcceptIdCurr = 0; 773 | DragDropAcceptFrameCount = -1; 774 | memset(DragDropPayloadBufLocal, 0, sizeof(DragDropPayloadBufLocal)); 775 | 776 | ScalarAsInputTextId = 0; 777 | ColorEditOptions = ImGuiColorEditFlags__OptionsDefault; 778 | DragCurrentValue = 0.0f; 779 | DragLastMouseDelta = ImVec2(0.0f, 0.0f); 780 | DragSpeedDefaultRatio = 1.0f / 100.0f; 781 | DragSpeedScaleSlow = 1.0f / 100.0f; 782 | DragSpeedScaleFast = 10.0f; 783 | ScrollbarClickDeltaToGrabCenter = ImVec2(0.0f, 0.0f); 784 | TooltipOverrideCount = 0; 785 | OsImePosRequest = OsImePosSet = ImVec2(-1.0f, -1.0f); 786 | 787 | SettingsLoaded = false; 788 | SettingsDirtyTimer = 0.0f; 789 | 790 | LogEnabled = false; 791 | LogFile = NULL; 792 | LogClipboard = NULL; 793 | LogStartDepth = 0; 794 | LogAutoExpandMaxDepth = 2; 795 | 796 | memset(FramerateSecPerFrame, 0, sizeof(FramerateSecPerFrame)); 797 | FramerateSecPerFrameIdx = 0; 798 | FramerateSecPerFrameAccum = 0.0f; 799 | WantCaptureMouseNextFrame = WantCaptureKeyboardNextFrame = WantTextInputNextFrame = -1; 800 | memset(TempBuffer, 0, sizeof(TempBuffer)); 801 | } 802 | }; 803 | 804 | // Transient per-window flags, reset at the beginning of the frame. For child window, inherited from parent on first Begin(). 805 | // This is going to be exposed in imgui.h when stabilized enough. 806 | enum ImGuiItemFlags_ 807 | { 808 | ImGuiItemFlags_AllowKeyboardFocus = 1 << 0, // true 809 | ImGuiItemFlags_ButtonRepeat = 1 << 1, // false // Button() will return true multiple times based on io.KeyRepeatDelay and io.KeyRepeatRate settings. 810 | ImGuiItemFlags_Disabled = 1 << 2, // false // FIXME-WIP: Disable interactions but doesn't affect visuals. Should be: grey out and disable interactions with widgets that affect data + view widgets (WIP) 811 | ImGuiItemFlags_NoNav = 1 << 3, // false 812 | ImGuiItemFlags_NoNavDefaultFocus = 1 << 4, // false 813 | ImGuiItemFlags_SelectableDontClosePopup = 1 << 5, // false // MenuItem/Selectable() automatically closes current Popup window 814 | ImGuiItemFlags_Default_ = ImGuiItemFlags_AllowKeyboardFocus 815 | }; 816 | 817 | // Transient per-window data, reset at the beginning of the frame 818 | // FIXME: That's theory, in practice the delimitation between ImGuiWindow and ImGuiDrawContext is quite tenuous and could be reconsidered. 819 | struct IMGUI_API ImGuiDrawContext 820 | { 821 | ImVec2 CursorPos; 822 | ImVec2 CursorPosPrevLine; 823 | ImVec2 CursorStartPos; 824 | ImVec2 CursorMaxPos; // Used to implicitly calculate the size of our contents, always growing during the frame. Turned into window->SizeContents at the beginning of next frame 825 | float CurrentLineHeight; 826 | float CurrentLineTextBaseOffset; 827 | float PrevLineHeight; 828 | float PrevLineTextBaseOffset; 829 | float LogLinePosY; 830 | int TreeDepth; 831 | ImU32 TreeDepthMayJumpToParentOnPop; // Store a copy of !g.NavIdIsAlive for TreeDepth 0..31 832 | ImGuiID LastItemId; 833 | ImGuiItemStatusFlags LastItemStatusFlags; 834 | ImRect LastItemRect; // Interaction rect 835 | ImRect LastItemDisplayRect; // End-user display rect (only valid if LastItemStatusFlags & ImGuiItemStatusFlags_HasDisplayRect) 836 | bool NavHideHighlightOneFrame; 837 | bool NavHasScroll; // Set when scrolling can be used (ScrollMax > 0.0f) 838 | int NavLayerCurrent; // Current layer, 0..31 (we currently only use 0..1) 839 | int NavLayerCurrentMask; // = (1 << NavLayerCurrent) used by ItemAdd prior to clipping. 840 | int NavLayerActiveMask; // Which layer have been written to (result from previous frame) 841 | int NavLayerActiveMaskNext; // Which layer have been written to (buffer for current frame) 842 | bool MenuBarAppending; // FIXME: Remove this 843 | float MenuBarOffsetX; 844 | ImVector ChildWindows; 845 | ImGuiStorage* StateStorage; 846 | ImGuiLayoutType LayoutType; 847 | ImGuiLayoutType ParentLayoutType; // Layout type of parent window at the time of Begin() 848 | 849 | // We store the current settings outside of the vectors to increase memory locality (reduce cache misses). The vectors are rarely modified. Also it allows us to not heap allocate for short-lived windows which are not using those settings. 850 | ImGuiItemFlags ItemFlags; // == ItemFlagsStack.back() [empty == ImGuiItemFlags_Default] 851 | float ItemWidth; // == ItemWidthStack.back(). 0.0: default, >0.0: width in pixels, <0.0: align xx pixels to the right of window 852 | float TextWrapPos; // == TextWrapPosStack.back() [empty == -1.0f] 853 | ImVectorItemFlagsStack; 854 | ImVector ItemWidthStack; 855 | ImVector TextWrapPosStack; 856 | ImVectorGroupStack; 857 | int StackSizesBackup[6]; // Store size of various stacks for asserting 858 | 859 | float IndentX; // Indentation / start position from left of window (increased by TreePush/TreePop, etc.) 860 | float GroupOffsetX; 861 | float ColumnsOffsetX; // Offset to the current column (if ColumnsCurrent > 0). FIXME: This and the above should be a stack to allow use cases like Tree->Column->Tree. Need revamp columns API. 862 | ImGuiColumnsSet* ColumnsSet; // Current columns set 863 | 864 | ImGuiDrawContext() 865 | { 866 | CursorPos = CursorPosPrevLine = CursorStartPos = CursorMaxPos = ImVec2(0.0f, 0.0f); 867 | CurrentLineHeight = PrevLineHeight = 0.0f; 868 | CurrentLineTextBaseOffset = PrevLineTextBaseOffset = 0.0f; 869 | LogLinePosY = -1.0f; 870 | TreeDepth = 0; 871 | TreeDepthMayJumpToParentOnPop = 0x00; 872 | LastItemId = 0; 873 | LastItemStatusFlags = 0; 874 | LastItemRect = LastItemDisplayRect = ImRect(); 875 | NavHideHighlightOneFrame = false; 876 | NavHasScroll = false; 877 | NavLayerActiveMask = NavLayerActiveMaskNext = 0x00; 878 | NavLayerCurrent = 0; 879 | NavLayerCurrentMask = 1 << 0; 880 | MenuBarAppending = false; 881 | MenuBarOffsetX = 0.0f; 882 | StateStorage = NULL; 883 | LayoutType = ParentLayoutType = ImGuiLayoutType_Vertical; 884 | ItemWidth = 0.0f; 885 | ItemFlags = ImGuiItemFlags_Default_; 886 | TextWrapPos = -1.0f; 887 | memset(StackSizesBackup, 0, sizeof(StackSizesBackup)); 888 | 889 | IndentX = 0.0f; 890 | GroupOffsetX = 0.0f; 891 | ColumnsOffsetX = 0.0f; 892 | ColumnsSet = NULL; 893 | } 894 | }; 895 | 896 | // Windows data 897 | struct IMGUI_API ImGuiWindow 898 | { 899 | char* Name; 900 | ImGuiID ID; // == ImHash(Name) 901 | ImGuiWindowFlags Flags; // See enum ImGuiWindowFlags_ 902 | ImVec2 PosFloat; 903 | ImVec2 Pos; // Position rounded-up to nearest pixel 904 | ImVec2 Size; // Current size (==SizeFull or collapsed title bar size) 905 | ImVec2 SizeFull; // Size when non collapsed 906 | ImVec2 SizeFullAtLastBegin; // Copy of SizeFull at the end of Begin. This is the reference value we'll use on the next frame to decide if we need scrollbars. 907 | ImVec2 SizeContents; // Size of contents (== extents reach of the drawing cursor) from previous frame. Include decoration, window title, border, menu, etc. 908 | ImVec2 SizeContentsExplicit; // Size of contents explicitly set by the user via SetNextWindowContentSize() 909 | ImRect ContentsRegionRect; // Maximum visible content position in window coordinates. ~~ (SizeContentsExplicit ? SizeContentsExplicit : Size - ScrollbarSizes) - CursorStartPos, per axis 910 | ImVec2 WindowPadding; // Window padding at the time of begin. 911 | float WindowRounding; // Window rounding at the time of begin. 912 | float WindowBorderSize; // Window border size at the time of begin. 913 | ImGuiID MoveId; // == window->GetID("#MOVE") 914 | ImGuiID ChildId; // Id of corresponding item in parent window (for child windows) 915 | ImVec2 Scroll; 916 | ImVec2 ScrollTarget; // target scroll position. stored as cursor position with scrolling canceled out, so the highest point is always 0.0f. (FLT_MAX for no change) 917 | ImVec2 ScrollTargetCenterRatio; // 0.0f = scroll so that target position is at top, 0.5f = scroll so that target position is centered 918 | bool ScrollbarX, ScrollbarY; 919 | ImVec2 ScrollbarSizes; 920 | bool Active; // Set to true on Begin(), unless Collapsed 921 | bool WasActive; 922 | bool WriteAccessed; // Set to true when any widget access the current window 923 | bool Collapsed; // Set when collapsing window to become only title-bar 924 | bool CollapseToggleWanted; 925 | bool SkipItems; // Set when items can safely be all clipped (e.g. window not visible or collapsed) 926 | bool Appearing; // Set during the frame where the window is appearing (or re-appearing) 927 | bool CloseButton; // Set when the window has a close button (p_open != NULL) 928 | int BeginOrderWithinParent; // Order within immediate parent window, if we are a child window. Otherwise 0. 929 | int BeginOrderWithinContext; // Order within entire imgui context. This is mostly used for debugging submission order related issues. 930 | int BeginCount; // Number of Begin() during the current frame (generally 0 or 1, 1+ if appending via multiple Begin/End pairs) 931 | ImGuiID PopupId; // ID in the popup stack when this window is used as a popup/menu (because we use generic Name/ID for recycling) 932 | int AutoFitFramesX, AutoFitFramesY; 933 | bool AutoFitOnlyGrows; 934 | int AutoFitChildAxises; 935 | ImGuiDir AutoPosLastDirection; 936 | int HiddenFrames; 937 | ImGuiCond SetWindowPosAllowFlags; // store condition flags for next SetWindowPos() call. 938 | ImGuiCond SetWindowSizeAllowFlags; // store condition flags for next SetWindowSize() call. 939 | ImGuiCond SetWindowCollapsedAllowFlags; // store condition flags for next SetWindowCollapsed() call. 940 | ImVec2 SetWindowPosVal; // store window position when using a non-zero Pivot (position set needs to be processed when we know the window size) 941 | ImVec2 SetWindowPosPivot; // store window pivot for positioning. ImVec2(0,0) when positioning from top-left corner; ImVec2(0.5f,0.5f) for centering; ImVec2(1,1) for bottom right. 942 | 943 | ImGuiDrawContext DC; // Temporary per-window data, reset at the beginning of the frame 944 | ImVector IDStack; // ID stack. ID are hashes seeded with the value at the top of the stack 945 | ImRect ClipRect; // = DrawList->clip_rect_stack.back(). Scissoring / clipping rectangle. x1, y1, x2, y2. 946 | ImRect WindowRectClipped; // = WindowRect just after setup in Begin(). == window->Rect() for root window. 947 | ImRect InnerRect, InnerClipRect; 948 | int LastFrameActive; 949 | float ItemWidthDefault; 950 | ImGuiMenuColumns MenuColumns; // Simplified columns storage for menu items 951 | ImGuiStorage StateStorage; 952 | ImVector ColumnsStorage; 953 | float FontWindowScale; // Scale multiplier per-window 954 | ImDrawList* DrawList; 955 | ImGuiWindow* ParentWindow; // If we are a child _or_ popup window, this is pointing to our parent. Otherwise NULL. 956 | ImGuiWindow* RootWindow; // Point to ourself or first ancestor that is not a child window. 957 | ImGuiWindow* RootWindowForTitleBarHighlight; // Point to ourself or first ancestor which will display TitleBgActive color when this window is active. 958 | ImGuiWindow* RootWindowForTabbing; // Point to ourself or first ancestor which can be CTRL-Tabbed into. 959 | ImGuiWindow* RootWindowForNav; // Point to ourself or first ancestor which doesn't have the NavFlattened flag. 960 | 961 | ImGuiWindow* NavLastChildNavWindow; // When going to the menu bar, we remember the child window we came from. (This could probably be made implicit if we kept g.Windows sorted by last focused including child window.) 962 | ImGuiID NavLastIds[2]; // Last known NavId for this window, per layer (0/1) 963 | ImRect NavRectRel[2]; // Reference rectangle, in window relative space 964 | 965 | // Navigation / Focus 966 | // FIXME-NAV: Merge all this with the new Nav system, at least the request variables should be moved to ImGuiContext 967 | int FocusIdxAllCounter; // Start at -1 and increase as assigned via FocusItemRegister() 968 | int FocusIdxTabCounter; // (same, but only count widgets which you can Tab through) 969 | int FocusIdxAllRequestCurrent; // Item being requested for focus 970 | int FocusIdxTabRequestCurrent; // Tab-able item being requested for focus 971 | int FocusIdxAllRequestNext; // Item being requested for focus, for next update (relies on layout to be stable between the frame pressing TAB and the next frame) 972 | int FocusIdxTabRequestNext; // " 973 | 974 | public: 975 | ImGuiWindow(ImGuiContext* context, const char* name); 976 | ~ImGuiWindow(); 977 | 978 | ImGuiID GetID(const char* str, const char* str_end = NULL); 979 | ImGuiID GetID(const void* ptr); 980 | ImGuiID GetIDNoKeepAlive(const char* str, const char* str_end = NULL); 981 | ImGuiID GetIDFromRectangle(const ImRect& r_abs); 982 | 983 | // We don't use g.FontSize because the window may be != g.CurrentWidow. 984 | ImRect Rect() const { return ImRect(Pos.x, Pos.y, Pos.x+Size.x, Pos.y+Size.y); } 985 | float CalcFontSize() const { return GImGui->FontBaseSize * FontWindowScale; } 986 | float TitleBarHeight() const { return (Flags & ImGuiWindowFlags_NoTitleBar) ? 0.0f : CalcFontSize() + GImGui->Style.FramePadding.y * 2.0f; } 987 | ImRect TitleBarRect() const { return ImRect(Pos, ImVec2(Pos.x + SizeFull.x, Pos.y + TitleBarHeight())); } 988 | float MenuBarHeight() const { return (Flags & ImGuiWindowFlags_MenuBar) ? CalcFontSize() + GImGui->Style.FramePadding.y * 2.0f : 0.0f; } 989 | ImRect MenuBarRect() const { float y1 = Pos.y + TitleBarHeight(); return ImRect(Pos.x, y1, Pos.x + SizeFull.x, y1 + MenuBarHeight()); } 990 | }; 991 | 992 | // Backup and restore just enough data to be able to use IsItemHovered() on item A after another B in the same window has overwritten the data. 993 | struct ImGuiItemHoveredDataBackup 994 | { 995 | ImGuiID LastItemId; 996 | ImGuiItemStatusFlags LastItemStatusFlags; 997 | ImRect LastItemRect; 998 | ImRect LastItemDisplayRect; 999 | 1000 | ImGuiItemHoveredDataBackup() { Backup(); } 1001 | void Backup() { ImGuiWindow* window = GImGui->CurrentWindow; LastItemId = window->DC.LastItemId; LastItemStatusFlags = window->DC.LastItemStatusFlags; LastItemRect = window->DC.LastItemRect; LastItemDisplayRect = window->DC.LastItemDisplayRect; } 1002 | void Restore() const { ImGuiWindow* window = GImGui->CurrentWindow; window->DC.LastItemId = LastItemId; window->DC.LastItemStatusFlags = LastItemStatusFlags; window->DC.LastItemRect = LastItemRect; window->DC.LastItemDisplayRect = LastItemDisplayRect; } 1003 | }; 1004 | 1005 | //----------------------------------------------------------------------------- 1006 | // Internal API 1007 | // No guarantee of forward compatibility here. 1008 | //----------------------------------------------------------------------------- 1009 | 1010 | namespace ImGui 1011 | { 1012 | // We should always have a CurrentWindow in the stack (there is an implicit "Debug" window) 1013 | // If this ever crash because g.CurrentWindow is NULL it means that either 1014 | // - ImGui::NewFrame() has never been called, which is illegal. 1015 | // - You are calling ImGui functions after ImGui::Render() and before the next ImGui::NewFrame(), which is also illegal. 1016 | inline ImGuiWindow* GetCurrentWindowRead() { ImGuiContext& g = *GImGui; return g.CurrentWindow; } 1017 | inline ImGuiWindow* GetCurrentWindow() { ImGuiContext& g = *GImGui; g.CurrentWindow->WriteAccessed = true; return g.CurrentWindow; } 1018 | IMGUI_API ImGuiWindow* FindWindowByName(const char* name); 1019 | IMGUI_API void FocusWindow(ImGuiWindow* window); 1020 | IMGUI_API void BringWindowToFront(ImGuiWindow* window); 1021 | IMGUI_API void BringWindowToBack(ImGuiWindow* window); 1022 | IMGUI_API bool IsWindowChildOf(ImGuiWindow* window, ImGuiWindow* potential_parent); 1023 | IMGUI_API bool IsWindowNavFocusable(ImGuiWindow* window); 1024 | 1025 | IMGUI_API void Initialize(ImGuiContext* context); 1026 | IMGUI_API void Shutdown(ImGuiContext* context); // Since 1.60 this is a _private_ function. You can call DestroyContext() to destroy the context created by CreateContext(). 1027 | 1028 | IMGUI_API void MarkIniSettingsDirty(); 1029 | IMGUI_API ImGuiSettingsHandler* FindSettingsHandler(const char* type_name); 1030 | IMGUI_API ImGuiWindowSettings* FindWindowSettings(ImGuiID id); 1031 | 1032 | IMGUI_API void SetActiveID(ImGuiID id, ImGuiWindow* window); 1033 | IMGUI_API ImGuiID GetActiveID(); 1034 | IMGUI_API void SetFocusID(ImGuiID id, ImGuiWindow* window); 1035 | IMGUI_API void ClearActiveID(); 1036 | IMGUI_API void SetHoveredID(ImGuiID id); 1037 | IMGUI_API ImGuiID GetHoveredID(); 1038 | IMGUI_API void KeepAliveID(ImGuiID id); 1039 | 1040 | IMGUI_API void ItemSize(const ImVec2& size, float text_offset_y = 0.0f); 1041 | IMGUI_API void ItemSize(const ImRect& bb, float text_offset_y = 0.0f); 1042 | IMGUI_API bool ItemAdd(const ImRect& bb, ImGuiID id, const ImRect* nav_bb = NULL); 1043 | IMGUI_API bool ItemHoverable(const ImRect& bb, ImGuiID id); 1044 | IMGUI_API bool IsClippedEx(const ImRect& bb, ImGuiID id, bool clip_even_when_logged); 1045 | IMGUI_API bool FocusableItemRegister(ImGuiWindow* window, ImGuiID id, bool tab_stop = true); // Return true if focus is requested 1046 | IMGUI_API void FocusableItemUnregister(ImGuiWindow* window); 1047 | IMGUI_API ImVec2 CalcItemSize(ImVec2 size, float default_x, float default_y); 1048 | IMGUI_API float CalcWrapWidthForPos(const ImVec2& pos, float wrap_pos_x); 1049 | IMGUI_API void PushMultiItemsWidths(int components, float width_full = 0.0f); 1050 | IMGUI_API void PushItemFlag(ImGuiItemFlags option, bool enabled); 1051 | IMGUI_API void PopItemFlag(); 1052 | 1053 | IMGUI_API void SetCurrentFont(ImFont* font); 1054 | 1055 | IMGUI_API void OpenPopupEx(ImGuiID id); 1056 | IMGUI_API void ClosePopup(ImGuiID id); 1057 | IMGUI_API void ClosePopupsOverWindow(ImGuiWindow* ref_window); 1058 | IMGUI_API bool IsPopupOpen(ImGuiID id); 1059 | IMGUI_API bool BeginPopupEx(ImGuiID id, ImGuiWindowFlags extra_flags); 1060 | IMGUI_API void BeginTooltipEx(ImGuiWindowFlags extra_flags, bool override_previous_tooltip = true); 1061 | 1062 | IMGUI_API void NavInitWindow(ImGuiWindow* window, bool force_reinit); 1063 | IMGUI_API void NavMoveRequestCancel(); 1064 | IMGUI_API void ActivateItem(ImGuiID id); // Remotely activate a button, checkbox, tree node etc. given its unique ID. activation is queued and processed on the next frame when the item is encountered again. 1065 | 1066 | IMGUI_API float GetNavInputAmount(ImGuiNavInput n, ImGuiInputReadMode mode); 1067 | IMGUI_API ImVec2 GetNavInputAmount2d(ImGuiNavDirSourceFlags dir_sources, ImGuiInputReadMode mode, float slow_factor = 0.0f, float fast_factor = 0.0f); 1068 | IMGUI_API int CalcTypematicPressedRepeatAmount(float t, float t_prev, float repeat_delay, float repeat_rate); 1069 | 1070 | IMGUI_API void Scrollbar(ImGuiLayoutType direction); 1071 | IMGUI_API void VerticalSeparator(); // Vertical separator, for menu bars (use current line height). not exposed because it is misleading what it doesn't have an effect on regular layout. 1072 | IMGUI_API bool SplitterBehavior(ImGuiID id, const ImRect& bb, ImGuiAxis axis, float* size1, float* size2, float min_size1, float min_size2, float hover_extend = 0.0f); 1073 | 1074 | IMGUI_API bool BeginDragDropTargetCustom(const ImRect& bb, ImGuiID id); 1075 | IMGUI_API void ClearDragDrop(); 1076 | IMGUI_API bool IsDragDropPayloadBeingAccepted(); 1077 | 1078 | // FIXME-WIP: New Columns API 1079 | IMGUI_API void BeginColumns(const char* str_id, int count, ImGuiColumnsFlags flags = 0); // setup number of columns. use an identifier to distinguish multiple column sets. close with EndColumns(). 1080 | IMGUI_API void EndColumns(); // close columns 1081 | IMGUI_API void PushColumnClipRect(int column_index = -1); 1082 | 1083 | // NB: All position are in absolute pixels coordinates (never using window coordinates internally) 1084 | // AVOID USING OUTSIDE OF IMGUI.CPP! NOT FOR PUBLIC CONSUMPTION. THOSE FUNCTIONS ARE A MESS. THEIR SIGNATURE AND BEHAVIOR WILL CHANGE, THEY NEED TO BE REFACTORED INTO SOMETHING DECENT. 1085 | IMGUI_API void RenderText(ImVec2 pos, const char* text, const char* text_end = NULL, bool hide_text_after_hash = true); 1086 | IMGUI_API void RenderTextWrapped(ImVec2 pos, const char* text, const char* text_end, float wrap_width); 1087 | IMGUI_API void RenderTextClipped(const ImVec2& pos_min, const ImVec2& pos_max, const char* text, const char* text_end, const ImVec2* text_size_if_known, const ImVec2& align = ImVec2(0,0), const ImRect* clip_rect = NULL); 1088 | IMGUI_API void RenderFrame(ImVec2 p_min, ImVec2 p_max, ImU32 fill_col, bool border = true, float rounding = 0.0f); 1089 | IMGUI_API void RenderFrameBorder(ImVec2 p_min, ImVec2 p_max, float rounding = 0.0f); 1090 | IMGUI_API void RenderColorRectWithAlphaCheckerboard(ImVec2 p_min, ImVec2 p_max, ImU32 fill_col, float grid_step, ImVec2 grid_off, float rounding = 0.0f, int rounding_corners_flags = ~0); 1091 | IMGUI_API void RenderArrow(ImVec2 pos, ImGuiDir dir, float scale = 1.0f); 1092 | IMGUI_API void RenderBullet(ImVec2 pos); 1093 | IMGUI_API void RenderCheckMark(ImVec2 pos, ImU32 col, float sz); 1094 | IMGUI_API void RenderNavHighlight(const ImRect& bb, ImGuiID id, ImGuiNavHighlightFlags flags = ImGuiNavHighlightFlags_TypeDefault); // Navigation highlight 1095 | IMGUI_API void RenderRectFilledRangeH(ImDrawList* draw_list, const ImRect& rect, ImU32 col, float x_start_norm, float x_end_norm, float rounding); 1096 | IMGUI_API const char* FindRenderedTextEnd(const char* text, const char* text_end = NULL); // Find the optional ## from which we stop displaying text. 1097 | 1098 | IMGUI_API bool ButtonBehavior(const ImRect& bb, ImGuiID id, bool* out_hovered, bool* out_held, ImGuiButtonFlags flags = 0); 1099 | IMGUI_API bool ButtonEx(const char* label, const ImVec2& size_arg = ImVec2(0,0), ImGuiButtonFlags flags = 0); 1100 | IMGUI_API bool CloseButton(ImGuiID id, const ImVec2& pos, float radius); 1101 | IMGUI_API bool ArrowButton(ImGuiID id, ImGuiDir dir, ImVec2 padding, ImGuiButtonFlags flags = 0); 1102 | 1103 | IMGUI_API bool SliderBehavior(const ImRect& frame_bb, ImGuiID id, float* v, float v_min, float v_max, float power, int decimal_precision, ImGuiSliderFlags flags = 0); 1104 | IMGUI_API bool SliderFloatN(const char* label, float* v, int components, float v_min, float v_max, const char* display_format, float power); 1105 | IMGUI_API bool SliderIntN(const char* label, int* v, int components, int v_min, int v_max, const char* display_format); 1106 | 1107 | IMGUI_API bool DragBehavior(const ImRect& frame_bb, ImGuiID id, float* v, float v_speed, float v_min, float v_max, int decimal_precision, float power); 1108 | IMGUI_API bool DragFloatN(const char* label, float* v, int components, float v_speed, float v_min, float v_max, const char* display_format, float power); 1109 | IMGUI_API bool DragIntN(const char* label, int* v, int components, float v_speed, int v_min, int v_max, const char* display_format); 1110 | 1111 | IMGUI_API bool InputTextEx(const char* label, char* buf, int buf_size, const ImVec2& size_arg, ImGuiInputTextFlags flags, ImGuiTextEditCallback callback = NULL, void* user_data = NULL); 1112 | IMGUI_API bool InputFloatN(const char* label, float* v, int components, int decimal_precision, ImGuiInputTextFlags extra_flags); 1113 | IMGUI_API bool InputIntN(const char* label, int* v, int components, ImGuiInputTextFlags extra_flags); 1114 | IMGUI_API bool InputScalarEx(const char* label, ImGuiDataType data_type, void* data_ptr, void* step_ptr, void* step_fast_ptr, const char* scalar_format, ImGuiInputTextFlags extra_flags); 1115 | IMGUI_API bool InputScalarAsWidgetReplacement(const ImRect& aabb, const char* label, ImGuiDataType data_type, void* data_ptr, ImGuiID id, int decimal_precision); 1116 | 1117 | IMGUI_API void ColorTooltip(const char* text, const float* col, ImGuiColorEditFlags flags); 1118 | IMGUI_API void ColorEditOptionsPopup(const float* col, ImGuiColorEditFlags flags); 1119 | 1120 | IMGUI_API bool TreeNodeBehavior(ImGuiID id, ImGuiTreeNodeFlags flags, const char* label, const char* label_end = NULL); 1121 | IMGUI_API bool TreeNodeBehaviorIsOpen(ImGuiID id, ImGuiTreeNodeFlags flags = 0); // Consume previous SetNextTreeNodeOpened() data, if any. May return true when logging 1122 | IMGUI_API void TreePushRawID(ImGuiID id); 1123 | 1124 | IMGUI_API void PlotEx(ImGuiPlotType plot_type, const char* label, float (*values_getter)(void* data, int idx), void* data, int values_count, int values_offset, const char* overlay_text, float scale_min, float scale_max, ImVec2 graph_size); 1125 | 1126 | IMGUI_API int ParseFormatPrecision(const char* fmt, int default_value); 1127 | IMGUI_API float RoundScalar(float value, int decimal_precision); 1128 | 1129 | // Shade functions 1130 | IMGUI_API void ShadeVertsLinearColorGradientKeepAlpha(ImDrawVert* vert_start, ImDrawVert* vert_end, ImVec2 gradient_p0, ImVec2 gradient_p1, ImU32 col0, ImU32 col1); 1131 | IMGUI_API void ShadeVertsLinearAlphaGradientForLeftToRightText(ImDrawVert* vert_start, ImDrawVert* vert_end, float gradient_p0_x, float gradient_p1_x); 1132 | IMGUI_API void ShadeVertsLinearUV(ImDrawVert* vert_start, ImDrawVert* vert_end, const ImVec2& a, const ImVec2& b, const ImVec2& uv_a, const ImVec2& uv_b, bool clamp); 1133 | 1134 | } // namespace ImGui 1135 | 1136 | // ImFontAtlas internals 1137 | IMGUI_API bool ImFontAtlasBuildWithStbTruetype(ImFontAtlas* atlas); 1138 | IMGUI_API void ImFontAtlasBuildRegisterDefaultCustomRects(ImFontAtlas* atlas); 1139 | IMGUI_API void ImFontAtlasBuildSetupFont(ImFontAtlas* atlas, ImFont* font, ImFontConfig* font_config, float ascent, float descent); 1140 | IMGUI_API void ImFontAtlasBuildPackCustomRects(ImFontAtlas* atlas, void* spc); 1141 | IMGUI_API void ImFontAtlasBuildFinish(ImFontAtlas* atlas); 1142 | IMGUI_API void ImFontAtlasBuildMultiplyCalcLookupTable(unsigned char out_table[256], float in_multiply_factor); 1143 | IMGUI_API void ImFontAtlasBuildMultiplyRectAlpha8(const unsigned char table[256], unsigned char* pixels, int x, int y, int w, int h, int stride); 1144 | 1145 | #ifdef __clang__ 1146 | #pragma clang diagnostic pop 1147 | #endif 1148 | 1149 | #ifdef _MSC_VER 1150 | #pragma warning (pop) 1151 | #endif 1152 | -------------------------------------------------------------------------------- /imgui_winapi_gl2/stb_rect_pack.h: -------------------------------------------------------------------------------- 1 | // stb_rect_pack.h - v0.11 - public domain - rectangle packing 2 | // Sean Barrett 2014 3 | // 4 | // Useful for e.g. packing rectangular textures into an atlas. 5 | // Does not do rotation. 6 | // 7 | // Not necessarily the awesomest packing method, but better than 8 | // the totally naive one in stb_truetype (which is primarily what 9 | // this is meant to replace). 10 | // 11 | // Has only had a few tests run, may have issues. 12 | // 13 | // More docs to come. 14 | // 15 | // No memory allocations; uses qsort() and assert() from stdlib. 16 | // Can override those by defining STBRP_SORT and STBRP_ASSERT. 17 | // 18 | // This library currently uses the Skyline Bottom-Left algorithm. 19 | // 20 | // Please note: better rectangle packers are welcome! Please 21 | // implement them to the same API, but with a different init 22 | // function. 23 | // 24 | // Credits 25 | // 26 | // Library 27 | // Sean Barrett 28 | // Minor features 29 | // Martins Mozeiko 30 | // github:IntellectualKitty 31 | // 32 | // Bugfixes / warning fixes 33 | // Jeremy Jaussaud 34 | // 35 | // Version history: 36 | // 37 | // 0.11 (2017-03-03) return packing success/fail result 38 | // 0.10 (2016-10-25) remove cast-away-const to avoid warnings 39 | // 0.09 (2016-08-27) fix compiler warnings 40 | // 0.08 (2015-09-13) really fix bug with empty rects (w=0 or h=0) 41 | // 0.07 (2015-09-13) fix bug with empty rects (w=0 or h=0) 42 | // 0.06 (2015-04-15) added STBRP_SORT to allow replacing qsort 43 | // 0.05: added STBRP_ASSERT to allow replacing assert 44 | // 0.04: fixed minor bug in STBRP_LARGE_RECTS support 45 | // 0.01: initial release 46 | // 47 | // LICENSE 48 | // 49 | // See end of file for license information. 50 | 51 | ////////////////////////////////////////////////////////////////////////////// 52 | // 53 | // INCLUDE SECTION 54 | // 55 | 56 | #ifndef STB_INCLUDE_STB_RECT_PACK_H 57 | #define STB_INCLUDE_STB_RECT_PACK_H 58 | 59 | #define STB_RECT_PACK_VERSION 1 60 | 61 | #ifdef STBRP_STATIC 62 | #define STBRP_DEF static 63 | #else 64 | #define STBRP_DEF extern 65 | #endif 66 | 67 | #ifdef __cplusplus 68 | extern "C" { 69 | #endif 70 | 71 | typedef struct stbrp_context stbrp_context; 72 | typedef struct stbrp_node stbrp_node; 73 | typedef struct stbrp_rect stbrp_rect; 74 | 75 | #ifdef STBRP_LARGE_RECTS 76 | typedef int stbrp_coord; 77 | #else 78 | typedef unsigned short stbrp_coord; 79 | #endif 80 | 81 | STBRP_DEF int stbrp_pack_rects (stbrp_context *context, stbrp_rect *rects, int num_rects); 82 | // Assign packed locations to rectangles. The rectangles are of type 83 | // 'stbrp_rect' defined below, stored in the array 'rects', and there 84 | // are 'num_rects' many of them. 85 | // 86 | // Rectangles which are successfully packed have the 'was_packed' flag 87 | // set to a non-zero value and 'x' and 'y' store the minimum location 88 | // on each axis (i.e. bottom-left in cartesian coordinates, top-left 89 | // if you imagine y increasing downwards). Rectangles which do not fit 90 | // have the 'was_packed' flag set to 0. 91 | // 92 | // You should not try to access the 'rects' array from another thread 93 | // while this function is running, as the function temporarily reorders 94 | // the array while it executes. 95 | // 96 | // To pack into another rectangle, you need to call stbrp_init_target 97 | // again. To continue packing into the same rectangle, you can call 98 | // this function again. Calling this multiple times with multiple rect 99 | // arrays will probably produce worse packing results than calling it 100 | // a single time with the full rectangle array, but the option is 101 | // available. 102 | // 103 | // The function returns 1 if all of the rectangles were successfully 104 | // packed and 0 otherwise. 105 | 106 | struct stbrp_rect 107 | { 108 | // reserved for your use: 109 | int id; 110 | 111 | // input: 112 | stbrp_coord w, h; 113 | 114 | // output: 115 | stbrp_coord x, y; 116 | int was_packed; // non-zero if valid packing 117 | 118 | }; // 16 bytes, nominally 119 | 120 | 121 | STBRP_DEF void stbrp_init_target (stbrp_context *context, int width, int height, stbrp_node *nodes, int num_nodes); 122 | // Initialize a rectangle packer to: 123 | // pack a rectangle that is 'width' by 'height' in dimensions 124 | // using temporary storage provided by the array 'nodes', which is 'num_nodes' long 125 | // 126 | // You must call this function every time you start packing into a new target. 127 | // 128 | // There is no "shutdown" function. The 'nodes' memory must stay valid for 129 | // the following stbrp_pack_rects() call (or calls), but can be freed after 130 | // the call (or calls) finish. 131 | // 132 | // Note: to guarantee best results, either: 133 | // 1. make sure 'num_nodes' >= 'width' 134 | // or 2. call stbrp_allow_out_of_mem() defined below with 'allow_out_of_mem = 1' 135 | // 136 | // If you don't do either of the above things, widths will be quantized to multiples 137 | // of small integers to guarantee the algorithm doesn't run out of temporary storage. 138 | // 139 | // If you do #2, then the non-quantized algorithm will be used, but the algorithm 140 | // may run out of temporary storage and be unable to pack some rectangles. 141 | 142 | STBRP_DEF void stbrp_setup_allow_out_of_mem (stbrp_context *context, int allow_out_of_mem); 143 | // Optionally call this function after init but before doing any packing to 144 | // change the handling of the out-of-temp-memory scenario, described above. 145 | // If you call init again, this will be reset to the default (false). 146 | 147 | 148 | STBRP_DEF void stbrp_setup_heuristic (stbrp_context *context, int heuristic); 149 | // Optionally select which packing heuristic the library should use. Different 150 | // heuristics will produce better/worse results for different data sets. 151 | // If you call init again, this will be reset to the default. 152 | 153 | enum 154 | { 155 | STBRP_HEURISTIC_Skyline_default=0, 156 | STBRP_HEURISTIC_Skyline_BL_sortHeight = STBRP_HEURISTIC_Skyline_default, 157 | STBRP_HEURISTIC_Skyline_BF_sortHeight 158 | }; 159 | 160 | 161 | ////////////////////////////////////////////////////////////////////////////// 162 | // 163 | // the details of the following structures don't matter to you, but they must 164 | // be visible so you can handle the memory allocations for them 165 | 166 | struct stbrp_node 167 | { 168 | stbrp_coord x,y; 169 | stbrp_node *next; 170 | }; 171 | 172 | struct stbrp_context 173 | { 174 | int width; 175 | int height; 176 | int align; 177 | int init_mode; 178 | int heuristic; 179 | int num_nodes; 180 | stbrp_node *active_head; 181 | stbrp_node *free_head; 182 | stbrp_node extra[2]; // we allocate two extra nodes so optimal user-node-count is 'width' not 'width+2' 183 | }; 184 | 185 | #ifdef __cplusplus 186 | } 187 | #endif 188 | 189 | #endif 190 | 191 | ////////////////////////////////////////////////////////////////////////////// 192 | // 193 | // IMPLEMENTATION SECTION 194 | // 195 | 196 | #ifdef STB_RECT_PACK_IMPLEMENTATION 197 | #ifndef STBRP_SORT 198 | #include 199 | #define STBRP_SORT qsort 200 | #endif 201 | 202 | #ifndef STBRP_ASSERT 203 | #include 204 | #define STBRP_ASSERT assert 205 | #endif 206 | 207 | #ifdef _MSC_VER 208 | #define STBRP__NOTUSED(v) (void)(v) 209 | #define STBRP__CDECL __cdecl 210 | #else 211 | #define STBRP__NOTUSED(v) (void)sizeof(v) 212 | #define STBRP__CDECL 213 | #endif 214 | 215 | enum 216 | { 217 | STBRP__INIT_skyline = 1 218 | }; 219 | 220 | STBRP_DEF void stbrp_setup_heuristic(stbrp_context *context, int heuristic) 221 | { 222 | switch (context->init_mode) { 223 | case STBRP__INIT_skyline: 224 | STBRP_ASSERT(heuristic == STBRP_HEURISTIC_Skyline_BL_sortHeight || heuristic == STBRP_HEURISTIC_Skyline_BF_sortHeight); 225 | context->heuristic = heuristic; 226 | break; 227 | default: 228 | STBRP_ASSERT(0); 229 | } 230 | } 231 | 232 | STBRP_DEF void stbrp_setup_allow_out_of_mem(stbrp_context *context, int allow_out_of_mem) 233 | { 234 | if (allow_out_of_mem) 235 | // if it's ok to run out of memory, then don't bother aligning them; 236 | // this gives better packing, but may fail due to OOM (even though 237 | // the rectangles easily fit). @TODO a smarter approach would be to only 238 | // quantize once we've hit OOM, then we could get rid of this parameter. 239 | context->align = 1; 240 | else { 241 | // if it's not ok to run out of memory, then quantize the widths 242 | // so that num_nodes is always enough nodes. 243 | // 244 | // I.e. num_nodes * align >= width 245 | // align >= width / num_nodes 246 | // align = ceil(width/num_nodes) 247 | 248 | context->align = (context->width + context->num_nodes-1) / context->num_nodes; 249 | } 250 | } 251 | 252 | STBRP_DEF void stbrp_init_target(stbrp_context *context, int width, int height, stbrp_node *nodes, int num_nodes) 253 | { 254 | int i; 255 | #ifndef STBRP_LARGE_RECTS 256 | STBRP_ASSERT(width <= 0xffff && height <= 0xffff); 257 | #endif 258 | 259 | for (i=0; i < num_nodes-1; ++i) 260 | nodes[i].next = &nodes[i+1]; 261 | nodes[i].next = NULL; 262 | context->init_mode = STBRP__INIT_skyline; 263 | context->heuristic = STBRP_HEURISTIC_Skyline_default; 264 | context->free_head = &nodes[0]; 265 | context->active_head = &context->extra[0]; 266 | context->width = width; 267 | context->height = height; 268 | context->num_nodes = num_nodes; 269 | stbrp_setup_allow_out_of_mem(context, 0); 270 | 271 | // node 0 is the full width, node 1 is the sentinel (lets us not store width explicitly) 272 | context->extra[0].x = 0; 273 | context->extra[0].y = 0; 274 | context->extra[0].next = &context->extra[1]; 275 | context->extra[1].x = (stbrp_coord) width; 276 | #ifdef STBRP_LARGE_RECTS 277 | context->extra[1].y = (1<<30); 278 | #else 279 | context->extra[1].y = 65535; 280 | #endif 281 | context->extra[1].next = NULL; 282 | } 283 | 284 | // find minimum y position if it starts at x1 285 | static int stbrp__skyline_find_min_y(stbrp_context *c, stbrp_node *first, int x0, int width, int *pwaste) 286 | { 287 | stbrp_node *node = first; 288 | int x1 = x0 + width; 289 | int min_y, visited_width, waste_area; 290 | 291 | STBRP__NOTUSED(c); 292 | 293 | STBRP_ASSERT(first->x <= x0); 294 | 295 | #if 0 296 | // skip in case we're past the node 297 | while (node->next->x <= x0) 298 | ++node; 299 | #else 300 | STBRP_ASSERT(node->next->x > x0); // we ended up handling this in the caller for efficiency 301 | #endif 302 | 303 | STBRP_ASSERT(node->x <= x0); 304 | 305 | min_y = 0; 306 | waste_area = 0; 307 | visited_width = 0; 308 | while (node->x < x1) { 309 | if (node->y > min_y) { 310 | // raise min_y higher. 311 | // we've accounted for all waste up to min_y, 312 | // but we'll now add more waste for everything we've visted 313 | waste_area += visited_width * (node->y - min_y); 314 | min_y = node->y; 315 | // the first time through, visited_width might be reduced 316 | if (node->x < x0) 317 | visited_width += node->next->x - x0; 318 | else 319 | visited_width += node->next->x - node->x; 320 | } else { 321 | // add waste area 322 | int under_width = node->next->x - node->x; 323 | if (under_width + visited_width > width) 324 | under_width = width - visited_width; 325 | waste_area += under_width * (min_y - node->y); 326 | visited_width += under_width; 327 | } 328 | node = node->next; 329 | } 330 | 331 | *pwaste = waste_area; 332 | return min_y; 333 | } 334 | 335 | typedef struct 336 | { 337 | int x,y; 338 | stbrp_node **prev_link; 339 | } stbrp__findresult; 340 | 341 | static stbrp__findresult stbrp__skyline_find_best_pos(stbrp_context *c, int width, int height) 342 | { 343 | int best_waste = (1<<30), best_x, best_y = (1 << 30); 344 | stbrp__findresult fr; 345 | stbrp_node **prev, *node, *tail, **best = NULL; 346 | 347 | // align to multiple of c->align 348 | width = (width + c->align - 1); 349 | width -= width % c->align; 350 | STBRP_ASSERT(width % c->align == 0); 351 | 352 | node = c->active_head; 353 | prev = &c->active_head; 354 | while (node->x + width <= c->width) { 355 | int y,waste; 356 | y = stbrp__skyline_find_min_y(c, node, node->x, width, &waste); 357 | if (c->heuristic == STBRP_HEURISTIC_Skyline_BL_sortHeight) { // actually just want to test BL 358 | // bottom left 359 | if (y < best_y) { 360 | best_y = y; 361 | best = prev; 362 | } 363 | } else { 364 | // best-fit 365 | if (y + height <= c->height) { 366 | // can only use it if it first vertically 367 | if (y < best_y || (y == best_y && waste < best_waste)) { 368 | best_y = y; 369 | best_waste = waste; 370 | best = prev; 371 | } 372 | } 373 | } 374 | prev = &node->next; 375 | node = node->next; 376 | } 377 | 378 | best_x = (best == NULL) ? 0 : (*best)->x; 379 | 380 | // if doing best-fit (BF), we also have to try aligning right edge to each node position 381 | // 382 | // e.g, if fitting 383 | // 384 | // ____________________ 385 | // |____________________| 386 | // 387 | // into 388 | // 389 | // | | 390 | // | ____________| 391 | // |____________| 392 | // 393 | // then right-aligned reduces waste, but bottom-left BL is always chooses left-aligned 394 | // 395 | // This makes BF take about 2x the time 396 | 397 | if (c->heuristic == STBRP_HEURISTIC_Skyline_BF_sortHeight) { 398 | tail = c->active_head; 399 | node = c->active_head; 400 | prev = &c->active_head; 401 | // find first node that's admissible 402 | while (tail->x < width) 403 | tail = tail->next; 404 | while (tail) { 405 | int xpos = tail->x - width; 406 | int y,waste; 407 | STBRP_ASSERT(xpos >= 0); 408 | // find the left position that matches this 409 | while (node->next->x <= xpos) { 410 | prev = &node->next; 411 | node = node->next; 412 | } 413 | STBRP_ASSERT(node->next->x > xpos && node->x <= xpos); 414 | y = stbrp__skyline_find_min_y(c, node, xpos, width, &waste); 415 | if (y + height < c->height) { 416 | if (y <= best_y) { 417 | if (y < best_y || waste < best_waste || (waste==best_waste && xpos < best_x)) { 418 | best_x = xpos; 419 | STBRP_ASSERT(y <= best_y); 420 | best_y = y; 421 | best_waste = waste; 422 | best = prev; 423 | } 424 | } 425 | } 426 | tail = tail->next; 427 | } 428 | } 429 | 430 | fr.prev_link = best; 431 | fr.x = best_x; 432 | fr.y = best_y; 433 | return fr; 434 | } 435 | 436 | static stbrp__findresult stbrp__skyline_pack_rectangle(stbrp_context *context, int width, int height) 437 | { 438 | // find best position according to heuristic 439 | stbrp__findresult res = stbrp__skyline_find_best_pos(context, width, height); 440 | stbrp_node *node, *cur; 441 | 442 | // bail if: 443 | // 1. it failed 444 | // 2. the best node doesn't fit (we don't always check this) 445 | // 3. we're out of memory 446 | if (res.prev_link == NULL || res.y + height > context->height || context->free_head == NULL) { 447 | res.prev_link = NULL; 448 | return res; 449 | } 450 | 451 | // on success, create new node 452 | node = context->free_head; 453 | node->x = (stbrp_coord) res.x; 454 | node->y = (stbrp_coord) (res.y + height); 455 | 456 | context->free_head = node->next; 457 | 458 | // insert the new node into the right starting point, and 459 | // let 'cur' point to the remaining nodes needing to be 460 | // stiched back in 461 | 462 | cur = *res.prev_link; 463 | if (cur->x < res.x) { 464 | // preserve the existing one, so start testing with the next one 465 | stbrp_node *next = cur->next; 466 | cur->next = node; 467 | cur = next; 468 | } else { 469 | *res.prev_link = node; 470 | } 471 | 472 | // from here, traverse cur and free the nodes, until we get to one 473 | // that shouldn't be freed 474 | while (cur->next && cur->next->x <= res.x + width) { 475 | stbrp_node *next = cur->next; 476 | // move the current node to the free list 477 | cur->next = context->free_head; 478 | context->free_head = cur; 479 | cur = next; 480 | } 481 | 482 | // stitch the list back in 483 | node->next = cur; 484 | 485 | if (cur->x < res.x + width) 486 | cur->x = (stbrp_coord) (res.x + width); 487 | 488 | #ifdef _DEBUG 489 | cur = context->active_head; 490 | while (cur->x < context->width) { 491 | STBRP_ASSERT(cur->x < cur->next->x); 492 | cur = cur->next; 493 | } 494 | STBRP_ASSERT(cur->next == NULL); 495 | 496 | { 497 | int count=0; 498 | cur = context->active_head; 499 | while (cur) { 500 | cur = cur->next; 501 | ++count; 502 | } 503 | cur = context->free_head; 504 | while (cur) { 505 | cur = cur->next; 506 | ++count; 507 | } 508 | STBRP_ASSERT(count == context->num_nodes+2); 509 | } 510 | #endif 511 | 512 | return res; 513 | } 514 | 515 | static int STBRP__CDECL rect_height_compare(const void *a, const void *b) 516 | { 517 | const stbrp_rect *p = (const stbrp_rect *) a; 518 | const stbrp_rect *q = (const stbrp_rect *) b; 519 | if (p->h > q->h) 520 | return -1; 521 | if (p->h < q->h) 522 | return 1; 523 | return (p->w > q->w) ? -1 : (p->w < q->w); 524 | } 525 | 526 | static int STBRP__CDECL rect_original_order(const void *a, const void *b) 527 | { 528 | const stbrp_rect *p = (const stbrp_rect *) a; 529 | const stbrp_rect *q = (const stbrp_rect *) b; 530 | return (p->was_packed < q->was_packed) ? -1 : (p->was_packed > q->was_packed); 531 | } 532 | 533 | #ifdef STBRP_LARGE_RECTS 534 | #define STBRP__MAXVAL 0xffffffff 535 | #else 536 | #define STBRP__MAXVAL 0xffff 537 | #endif 538 | 539 | STBRP_DEF int stbrp_pack_rects(stbrp_context *context, stbrp_rect *rects, int num_rects) 540 | { 541 | int i, all_rects_packed = 1; 542 | 543 | // we use the 'was_packed' field internally to allow sorting/unsorting 544 | for (i=0; i < num_rects; ++i) { 545 | rects[i].was_packed = i; 546 | #ifndef STBRP_LARGE_RECTS 547 | STBRP_ASSERT(rects[i].w <= 0xffff && rects[i].h <= 0xffff); 548 | #endif 549 | } 550 | 551 | // sort according to heuristic 552 | STBRP_SORT(rects, num_rects, sizeof(rects[0]), rect_height_compare); 553 | 554 | for (i=0; i < num_rects; ++i) { 555 | if (rects[i].w == 0 || rects[i].h == 0) { 556 | rects[i].x = rects[i].y = 0; // empty rect needs no space 557 | } else { 558 | stbrp__findresult fr = stbrp__skyline_pack_rectangle(context, rects[i].w, rects[i].h); 559 | if (fr.prev_link) { 560 | rects[i].x = (stbrp_coord) fr.x; 561 | rects[i].y = (stbrp_coord) fr.y; 562 | } else { 563 | rects[i].x = rects[i].y = STBRP__MAXVAL; 564 | } 565 | } 566 | } 567 | 568 | // unsort 569 | STBRP_SORT(rects, num_rects, sizeof(rects[0]), rect_original_order); 570 | 571 | // set was_packed flags and all_rects_packed status 572 | for (i=0; i < num_rects; ++i) { 573 | rects[i].was_packed = !(rects[i].x == STBRP__MAXVAL && rects[i].y == STBRP__MAXVAL); 574 | if (!rects[i].was_packed) 575 | all_rects_packed = 0; 576 | } 577 | 578 | // return the all_rects_packed status 579 | return all_rects_packed; 580 | } 581 | #endif 582 | 583 | /* 584 | ------------------------------------------------------------------------------ 585 | This software is available under 2 licenses -- choose whichever you prefer. 586 | ------------------------------------------------------------------------------ 587 | ALTERNATIVE A - MIT License 588 | Copyright (c) 2017 Sean Barrett 589 | Permission is hereby granted, free of charge, to any person obtaining a copy of 590 | this software and associated documentation files (the "Software"), to deal in 591 | the Software without restriction, including without limitation the rights to 592 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 593 | of the Software, and to permit persons to whom the Software is furnished to do 594 | so, subject to the following conditions: 595 | The above copyright notice and this permission notice shall be included in all 596 | copies or substantial portions of the Software. 597 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 598 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 599 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 600 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 601 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 602 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 603 | SOFTWARE. 604 | ------------------------------------------------------------------------------ 605 | ALTERNATIVE B - Public Domain (www.unlicense.org) 606 | This is free and unencumbered software released into the public domain. 607 | Anyone is free to copy, modify, publish, use, compile, sell, or distribute this 608 | software, either in source code form or as a compiled binary, for any purpose, 609 | commercial or non-commercial, and by any means. 610 | In jurisdictions that recognize copyright laws, the author or authors of this 611 | software dedicate any and all copyright interest in the software to the public 612 | domain. We make this dedication for the benefit of the public at large and to 613 | the detriment of our heirs and successors. We intend this dedication to be an 614 | overt act of relinquishment in perpetuity of all present and future rights to 615 | this software under copyright law. 616 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 617 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 618 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 619 | AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 620 | ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 621 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 622 | ------------------------------------------------------------------------------ 623 | */ 624 | -------------------------------------------------------------------------------- /imgui_winapi_gl2/stb_textedit.h: -------------------------------------------------------------------------------- 1 | // [ImGui] this is a slightly modified version of stb_truetype.h 1.9. Those changes would need to be pushed into nothings/sb 2 | // [ImGui] - fixed linestart handler when over last character of multi-line buffer + simplified existing code (#588, #815) 3 | // [ImGui] - fixed a state corruption/crash bug in stb_text_redo and stb_textedit_discard_redo (#715) 4 | // [ImGui] - fixed a crash bug in stb_textedit_discard_redo (#681) 5 | // [ImGui] - fixed some minor warnings 6 | 7 | // stb_textedit.h - v1.9 - public domain - Sean Barrett 8 | // Development of this library was sponsored by RAD Game Tools 9 | // 10 | // This C header file implements the guts of a multi-line text-editing 11 | // widget; you implement display, word-wrapping, and low-level string 12 | // insertion/deletion, and stb_textedit will map user inputs into 13 | // insertions & deletions, plus updates to the cursor position, 14 | // selection state, and undo state. 15 | // 16 | // It is intended for use in games and other systems that need to build 17 | // their own custom widgets and which do not have heavy text-editing 18 | // requirements (this library is not recommended for use for editing large 19 | // texts, as its performance does not scale and it has limited undo). 20 | // 21 | // Non-trivial behaviors are modelled after Windows text controls. 22 | // 23 | // 24 | // LICENSE 25 | // 26 | // This software is dual-licensed to the public domain and under the following 27 | // license: you are granted a perpetual, irrevocable license to copy, modify, 28 | // publish, and distribute this file as you see fit. 29 | // 30 | // 31 | // DEPENDENCIES 32 | // 33 | // Uses the C runtime function 'memmove', which you can override 34 | // by defining STB_TEXTEDIT_memmove before the implementation. 35 | // Uses no other functions. Performs no runtime allocations. 36 | // 37 | // 38 | // VERSION HISTORY 39 | // 40 | // 1.9 (2016-08-27) customizable move-by-word 41 | // 1.8 (2016-04-02) better keyboard handling when mouse button is down 42 | // 1.7 (2015-09-13) change y range handling in case baseline is non-0 43 | // 1.6 (2015-04-15) allow STB_TEXTEDIT_memmove 44 | // 1.5 (2014-09-10) add support for secondary keys for OS X 45 | // 1.4 (2014-08-17) fix signed/unsigned warnings 46 | // 1.3 (2014-06-19) fix mouse clicking to round to nearest char boundary 47 | // 1.2 (2014-05-27) fix some RAD types that had crept into the new code 48 | // 1.1 (2013-12-15) move-by-word (requires STB_TEXTEDIT_IS_SPACE ) 49 | // 1.0 (2012-07-26) improve documentation, initial public release 50 | // 0.3 (2012-02-24) bugfixes, single-line mode; insert mode 51 | // 0.2 (2011-11-28) fixes to undo/redo 52 | // 0.1 (2010-07-08) initial version 53 | // 54 | // ADDITIONAL CONTRIBUTORS 55 | // 56 | // Ulf Winklemann: move-by-word in 1.1 57 | // Fabian Giesen: secondary key inputs in 1.5 58 | // Martins Mozeiko: STB_TEXTEDIT_memmove 59 | // 60 | // Bugfixes: 61 | // Scott Graham 62 | // Daniel Keller 63 | // Omar Cornut 64 | // 65 | // USAGE 66 | // 67 | // This file behaves differently depending on what symbols you define 68 | // before including it. 69 | // 70 | // 71 | // Header-file mode: 72 | // 73 | // If you do not define STB_TEXTEDIT_IMPLEMENTATION before including this, 74 | // it will operate in "header file" mode. In this mode, it declares a 75 | // single public symbol, STB_TexteditState, which encapsulates the current 76 | // state of a text widget (except for the string, which you will store 77 | // separately). 78 | // 79 | // To compile in this mode, you must define STB_TEXTEDIT_CHARTYPE to a 80 | // primitive type that defines a single character (e.g. char, wchar_t, etc). 81 | // 82 | // To save space or increase undo-ability, you can optionally define the 83 | // following things that are used by the undo system: 84 | // 85 | // STB_TEXTEDIT_POSITIONTYPE small int type encoding a valid cursor position 86 | // STB_TEXTEDIT_UNDOSTATECOUNT the number of undo states to allow 87 | // STB_TEXTEDIT_UNDOCHARCOUNT the number of characters to store in the undo buffer 88 | // 89 | // If you don't define these, they are set to permissive types and 90 | // moderate sizes. The undo system does no memory allocations, so 91 | // it grows STB_TexteditState by the worst-case storage which is (in bytes): 92 | // 93 | // [4 + sizeof(STB_TEXTEDIT_POSITIONTYPE)] * STB_TEXTEDIT_UNDOSTATE_COUNT 94 | // + sizeof(STB_TEXTEDIT_CHARTYPE) * STB_TEXTEDIT_UNDOCHAR_COUNT 95 | // 96 | // 97 | // Implementation mode: 98 | // 99 | // If you define STB_TEXTEDIT_IMPLEMENTATION before including this, it 100 | // will compile the implementation of the text edit widget, depending 101 | // on a large number of symbols which must be defined before the include. 102 | // 103 | // The implementation is defined only as static functions. You will then 104 | // need to provide your own APIs in the same file which will access the 105 | // static functions. 106 | // 107 | // The basic concept is that you provide a "string" object which 108 | // behaves like an array of characters. stb_textedit uses indices to 109 | // refer to positions in the string, implicitly representing positions 110 | // in the displayed textedit. This is true for both plain text and 111 | // rich text; even with rich text stb_truetype interacts with your 112 | // code as if there was an array of all the displayed characters. 113 | // 114 | // Symbols that must be the same in header-file and implementation mode: 115 | // 116 | // STB_TEXTEDIT_CHARTYPE the character type 117 | // STB_TEXTEDIT_POSITIONTYPE small type that a valid cursor position 118 | // STB_TEXTEDIT_UNDOSTATECOUNT the number of undo states to allow 119 | // STB_TEXTEDIT_UNDOCHARCOUNT the number of characters to store in the undo buffer 120 | // 121 | // Symbols you must define for implementation mode: 122 | // 123 | // STB_TEXTEDIT_STRING the type of object representing a string being edited, 124 | // typically this is a wrapper object with other data you need 125 | // 126 | // STB_TEXTEDIT_STRINGLEN(obj) the length of the string (ideally O(1)) 127 | // STB_TEXTEDIT_LAYOUTROW(&r,obj,n) returns the results of laying out a line of characters 128 | // starting from character #n (see discussion below) 129 | // STB_TEXTEDIT_GETWIDTH(obj,n,i) returns the pixel delta from the xpos of the i'th character 130 | // to the xpos of the i+1'th char for a line of characters 131 | // starting at character #n (i.e. accounts for kerning 132 | // with previous char) 133 | // STB_TEXTEDIT_KEYTOTEXT(k) maps a keyboard input to an insertable character 134 | // (return type is int, -1 means not valid to insert) 135 | // STB_TEXTEDIT_GETCHAR(obj,i) returns the i'th character of obj, 0-based 136 | // STB_TEXTEDIT_NEWLINE the character returned by _GETCHAR() we recognize 137 | // as manually wordwrapping for end-of-line positioning 138 | // 139 | // STB_TEXTEDIT_DELETECHARS(obj,i,n) delete n characters starting at i 140 | // STB_TEXTEDIT_INSERTCHARS(obj,i,c*,n) insert n characters at i (pointed to by STB_TEXTEDIT_CHARTYPE*) 141 | // 142 | // STB_TEXTEDIT_K_SHIFT a power of two that is or'd in to a keyboard input to represent the shift key 143 | // 144 | // STB_TEXTEDIT_K_LEFT keyboard input to move cursor left 145 | // STB_TEXTEDIT_K_RIGHT keyboard input to move cursor right 146 | // STB_TEXTEDIT_K_UP keyboard input to move cursor up 147 | // STB_TEXTEDIT_K_DOWN keyboard input to move cursor down 148 | // STB_TEXTEDIT_K_LINESTART keyboard input to move cursor to start of line // e.g. HOME 149 | // STB_TEXTEDIT_K_LINEEND keyboard input to move cursor to end of line // e.g. END 150 | // STB_TEXTEDIT_K_TEXTSTART keyboard input to move cursor to start of text // e.g. ctrl-HOME 151 | // STB_TEXTEDIT_K_TEXTEND keyboard input to move cursor to end of text // e.g. ctrl-END 152 | // STB_TEXTEDIT_K_DELETE keyboard input to delete selection or character under cursor 153 | // STB_TEXTEDIT_K_BACKSPACE keyboard input to delete selection or character left of cursor 154 | // STB_TEXTEDIT_K_UNDO keyboard input to perform undo 155 | // STB_TEXTEDIT_K_REDO keyboard input to perform redo 156 | // 157 | // Optional: 158 | // STB_TEXTEDIT_K_INSERT keyboard input to toggle insert mode 159 | // STB_TEXTEDIT_IS_SPACE(ch) true if character is whitespace (e.g. 'isspace'), 160 | // required for default WORDLEFT/WORDRIGHT handlers 161 | // STB_TEXTEDIT_MOVEWORDLEFT(obj,i) custom handler for WORDLEFT, returns index to move cursor to 162 | // STB_TEXTEDIT_MOVEWORDRIGHT(obj,i) custom handler for WORDRIGHT, returns index to move cursor to 163 | // STB_TEXTEDIT_K_WORDLEFT keyboard input to move cursor left one word // e.g. ctrl-LEFT 164 | // STB_TEXTEDIT_K_WORDRIGHT keyboard input to move cursor right one word // e.g. ctrl-RIGHT 165 | // STB_TEXTEDIT_K_LINESTART2 secondary keyboard input to move cursor to start of line 166 | // STB_TEXTEDIT_K_LINEEND2 secondary keyboard input to move cursor to end of line 167 | // STB_TEXTEDIT_K_TEXTSTART2 secondary keyboard input to move cursor to start of text 168 | // STB_TEXTEDIT_K_TEXTEND2 secondary keyboard input to move cursor to end of text 169 | // 170 | // Todo: 171 | // STB_TEXTEDIT_K_PGUP keyboard input to move cursor up a page 172 | // STB_TEXTEDIT_K_PGDOWN keyboard input to move cursor down a page 173 | // 174 | // Keyboard input must be encoded as a single integer value; e.g. a character code 175 | // and some bitflags that represent shift states. to simplify the interface, SHIFT must 176 | // be a bitflag, so we can test the shifted state of cursor movements to allow selection, 177 | // i.e. (STB_TEXTED_K_RIGHT|STB_TEXTEDIT_K_SHIFT) should be shifted right-arrow. 178 | // 179 | // You can encode other things, such as CONTROL or ALT, in additional bits, and 180 | // then test for their presence in e.g. STB_TEXTEDIT_K_WORDLEFT. For example, 181 | // my Windows implementations add an additional CONTROL bit, and an additional KEYDOWN 182 | // bit. Then all of the STB_TEXTEDIT_K_ values bitwise-or in the KEYDOWN bit, 183 | // and I pass both WM_KEYDOWN and WM_CHAR events to the "key" function in the 184 | // API below. The control keys will only match WM_KEYDOWN events because of the 185 | // keydown bit I add, and STB_TEXTEDIT_KEYTOTEXT only tests for the KEYDOWN 186 | // bit so it only decodes WM_CHAR events. 187 | // 188 | // STB_TEXTEDIT_LAYOUTROW returns information about the shape of one displayed 189 | // row of characters assuming they start on the i'th character--the width and 190 | // the height and the number of characters consumed. This allows this library 191 | // to traverse the entire layout incrementally. You need to compute word-wrapping 192 | // here. 193 | // 194 | // Each textfield keeps its own insert mode state, which is not how normal 195 | // applications work. To keep an app-wide insert mode, update/copy the 196 | // "insert_mode" field of STB_TexteditState before/after calling API functions. 197 | // 198 | // API 199 | // 200 | // void stb_textedit_initialize_state(STB_TexteditState *state, int is_single_line) 201 | // 202 | // void stb_textedit_click(STB_TEXTEDIT_STRING *str, STB_TexteditState *state, float x, float y) 203 | // void stb_textedit_drag(STB_TEXTEDIT_STRING *str, STB_TexteditState *state, float x, float y) 204 | // int stb_textedit_cut(STB_TEXTEDIT_STRING *str, STB_TexteditState *state) 205 | // int stb_textedit_paste(STB_TEXTEDIT_STRING *str, STB_TexteditState *state, STB_TEXTEDIT_CHARTYPE *text, int len) 206 | // void stb_textedit_key(STB_TEXTEDIT_STRING *str, STB_TexteditState *state, int key) 207 | // 208 | // Each of these functions potentially updates the string and updates the 209 | // state. 210 | // 211 | // initialize_state: 212 | // set the textedit state to a known good default state when initially 213 | // constructing the textedit. 214 | // 215 | // click: 216 | // call this with the mouse x,y on a mouse down; it will update the cursor 217 | // and reset the selection start/end to the cursor point. the x,y must 218 | // be relative to the text widget, with (0,0) being the top left. 219 | // 220 | // drag: 221 | // call this with the mouse x,y on a mouse drag/up; it will update the 222 | // cursor and the selection end point 223 | // 224 | // cut: 225 | // call this to delete the current selection; returns true if there was 226 | // one. you should FIRST copy the current selection to the system paste buffer. 227 | // (To copy, just copy the current selection out of the string yourself.) 228 | // 229 | // paste: 230 | // call this to paste text at the current cursor point or over the current 231 | // selection if there is one. 232 | // 233 | // key: 234 | // call this for keyboard inputs sent to the textfield. you can use it 235 | // for "key down" events or for "translated" key events. if you need to 236 | // do both (as in Win32), or distinguish Unicode characters from control 237 | // inputs, set a high bit to distinguish the two; then you can define the 238 | // various definitions like STB_TEXTEDIT_K_LEFT have the is-key-event bit 239 | // set, and make STB_TEXTEDIT_KEYTOCHAR check that the is-key-event bit is 240 | // clear. 241 | // 242 | // When rendering, you can read the cursor position and selection state from 243 | // the STB_TexteditState. 244 | // 245 | // 246 | // Notes: 247 | // 248 | // This is designed to be usable in IMGUI, so it allows for the possibility of 249 | // running in an IMGUI that has NOT cached the multi-line layout. For this 250 | // reason, it provides an interface that is compatible with computing the 251 | // layout incrementally--we try to make sure we make as few passes through 252 | // as possible. (For example, to locate the mouse pointer in the text, we 253 | // could define functions that return the X and Y positions of characters 254 | // and binary search Y and then X, but if we're doing dynamic layout this 255 | // will run the layout algorithm many times, so instead we manually search 256 | // forward in one pass. Similar logic applies to e.g. up-arrow and 257 | // down-arrow movement.) 258 | // 259 | // If it's run in a widget that *has* cached the layout, then this is less 260 | // efficient, but it's not horrible on modern computers. But you wouldn't 261 | // want to edit million-line files with it. 262 | 263 | 264 | //////////////////////////////////////////////////////////////////////////// 265 | //////////////////////////////////////////////////////////////////////////// 266 | //// 267 | //// Header-file mode 268 | //// 269 | //// 270 | 271 | #ifndef INCLUDE_STB_TEXTEDIT_H 272 | #define INCLUDE_STB_TEXTEDIT_H 273 | 274 | //////////////////////////////////////////////////////////////////////// 275 | // 276 | // STB_TexteditState 277 | // 278 | // Definition of STB_TexteditState which you should store 279 | // per-textfield; it includes cursor position, selection state, 280 | // and undo state. 281 | // 282 | 283 | #ifndef STB_TEXTEDIT_UNDOSTATECOUNT 284 | #define STB_TEXTEDIT_UNDOSTATECOUNT 99 285 | #endif 286 | #ifndef STB_TEXTEDIT_UNDOCHARCOUNT 287 | #define STB_TEXTEDIT_UNDOCHARCOUNT 999 288 | #endif 289 | #ifndef STB_TEXTEDIT_CHARTYPE 290 | #define STB_TEXTEDIT_CHARTYPE int 291 | #endif 292 | #ifndef STB_TEXTEDIT_POSITIONTYPE 293 | #define STB_TEXTEDIT_POSITIONTYPE int 294 | #endif 295 | 296 | typedef struct 297 | { 298 | // private data 299 | STB_TEXTEDIT_POSITIONTYPE where; 300 | short insert_length; 301 | short delete_length; 302 | short char_storage; 303 | } StbUndoRecord; 304 | 305 | typedef struct 306 | { 307 | // private data 308 | StbUndoRecord undo_rec [STB_TEXTEDIT_UNDOSTATECOUNT]; 309 | STB_TEXTEDIT_CHARTYPE undo_char[STB_TEXTEDIT_UNDOCHARCOUNT]; 310 | short undo_point, redo_point; 311 | short undo_char_point, redo_char_point; 312 | } StbUndoState; 313 | 314 | typedef struct 315 | { 316 | ///////////////////// 317 | // 318 | // public data 319 | // 320 | 321 | int cursor; 322 | // position of the text cursor within the string 323 | 324 | int select_start; // selection start point 325 | int select_end; 326 | // selection start and end point in characters; if equal, no selection. 327 | // note that start may be less than or greater than end (e.g. when 328 | // dragging the mouse, start is where the initial click was, and you 329 | // can drag in either direction) 330 | 331 | unsigned char insert_mode; 332 | // each textfield keeps its own insert mode state. to keep an app-wide 333 | // insert mode, copy this value in/out of the app state 334 | 335 | ///////////////////// 336 | // 337 | // private data 338 | // 339 | unsigned char cursor_at_end_of_line; // not implemented yet 340 | unsigned char initialized; 341 | unsigned char has_preferred_x; 342 | unsigned char single_line; 343 | unsigned char padding1, padding2, padding3; 344 | float preferred_x; // this determines where the cursor up/down tries to seek to along x 345 | StbUndoState undostate; 346 | } STB_TexteditState; 347 | 348 | 349 | //////////////////////////////////////////////////////////////////////// 350 | // 351 | // StbTexteditRow 352 | // 353 | // Result of layout query, used by stb_textedit to determine where 354 | // the text in each row is. 355 | 356 | // result of layout query 357 | typedef struct 358 | { 359 | float x0,x1; // starting x location, end x location (allows for align=right, etc) 360 | float baseline_y_delta; // position of baseline relative to previous row's baseline 361 | float ymin,ymax; // height of row above and below baseline 362 | int num_chars; 363 | } StbTexteditRow; 364 | #endif //INCLUDE_STB_TEXTEDIT_H 365 | 366 | 367 | //////////////////////////////////////////////////////////////////////////// 368 | //////////////////////////////////////////////////////////////////////////// 369 | //// 370 | //// Implementation mode 371 | //// 372 | //// 373 | 374 | 375 | // implementation isn't include-guarded, since it might have indirectly 376 | // included just the "header" portion 377 | #ifdef STB_TEXTEDIT_IMPLEMENTATION 378 | 379 | #ifndef STB_TEXTEDIT_memmove 380 | #include 381 | #define STB_TEXTEDIT_memmove memmove 382 | #endif 383 | 384 | 385 | ///////////////////////////////////////////////////////////////////////////// 386 | // 387 | // Mouse input handling 388 | // 389 | 390 | // traverse the layout to locate the nearest character to a display position 391 | static int stb_text_locate_coord(STB_TEXTEDIT_STRING *str, float x, float y) 392 | { 393 | StbTexteditRow r; 394 | int n = STB_TEXTEDIT_STRINGLEN(str); 395 | float base_y = 0, prev_x; 396 | int i=0, k; 397 | 398 | r.x0 = r.x1 = 0; 399 | r.ymin = r.ymax = 0; 400 | r.num_chars = 0; 401 | 402 | // search rows to find one that straddles 'y' 403 | while (i < n) { 404 | STB_TEXTEDIT_LAYOUTROW(&r, str, i); 405 | if (r.num_chars <= 0) 406 | return n; 407 | 408 | if (i==0 && y < base_y + r.ymin) 409 | return 0; 410 | 411 | if (y < base_y + r.ymax) 412 | break; 413 | 414 | i += r.num_chars; 415 | base_y += r.baseline_y_delta; 416 | } 417 | 418 | // below all text, return 'after' last character 419 | if (i >= n) 420 | return n; 421 | 422 | // check if it's before the beginning of the line 423 | if (x < r.x0) 424 | return i; 425 | 426 | // check if it's before the end of the line 427 | if (x < r.x1) { 428 | // search characters in row for one that straddles 'x' 429 | prev_x = r.x0; 430 | for (k=0; k < r.num_chars; ++k) { 431 | float w = STB_TEXTEDIT_GETWIDTH(str, i, k); 432 | if (x < prev_x+w) { 433 | if (x < prev_x+w/2) 434 | return k+i; 435 | else 436 | return k+i+1; 437 | } 438 | prev_x += w; 439 | } 440 | // shouldn't happen, but if it does, fall through to end-of-line case 441 | } 442 | 443 | // if the last character is a newline, return that. otherwise return 'after' the last character 444 | if (STB_TEXTEDIT_GETCHAR(str, i+r.num_chars-1) == STB_TEXTEDIT_NEWLINE) 445 | return i+r.num_chars-1; 446 | else 447 | return i+r.num_chars; 448 | } 449 | 450 | // API click: on mouse down, move the cursor to the clicked location, and reset the selection 451 | static void stb_textedit_click(STB_TEXTEDIT_STRING *str, STB_TexteditState *state, float x, float y) 452 | { 453 | state->cursor = stb_text_locate_coord(str, x, y); 454 | state->select_start = state->cursor; 455 | state->select_end = state->cursor; 456 | state->has_preferred_x = 0; 457 | } 458 | 459 | // API drag: on mouse drag, move the cursor and selection endpoint to the clicked location 460 | static void stb_textedit_drag(STB_TEXTEDIT_STRING *str, STB_TexteditState *state, float x, float y) 461 | { 462 | int p = stb_text_locate_coord(str, x, y); 463 | if (state->select_start == state->select_end) 464 | state->select_start = state->cursor; 465 | state->cursor = state->select_end = p; 466 | } 467 | 468 | ///////////////////////////////////////////////////////////////////////////// 469 | // 470 | // Keyboard input handling 471 | // 472 | 473 | // forward declarations 474 | static void stb_text_undo(STB_TEXTEDIT_STRING *str, STB_TexteditState *state); 475 | static void stb_text_redo(STB_TEXTEDIT_STRING *str, STB_TexteditState *state); 476 | static void stb_text_makeundo_delete(STB_TEXTEDIT_STRING *str, STB_TexteditState *state, int where, int length); 477 | static void stb_text_makeundo_insert(STB_TexteditState *state, int where, int length); 478 | static void stb_text_makeundo_replace(STB_TEXTEDIT_STRING *str, STB_TexteditState *state, int where, int old_length, int new_length); 479 | 480 | typedef struct 481 | { 482 | float x,y; // position of n'th character 483 | float height; // height of line 484 | int first_char, length; // first char of row, and length 485 | int prev_first; // first char of previous row 486 | } StbFindState; 487 | 488 | // find the x/y location of a character, and remember info about the previous row in 489 | // case we get a move-up event (for page up, we'll have to rescan) 490 | static void stb_textedit_find_charpos(StbFindState *find, STB_TEXTEDIT_STRING *str, int n, int single_line) 491 | { 492 | StbTexteditRow r; 493 | int prev_start = 0; 494 | int z = STB_TEXTEDIT_STRINGLEN(str); 495 | int i=0, first; 496 | 497 | if (n == z) { 498 | // if it's at the end, then find the last line -- simpler than trying to 499 | // explicitly handle this case in the regular code 500 | if (single_line) { 501 | STB_TEXTEDIT_LAYOUTROW(&r, str, 0); 502 | find->y = 0; 503 | find->first_char = 0; 504 | find->length = z; 505 | find->height = r.ymax - r.ymin; 506 | find->x = r.x1; 507 | } else { 508 | find->y = 0; 509 | find->x = 0; 510 | find->height = 1; 511 | while (i < z) { 512 | STB_TEXTEDIT_LAYOUTROW(&r, str, i); 513 | prev_start = i; 514 | i += r.num_chars; 515 | } 516 | find->first_char = i; 517 | find->length = 0; 518 | find->prev_first = prev_start; 519 | } 520 | return; 521 | } 522 | 523 | // search rows to find the one that straddles character n 524 | find->y = 0; 525 | 526 | for(;;) { 527 | STB_TEXTEDIT_LAYOUTROW(&r, str, i); 528 | if (n < i + r.num_chars) 529 | break; 530 | prev_start = i; 531 | i += r.num_chars; 532 | find->y += r.baseline_y_delta; 533 | } 534 | 535 | find->first_char = first = i; 536 | find->length = r.num_chars; 537 | find->height = r.ymax - r.ymin; 538 | find->prev_first = prev_start; 539 | 540 | // now scan to find xpos 541 | find->x = r.x0; 542 | i = 0; 543 | for (i=0; first+i < n; ++i) 544 | find->x += STB_TEXTEDIT_GETWIDTH(str, first, i); 545 | } 546 | 547 | #define STB_TEXT_HAS_SELECTION(s) ((s)->select_start != (s)->select_end) 548 | 549 | // make the selection/cursor state valid if client altered the string 550 | static void stb_textedit_clamp(STB_TEXTEDIT_STRING *str, STB_TexteditState *state) 551 | { 552 | int n = STB_TEXTEDIT_STRINGLEN(str); 553 | if (STB_TEXT_HAS_SELECTION(state)) { 554 | if (state->select_start > n) state->select_start = n; 555 | if (state->select_end > n) state->select_end = n; 556 | // if clamping forced them to be equal, move the cursor to match 557 | if (state->select_start == state->select_end) 558 | state->cursor = state->select_start; 559 | } 560 | if (state->cursor > n) state->cursor = n; 561 | } 562 | 563 | // delete characters while updating undo 564 | static void stb_textedit_delete(STB_TEXTEDIT_STRING *str, STB_TexteditState *state, int where, int len) 565 | { 566 | stb_text_makeundo_delete(str, state, where, len); 567 | STB_TEXTEDIT_DELETECHARS(str, where, len); 568 | state->has_preferred_x = 0; 569 | } 570 | 571 | // delete the section 572 | static void stb_textedit_delete_selection(STB_TEXTEDIT_STRING *str, STB_TexteditState *state) 573 | { 574 | stb_textedit_clamp(str, state); 575 | if (STB_TEXT_HAS_SELECTION(state)) { 576 | if (state->select_start < state->select_end) { 577 | stb_textedit_delete(str, state, state->select_start, state->select_end - state->select_start); 578 | state->select_end = state->cursor = state->select_start; 579 | } else { 580 | stb_textedit_delete(str, state, state->select_end, state->select_start - state->select_end); 581 | state->select_start = state->cursor = state->select_end; 582 | } 583 | state->has_preferred_x = 0; 584 | } 585 | } 586 | 587 | // canoncialize the selection so start <= end 588 | static void stb_textedit_sortselection(STB_TexteditState *state) 589 | { 590 | if (state->select_end < state->select_start) { 591 | int temp = state->select_end; 592 | state->select_end = state->select_start; 593 | state->select_start = temp; 594 | } 595 | } 596 | 597 | // move cursor to first character of selection 598 | static void stb_textedit_move_to_first(STB_TexteditState *state) 599 | { 600 | if (STB_TEXT_HAS_SELECTION(state)) { 601 | stb_textedit_sortselection(state); 602 | state->cursor = state->select_start; 603 | state->select_end = state->select_start; 604 | state->has_preferred_x = 0; 605 | } 606 | } 607 | 608 | // move cursor to last character of selection 609 | static void stb_textedit_move_to_last(STB_TEXTEDIT_STRING *str, STB_TexteditState *state) 610 | { 611 | if (STB_TEXT_HAS_SELECTION(state)) { 612 | stb_textedit_sortselection(state); 613 | stb_textedit_clamp(str, state); 614 | state->cursor = state->select_end; 615 | state->select_start = state->select_end; 616 | state->has_preferred_x = 0; 617 | } 618 | } 619 | 620 | #ifdef STB_TEXTEDIT_IS_SPACE 621 | static int is_word_boundary( STB_TEXTEDIT_STRING *str, int idx ) 622 | { 623 | return idx > 0 ? (STB_TEXTEDIT_IS_SPACE( STB_TEXTEDIT_GETCHAR(str,idx-1) ) && !STB_TEXTEDIT_IS_SPACE( STB_TEXTEDIT_GETCHAR(str, idx) ) ) : 1; 624 | } 625 | 626 | #ifndef STB_TEXTEDIT_MOVEWORDLEFT 627 | static int stb_textedit_move_to_word_previous( STB_TEXTEDIT_STRING *str, int c ) 628 | { 629 | --c; // always move at least one character 630 | while( c >= 0 && !is_word_boundary( str, c ) ) 631 | --c; 632 | 633 | if( c < 0 ) 634 | c = 0; 635 | 636 | return c; 637 | } 638 | #define STB_TEXTEDIT_MOVEWORDLEFT stb_textedit_move_to_word_previous 639 | #endif 640 | 641 | #ifndef STB_TEXTEDIT_MOVEWORDRIGHT 642 | static int stb_textedit_move_to_word_next( STB_TEXTEDIT_STRING *str, int c ) 643 | { 644 | const int len = STB_TEXTEDIT_STRINGLEN(str); 645 | ++c; // always move at least one character 646 | while( c < len && !is_word_boundary( str, c ) ) 647 | ++c; 648 | 649 | if( c > len ) 650 | c = len; 651 | 652 | return c; 653 | } 654 | #define STB_TEXTEDIT_MOVEWORDRIGHT stb_textedit_move_to_word_next 655 | #endif 656 | 657 | #endif 658 | 659 | // update selection and cursor to match each other 660 | static void stb_textedit_prep_selection_at_cursor(STB_TexteditState *state) 661 | { 662 | if (!STB_TEXT_HAS_SELECTION(state)) 663 | state->select_start = state->select_end = state->cursor; 664 | else 665 | state->cursor = state->select_end; 666 | } 667 | 668 | // API cut: delete selection 669 | static int stb_textedit_cut(STB_TEXTEDIT_STRING *str, STB_TexteditState *state) 670 | { 671 | if (STB_TEXT_HAS_SELECTION(state)) { 672 | stb_textedit_delete_selection(str,state); // implicity clamps 673 | state->has_preferred_x = 0; 674 | return 1; 675 | } 676 | return 0; 677 | } 678 | 679 | // API paste: replace existing selection with passed-in text 680 | static int stb_textedit_paste(STB_TEXTEDIT_STRING *str, STB_TexteditState *state, STB_TEXTEDIT_CHARTYPE const *ctext, int len) 681 | { 682 | STB_TEXTEDIT_CHARTYPE *text = (STB_TEXTEDIT_CHARTYPE *) ctext; 683 | // if there's a selection, the paste should delete it 684 | stb_textedit_clamp(str, state); 685 | stb_textedit_delete_selection(str,state); 686 | // try to insert the characters 687 | if (STB_TEXTEDIT_INSERTCHARS(str, state->cursor, text, len)) { 688 | stb_text_makeundo_insert(state, state->cursor, len); 689 | state->cursor += len; 690 | state->has_preferred_x = 0; 691 | return 1; 692 | } 693 | // remove the undo since we didn't actually insert the characters 694 | if (state->undostate.undo_point) 695 | --state->undostate.undo_point; 696 | return 0; 697 | } 698 | 699 | // API key: process a keyboard input 700 | static void stb_textedit_key(STB_TEXTEDIT_STRING *str, STB_TexteditState *state, int key) 701 | { 702 | retry: 703 | switch (key) { 704 | default: { 705 | int c = STB_TEXTEDIT_KEYTOTEXT(key); 706 | if (c > 0) { 707 | STB_TEXTEDIT_CHARTYPE ch = (STB_TEXTEDIT_CHARTYPE) c; 708 | 709 | // can't add newline in single-line mode 710 | if (c == '\n' && state->single_line) 711 | break; 712 | 713 | if (state->insert_mode && !STB_TEXT_HAS_SELECTION(state) && state->cursor < STB_TEXTEDIT_STRINGLEN(str)) { 714 | stb_text_makeundo_replace(str, state, state->cursor, 1, 1); 715 | STB_TEXTEDIT_DELETECHARS(str, state->cursor, 1); 716 | if (STB_TEXTEDIT_INSERTCHARS(str, state->cursor, &ch, 1)) { 717 | ++state->cursor; 718 | state->has_preferred_x = 0; 719 | } 720 | } else { 721 | stb_textedit_delete_selection(str,state); // implicity clamps 722 | if (STB_TEXTEDIT_INSERTCHARS(str, state->cursor, &ch, 1)) { 723 | stb_text_makeundo_insert(state, state->cursor, 1); 724 | ++state->cursor; 725 | state->has_preferred_x = 0; 726 | } 727 | } 728 | } 729 | break; 730 | } 731 | 732 | #ifdef STB_TEXTEDIT_K_INSERT 733 | case STB_TEXTEDIT_K_INSERT: 734 | state->insert_mode = !state->insert_mode; 735 | break; 736 | #endif 737 | 738 | case STB_TEXTEDIT_K_UNDO: 739 | stb_text_undo(str, state); 740 | state->has_preferred_x = 0; 741 | break; 742 | 743 | case STB_TEXTEDIT_K_REDO: 744 | stb_text_redo(str, state); 745 | state->has_preferred_x = 0; 746 | break; 747 | 748 | case STB_TEXTEDIT_K_LEFT: 749 | // if currently there's a selection, move cursor to start of selection 750 | if (STB_TEXT_HAS_SELECTION(state)) 751 | stb_textedit_move_to_first(state); 752 | else 753 | if (state->cursor > 0) 754 | --state->cursor; 755 | state->has_preferred_x = 0; 756 | break; 757 | 758 | case STB_TEXTEDIT_K_RIGHT: 759 | // if currently there's a selection, move cursor to end of selection 760 | if (STB_TEXT_HAS_SELECTION(state)) 761 | stb_textedit_move_to_last(str, state); 762 | else 763 | ++state->cursor; 764 | stb_textedit_clamp(str, state); 765 | state->has_preferred_x = 0; 766 | break; 767 | 768 | case STB_TEXTEDIT_K_LEFT | STB_TEXTEDIT_K_SHIFT: 769 | stb_textedit_clamp(str, state); 770 | stb_textedit_prep_selection_at_cursor(state); 771 | // move selection left 772 | if (state->select_end > 0) 773 | --state->select_end; 774 | state->cursor = state->select_end; 775 | state->has_preferred_x = 0; 776 | break; 777 | 778 | #ifdef STB_TEXTEDIT_MOVEWORDLEFT 779 | case STB_TEXTEDIT_K_WORDLEFT: 780 | if (STB_TEXT_HAS_SELECTION(state)) 781 | stb_textedit_move_to_first(state); 782 | else { 783 | state->cursor = STB_TEXTEDIT_MOVEWORDLEFT(str, state->cursor); 784 | stb_textedit_clamp( str, state ); 785 | } 786 | break; 787 | 788 | case STB_TEXTEDIT_K_WORDLEFT | STB_TEXTEDIT_K_SHIFT: 789 | if( !STB_TEXT_HAS_SELECTION( state ) ) 790 | stb_textedit_prep_selection_at_cursor(state); 791 | 792 | state->cursor = STB_TEXTEDIT_MOVEWORDLEFT(str, state->cursor); 793 | state->select_end = state->cursor; 794 | 795 | stb_textedit_clamp( str, state ); 796 | break; 797 | #endif 798 | 799 | #ifdef STB_TEXTEDIT_MOVEWORDRIGHT 800 | case STB_TEXTEDIT_K_WORDRIGHT: 801 | if (STB_TEXT_HAS_SELECTION(state)) 802 | stb_textedit_move_to_last(str, state); 803 | else { 804 | state->cursor = STB_TEXTEDIT_MOVEWORDRIGHT(str, state->cursor); 805 | stb_textedit_clamp( str, state ); 806 | } 807 | break; 808 | 809 | case STB_TEXTEDIT_K_WORDRIGHT | STB_TEXTEDIT_K_SHIFT: 810 | if( !STB_TEXT_HAS_SELECTION( state ) ) 811 | stb_textedit_prep_selection_at_cursor(state); 812 | 813 | state->cursor = STB_TEXTEDIT_MOVEWORDRIGHT(str, state->cursor); 814 | state->select_end = state->cursor; 815 | 816 | stb_textedit_clamp( str, state ); 817 | break; 818 | #endif 819 | 820 | case STB_TEXTEDIT_K_RIGHT | STB_TEXTEDIT_K_SHIFT: 821 | stb_textedit_prep_selection_at_cursor(state); 822 | // move selection right 823 | ++state->select_end; 824 | stb_textedit_clamp(str, state); 825 | state->cursor = state->select_end; 826 | state->has_preferred_x = 0; 827 | break; 828 | 829 | case STB_TEXTEDIT_K_DOWN: 830 | case STB_TEXTEDIT_K_DOWN | STB_TEXTEDIT_K_SHIFT: { 831 | StbFindState find; 832 | StbTexteditRow row; 833 | int i, sel = (key & STB_TEXTEDIT_K_SHIFT) != 0; 834 | 835 | if (state->single_line) { 836 | // on windows, up&down in single-line behave like left&right 837 | key = STB_TEXTEDIT_K_RIGHT | (key & STB_TEXTEDIT_K_SHIFT); 838 | goto retry; 839 | } 840 | 841 | if (sel) 842 | stb_textedit_prep_selection_at_cursor(state); 843 | else if (STB_TEXT_HAS_SELECTION(state)) 844 | stb_textedit_move_to_last(str,state); 845 | 846 | // compute current position of cursor point 847 | stb_textedit_clamp(str, state); 848 | stb_textedit_find_charpos(&find, str, state->cursor, state->single_line); 849 | 850 | // now find character position down a row 851 | if (find.length) { 852 | float goal_x = state->has_preferred_x ? state->preferred_x : find.x; 853 | float x; 854 | int start = find.first_char + find.length; 855 | state->cursor = start; 856 | STB_TEXTEDIT_LAYOUTROW(&row, str, state->cursor); 857 | x = row.x0; 858 | for (i=0; i < row.num_chars; ++i) { 859 | float dx = STB_TEXTEDIT_GETWIDTH(str, start, i); 860 | #ifdef STB_TEXTEDIT_GETWIDTH_NEWLINE 861 | if (dx == STB_TEXTEDIT_GETWIDTH_NEWLINE) 862 | break; 863 | #endif 864 | x += dx; 865 | if (x > goal_x) 866 | break; 867 | ++state->cursor; 868 | } 869 | stb_textedit_clamp(str, state); 870 | 871 | state->has_preferred_x = 1; 872 | state->preferred_x = goal_x; 873 | 874 | if (sel) 875 | state->select_end = state->cursor; 876 | } 877 | break; 878 | } 879 | 880 | case STB_TEXTEDIT_K_UP: 881 | case STB_TEXTEDIT_K_UP | STB_TEXTEDIT_K_SHIFT: { 882 | StbFindState find; 883 | StbTexteditRow row; 884 | int i, sel = (key & STB_TEXTEDIT_K_SHIFT) != 0; 885 | 886 | if (state->single_line) { 887 | // on windows, up&down become left&right 888 | key = STB_TEXTEDIT_K_LEFT | (key & STB_TEXTEDIT_K_SHIFT); 889 | goto retry; 890 | } 891 | 892 | if (sel) 893 | stb_textedit_prep_selection_at_cursor(state); 894 | else if (STB_TEXT_HAS_SELECTION(state)) 895 | stb_textedit_move_to_first(state); 896 | 897 | // compute current position of cursor point 898 | stb_textedit_clamp(str, state); 899 | stb_textedit_find_charpos(&find, str, state->cursor, state->single_line); 900 | 901 | // can only go up if there's a previous row 902 | if (find.prev_first != find.first_char) { 903 | // now find character position up a row 904 | float goal_x = state->has_preferred_x ? state->preferred_x : find.x; 905 | float x; 906 | state->cursor = find.prev_first; 907 | STB_TEXTEDIT_LAYOUTROW(&row, str, state->cursor); 908 | x = row.x0; 909 | for (i=0; i < row.num_chars; ++i) { 910 | float dx = STB_TEXTEDIT_GETWIDTH(str, find.prev_first, i); 911 | #ifdef STB_TEXTEDIT_GETWIDTH_NEWLINE 912 | if (dx == STB_TEXTEDIT_GETWIDTH_NEWLINE) 913 | break; 914 | #endif 915 | x += dx; 916 | if (x > goal_x) 917 | break; 918 | ++state->cursor; 919 | } 920 | stb_textedit_clamp(str, state); 921 | 922 | state->has_preferred_x = 1; 923 | state->preferred_x = goal_x; 924 | 925 | if (sel) 926 | state->select_end = state->cursor; 927 | } 928 | break; 929 | } 930 | 931 | case STB_TEXTEDIT_K_DELETE: 932 | case STB_TEXTEDIT_K_DELETE | STB_TEXTEDIT_K_SHIFT: 933 | if (STB_TEXT_HAS_SELECTION(state)) 934 | stb_textedit_delete_selection(str, state); 935 | else { 936 | int n = STB_TEXTEDIT_STRINGLEN(str); 937 | if (state->cursor < n) 938 | stb_textedit_delete(str, state, state->cursor, 1); 939 | } 940 | state->has_preferred_x = 0; 941 | break; 942 | 943 | case STB_TEXTEDIT_K_BACKSPACE: 944 | case STB_TEXTEDIT_K_BACKSPACE | STB_TEXTEDIT_K_SHIFT: 945 | if (STB_TEXT_HAS_SELECTION(state)) 946 | stb_textedit_delete_selection(str, state); 947 | else { 948 | stb_textedit_clamp(str, state); 949 | if (state->cursor > 0) { 950 | stb_textedit_delete(str, state, state->cursor-1, 1); 951 | --state->cursor; 952 | } 953 | } 954 | state->has_preferred_x = 0; 955 | break; 956 | 957 | #ifdef STB_TEXTEDIT_K_TEXTSTART2 958 | case STB_TEXTEDIT_K_TEXTSTART2: 959 | #endif 960 | case STB_TEXTEDIT_K_TEXTSTART: 961 | state->cursor = state->select_start = state->select_end = 0; 962 | state->has_preferred_x = 0; 963 | break; 964 | 965 | #ifdef STB_TEXTEDIT_K_TEXTEND2 966 | case STB_TEXTEDIT_K_TEXTEND2: 967 | #endif 968 | case STB_TEXTEDIT_K_TEXTEND: 969 | state->cursor = STB_TEXTEDIT_STRINGLEN(str); 970 | state->select_start = state->select_end = 0; 971 | state->has_preferred_x = 0; 972 | break; 973 | 974 | #ifdef STB_TEXTEDIT_K_TEXTSTART2 975 | case STB_TEXTEDIT_K_TEXTSTART2 | STB_TEXTEDIT_K_SHIFT: 976 | #endif 977 | case STB_TEXTEDIT_K_TEXTSTART | STB_TEXTEDIT_K_SHIFT: 978 | stb_textedit_prep_selection_at_cursor(state); 979 | state->cursor = state->select_end = 0; 980 | state->has_preferred_x = 0; 981 | break; 982 | 983 | #ifdef STB_TEXTEDIT_K_TEXTEND2 984 | case STB_TEXTEDIT_K_TEXTEND2 | STB_TEXTEDIT_K_SHIFT: 985 | #endif 986 | case STB_TEXTEDIT_K_TEXTEND | STB_TEXTEDIT_K_SHIFT: 987 | stb_textedit_prep_selection_at_cursor(state); 988 | state->cursor = state->select_end = STB_TEXTEDIT_STRINGLEN(str); 989 | state->has_preferred_x = 0; 990 | break; 991 | 992 | 993 | #ifdef STB_TEXTEDIT_K_LINESTART2 994 | case STB_TEXTEDIT_K_LINESTART2: 995 | #endif 996 | case STB_TEXTEDIT_K_LINESTART: 997 | stb_textedit_clamp(str, state); 998 | stb_textedit_move_to_first(state); 999 | if (state->single_line) 1000 | state->cursor = 0; 1001 | else while (state->cursor > 0 && STB_TEXTEDIT_GETCHAR(str, state->cursor-1) != STB_TEXTEDIT_NEWLINE) 1002 | --state->cursor; 1003 | state->has_preferred_x = 0; 1004 | break; 1005 | 1006 | #ifdef STB_TEXTEDIT_K_LINEEND2 1007 | case STB_TEXTEDIT_K_LINEEND2: 1008 | #endif 1009 | case STB_TEXTEDIT_K_LINEEND: { 1010 | int n = STB_TEXTEDIT_STRINGLEN(str); 1011 | stb_textedit_clamp(str, state); 1012 | stb_textedit_move_to_first(state); 1013 | if (state->single_line) 1014 | state->cursor = n; 1015 | else while (state->cursor < n && STB_TEXTEDIT_GETCHAR(str, state->cursor) != STB_TEXTEDIT_NEWLINE) 1016 | ++state->cursor; 1017 | state->has_preferred_x = 0; 1018 | break; 1019 | } 1020 | 1021 | #ifdef STB_TEXTEDIT_K_LINESTART2 1022 | case STB_TEXTEDIT_K_LINESTART2 | STB_TEXTEDIT_K_SHIFT: 1023 | #endif 1024 | case STB_TEXTEDIT_K_LINESTART | STB_TEXTEDIT_K_SHIFT: 1025 | stb_textedit_clamp(str, state); 1026 | stb_textedit_prep_selection_at_cursor(state); 1027 | if (state->single_line) 1028 | state->cursor = 0; 1029 | else while (state->cursor > 0 && STB_TEXTEDIT_GETCHAR(str, state->cursor-1) != STB_TEXTEDIT_NEWLINE) 1030 | --state->cursor; 1031 | state->select_end = state->cursor; 1032 | state->has_preferred_x = 0; 1033 | break; 1034 | 1035 | #ifdef STB_TEXTEDIT_K_LINEEND2 1036 | case STB_TEXTEDIT_K_LINEEND2 | STB_TEXTEDIT_K_SHIFT: 1037 | #endif 1038 | case STB_TEXTEDIT_K_LINEEND | STB_TEXTEDIT_K_SHIFT: { 1039 | int n = STB_TEXTEDIT_STRINGLEN(str); 1040 | stb_textedit_clamp(str, state); 1041 | stb_textedit_prep_selection_at_cursor(state); 1042 | if (state->single_line) 1043 | state->cursor = n; 1044 | else while (state->cursor < n && STB_TEXTEDIT_GETCHAR(str, state->cursor) != STB_TEXTEDIT_NEWLINE) 1045 | ++state->cursor; 1046 | state->select_end = state->cursor; 1047 | state->has_preferred_x = 0; 1048 | break; 1049 | } 1050 | 1051 | // @TODO: 1052 | // STB_TEXTEDIT_K_PGUP - move cursor up a page 1053 | // STB_TEXTEDIT_K_PGDOWN - move cursor down a page 1054 | } 1055 | } 1056 | 1057 | ///////////////////////////////////////////////////////////////////////////// 1058 | // 1059 | // Undo processing 1060 | // 1061 | // @OPTIMIZE: the undo/redo buffer should be circular 1062 | 1063 | static void stb_textedit_flush_redo(StbUndoState *state) 1064 | { 1065 | state->redo_point = STB_TEXTEDIT_UNDOSTATECOUNT; 1066 | state->redo_char_point = STB_TEXTEDIT_UNDOCHARCOUNT; 1067 | } 1068 | 1069 | // discard the oldest entry in the undo list 1070 | static void stb_textedit_discard_undo(StbUndoState *state) 1071 | { 1072 | if (state->undo_point > 0) { 1073 | // if the 0th undo state has characters, clean those up 1074 | if (state->undo_rec[0].char_storage >= 0) { 1075 | int n = state->undo_rec[0].insert_length, i; 1076 | // delete n characters from all other records 1077 | state->undo_char_point = state->undo_char_point - (short) n; // vsnet05 1078 | STB_TEXTEDIT_memmove(state->undo_char, state->undo_char + n, (size_t) ((size_t)state->undo_char_point*sizeof(STB_TEXTEDIT_CHARTYPE))); 1079 | for (i=0; i < state->undo_point; ++i) 1080 | if (state->undo_rec[i].char_storage >= 0) 1081 | state->undo_rec[i].char_storage = state->undo_rec[i].char_storage - (short) n; // vsnet05 // @OPTIMIZE: get rid of char_storage and infer it 1082 | } 1083 | --state->undo_point; 1084 | STB_TEXTEDIT_memmove(state->undo_rec, state->undo_rec+1, (size_t) ((size_t)state->undo_point*sizeof(state->undo_rec[0]))); 1085 | } 1086 | } 1087 | 1088 | // discard the oldest entry in the redo list--it's bad if this 1089 | // ever happens, but because undo & redo have to store the actual 1090 | // characters in different cases, the redo character buffer can 1091 | // fill up even though the undo buffer didn't 1092 | static void stb_textedit_discard_redo(StbUndoState *state) 1093 | { 1094 | int k = STB_TEXTEDIT_UNDOSTATECOUNT-1; 1095 | 1096 | if (state->redo_point <= k) { 1097 | // if the k'th undo state has characters, clean those up 1098 | if (state->undo_rec[k].char_storage >= 0) { 1099 | int n = state->undo_rec[k].insert_length, i; 1100 | // delete n characters from all other records 1101 | state->redo_char_point = state->redo_char_point + (short) n; // vsnet05 1102 | STB_TEXTEDIT_memmove(state->undo_char + state->redo_char_point, state->undo_char + state->redo_char_point-n, (size_t) ((size_t)(STB_TEXTEDIT_UNDOCHARCOUNT - state->redo_char_point)*sizeof(STB_TEXTEDIT_CHARTYPE))); 1103 | for (i=state->redo_point; i < k; ++i) 1104 | if (state->undo_rec[i].char_storage >= 0) 1105 | state->undo_rec[i].char_storage = state->undo_rec[i].char_storage + (short) n; // vsnet05 1106 | } 1107 | STB_TEXTEDIT_memmove(state->undo_rec + state->redo_point, state->undo_rec + state->redo_point-1, (size_t) ((size_t)(STB_TEXTEDIT_UNDOSTATECOUNT - state->redo_point)*sizeof(state->undo_rec[0]))); 1108 | ++state->redo_point; 1109 | } 1110 | } 1111 | 1112 | static StbUndoRecord *stb_text_create_undo_record(StbUndoState *state, int numchars) 1113 | { 1114 | // any time we create a new undo record, we discard redo 1115 | stb_textedit_flush_redo(state); 1116 | 1117 | // if we have no free records, we have to make room, by sliding the 1118 | // existing records down 1119 | if (state->undo_point == STB_TEXTEDIT_UNDOSTATECOUNT) 1120 | stb_textedit_discard_undo(state); 1121 | 1122 | // if the characters to store won't possibly fit in the buffer, we can't undo 1123 | if (numchars > STB_TEXTEDIT_UNDOCHARCOUNT) { 1124 | state->undo_point = 0; 1125 | state->undo_char_point = 0; 1126 | return NULL; 1127 | } 1128 | 1129 | // if we don't have enough free characters in the buffer, we have to make room 1130 | while (state->undo_char_point + numchars > STB_TEXTEDIT_UNDOCHARCOUNT) 1131 | stb_textedit_discard_undo(state); 1132 | 1133 | return &state->undo_rec[state->undo_point++]; 1134 | } 1135 | 1136 | static STB_TEXTEDIT_CHARTYPE *stb_text_createundo(StbUndoState *state, int pos, int insert_len, int delete_len) 1137 | { 1138 | StbUndoRecord *r = stb_text_create_undo_record(state, insert_len); 1139 | if (r == NULL) 1140 | return NULL; 1141 | 1142 | r->where = pos; 1143 | r->insert_length = (short) insert_len; 1144 | r->delete_length = (short) delete_len; 1145 | 1146 | if (insert_len == 0) { 1147 | r->char_storage = -1; 1148 | return NULL; 1149 | } else { 1150 | r->char_storage = state->undo_char_point; 1151 | state->undo_char_point = state->undo_char_point + (short) insert_len; 1152 | return &state->undo_char[r->char_storage]; 1153 | } 1154 | } 1155 | 1156 | static void stb_text_undo(STB_TEXTEDIT_STRING *str, STB_TexteditState *state) 1157 | { 1158 | StbUndoState *s = &state->undostate; 1159 | StbUndoRecord u, *r; 1160 | if (s->undo_point == 0) 1161 | return; 1162 | 1163 | // we need to do two things: apply the undo record, and create a redo record 1164 | u = s->undo_rec[s->undo_point-1]; 1165 | r = &s->undo_rec[s->redo_point-1]; 1166 | r->char_storage = -1; 1167 | 1168 | r->insert_length = u.delete_length; 1169 | r->delete_length = u.insert_length; 1170 | r->where = u.where; 1171 | 1172 | if (u.delete_length) { 1173 | // if the undo record says to delete characters, then the redo record will 1174 | // need to re-insert the characters that get deleted, so we need to store 1175 | // them. 1176 | 1177 | // there are three cases: 1178 | // there's enough room to store the characters 1179 | // characters stored for *redoing* don't leave room for redo 1180 | // characters stored for *undoing* don't leave room for redo 1181 | // if the last is true, we have to bail 1182 | 1183 | if (s->undo_char_point + u.delete_length >= STB_TEXTEDIT_UNDOCHARCOUNT) { 1184 | // the undo records take up too much character space; there's no space to store the redo characters 1185 | r->insert_length = 0; 1186 | } else { 1187 | int i; 1188 | 1189 | // there's definitely room to store the characters eventually 1190 | while (s->undo_char_point + u.delete_length > s->redo_char_point) { 1191 | // there's currently not enough room, so discard a redo record 1192 | stb_textedit_discard_redo(s); 1193 | // should never happen: 1194 | if (s->redo_point == STB_TEXTEDIT_UNDOSTATECOUNT) 1195 | return; 1196 | } 1197 | r = &s->undo_rec[s->redo_point-1]; 1198 | 1199 | r->char_storage = s->redo_char_point - u.delete_length; 1200 | s->redo_char_point = s->redo_char_point - (short) u.delete_length; 1201 | 1202 | // now save the characters 1203 | for (i=0; i < u.delete_length; ++i) 1204 | s->undo_char[r->char_storage + i] = STB_TEXTEDIT_GETCHAR(str, u.where + i); 1205 | } 1206 | 1207 | // now we can carry out the deletion 1208 | STB_TEXTEDIT_DELETECHARS(str, u.where, u.delete_length); 1209 | } 1210 | 1211 | // check type of recorded action: 1212 | if (u.insert_length) { 1213 | // easy case: was a deletion, so we need to insert n characters 1214 | STB_TEXTEDIT_INSERTCHARS(str, u.where, &s->undo_char[u.char_storage], u.insert_length); 1215 | s->undo_char_point -= u.insert_length; 1216 | } 1217 | 1218 | state->cursor = u.where + u.insert_length; 1219 | 1220 | s->undo_point--; 1221 | s->redo_point--; 1222 | } 1223 | 1224 | static void stb_text_redo(STB_TEXTEDIT_STRING *str, STB_TexteditState *state) 1225 | { 1226 | StbUndoState *s = &state->undostate; 1227 | StbUndoRecord *u, r; 1228 | if (s->redo_point == STB_TEXTEDIT_UNDOSTATECOUNT) 1229 | return; 1230 | 1231 | // we need to do two things: apply the redo record, and create an undo record 1232 | u = &s->undo_rec[s->undo_point]; 1233 | r = s->undo_rec[s->redo_point]; 1234 | 1235 | // we KNOW there must be room for the undo record, because the redo record 1236 | // was derived from an undo record 1237 | 1238 | u->delete_length = r.insert_length; 1239 | u->insert_length = r.delete_length; 1240 | u->where = r.where; 1241 | u->char_storage = -1; 1242 | 1243 | if (r.delete_length) { 1244 | // the redo record requires us to delete characters, so the undo record 1245 | // needs to store the characters 1246 | 1247 | if (s->undo_char_point + u->insert_length > s->redo_char_point) { 1248 | u->insert_length = 0; 1249 | u->delete_length = 0; 1250 | } else { 1251 | int i; 1252 | u->char_storage = s->undo_char_point; 1253 | s->undo_char_point = s->undo_char_point + u->insert_length; 1254 | 1255 | // now save the characters 1256 | for (i=0; i < u->insert_length; ++i) 1257 | s->undo_char[u->char_storage + i] = STB_TEXTEDIT_GETCHAR(str, u->where + i); 1258 | } 1259 | 1260 | STB_TEXTEDIT_DELETECHARS(str, r.where, r.delete_length); 1261 | } 1262 | 1263 | if (r.insert_length) { 1264 | // easy case: need to insert n characters 1265 | STB_TEXTEDIT_INSERTCHARS(str, r.where, &s->undo_char[r.char_storage], r.insert_length); 1266 | s->redo_char_point += r.insert_length; 1267 | } 1268 | 1269 | state->cursor = r.where + r.insert_length; 1270 | 1271 | s->undo_point++; 1272 | s->redo_point++; 1273 | } 1274 | 1275 | static void stb_text_makeundo_insert(STB_TexteditState *state, int where, int length) 1276 | { 1277 | stb_text_createundo(&state->undostate, where, 0, length); 1278 | } 1279 | 1280 | static void stb_text_makeundo_delete(STB_TEXTEDIT_STRING *str, STB_TexteditState *state, int where, int length) 1281 | { 1282 | int i; 1283 | STB_TEXTEDIT_CHARTYPE *p = stb_text_createundo(&state->undostate, where, length, 0); 1284 | if (p) { 1285 | for (i=0; i < length; ++i) 1286 | p[i] = STB_TEXTEDIT_GETCHAR(str, where+i); 1287 | } 1288 | } 1289 | 1290 | static void stb_text_makeundo_replace(STB_TEXTEDIT_STRING *str, STB_TexteditState *state, int where, int old_length, int new_length) 1291 | { 1292 | int i; 1293 | STB_TEXTEDIT_CHARTYPE *p = stb_text_createundo(&state->undostate, where, old_length, new_length); 1294 | if (p) { 1295 | for (i=0; i < old_length; ++i) 1296 | p[i] = STB_TEXTEDIT_GETCHAR(str, where+i); 1297 | } 1298 | } 1299 | 1300 | // reset the state to default 1301 | static void stb_textedit_clear_state(STB_TexteditState *state, int is_single_line) 1302 | { 1303 | state->undostate.undo_point = 0; 1304 | state->undostate.undo_char_point = 0; 1305 | state->undostate.redo_point = STB_TEXTEDIT_UNDOSTATECOUNT; 1306 | state->undostate.redo_char_point = STB_TEXTEDIT_UNDOCHARCOUNT; 1307 | state->select_end = state->select_start = 0; 1308 | state->cursor = 0; 1309 | state->has_preferred_x = 0; 1310 | state->preferred_x = 0; 1311 | state->cursor_at_end_of_line = 0; 1312 | state->initialized = 1; 1313 | state->single_line = (unsigned char) is_single_line; 1314 | state->insert_mode = 0; 1315 | } 1316 | 1317 | // API initialize 1318 | static void stb_textedit_initialize_state(STB_TexteditState *state, int is_single_line) 1319 | { 1320 | stb_textedit_clear_state(state, is_single_line); 1321 | } 1322 | #endif//STB_TEXTEDIT_IMPLEMENTATION 1323 | -------------------------------------------------------------------------------- /resources.rc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | VS_VERSION_INFO VERSIONINFO 4 | FILEVERSION 1, 0, 0, 0 5 | PRODUCTVERSION 1, 0, 0, 0 6 | FILEFLAGSMASK VS_FFI_FILEFLAGSMASK 7 | FILEFLAGS 0 8 | FILEOS VOS_NT_WINDOWS32 9 | FILETYPE VFT_APP 10 | FILESUBTYPE 0 11 | { 12 | BLOCK "StringFileInfo" { 13 | BLOCK "000004b0" { 14 | VALUE "CompanyName", "Company Mc Companyface" 15 | VALUE "FileDescription", "borderless-window" 16 | VALUE "FileVersion", "1.0.0.0" 17 | VALUE "InternalName", "borderless-window" 18 | VALUE "OriginalFilename", "borderless-window.exe" 19 | VALUE "ProductName", "borderless-window" 20 | VALUE "ProductVersion", "1.0.0.0" 21 | } 22 | } 23 | BLOCK "VarFileInfo" { 24 | VALUE "Translation", 0, 1200 25 | } 26 | } 27 | 28 | CREATEPROCESS_MANIFEST_RESOURCE_ID RT_MANIFEST "borderless-window.exe.manifest" 29 | -------------------------------------------------------------------------------- /screenshots/imgui_with_alpha_on_win32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ands/borderless-window-opengl/e451f4f8e54cf3916e196c504f9453ff9ab2ede8/screenshots/imgui_with_alpha_on_win32.png -------------------------------------------------------------------------------- /vs2013_build.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | call "C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\vcvarsall.bat" x64 3 | cd /d %~dp0 4 | set INCLUDE_DIRS=-I. -Iimgui_winapi_gl2 5 | set SOURCES=borderless-window.cpp borderless-window-rendering.cpp 6 | set IMGUI_SOURCES=imgui_winapi_gl2/imgui.cpp imgui_winapi_gl2/imgui_demo.cpp imgui_winapi_gl2/imgui_draw.cpp imgui_winapi_gl2/imgui_impl_gl2.cpp 7 | rc resources.rc 8 | cl -nologo -MTd -Od -Oi -fp:fast -Gm- -EHsc -GR- -WX -W4 -FC -Z7 %INCLUDE_DIRS% %SOURCES% %IMGUI_SOURCES% /link resources.res -incremental:no -opt:ref 9 | pause -------------------------------------------------------------------------------- /vs2013_debug.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | call "C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\vcvarsall.bat" x64 3 | cd /d %~dp0 4 | devenv borderless-window.exe -------------------------------------------------------------------------------- /vs2015_build.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | call "C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat" x64 3 | cd /d %~dp0 4 | set INCLUDE_DIRS=-I. -Iimgui_winapi_gl2 5 | set SOURCES=borderless-window.cpp borderless-window-rendering.cpp 6 | set IMGUI_SOURCES=imgui_winapi_gl2/imgui.cpp imgui_winapi_gl2/imgui_demo.cpp imgui_winapi_gl2/imgui_draw.cpp imgui_winapi_gl2/imgui_impl_gl2.cpp 7 | rc resources.rc 8 | cl -nologo -MTd -Od -Oi -fp:fast -Gm- -EHsc -GR- -WX -W4 -FC -Z7 %INCLUDE_DIRS% %SOURCES% %IMGUI_SOURCES% /link resources.res -incremental:no -opt:ref 9 | pause -------------------------------------------------------------------------------- /vs2015_debug.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | call "C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat" x64 3 | cd /d %~dp0 4 | devenv borderless-window.exe --------------------------------------------------------------------------------