Compare commits

..

16 Commits
v1.03 ... v1.05

Author SHA1 Message Date
a8d3b045b7 Fix for doing multiple Begin()/End() during the same frame 2014-08-14 15:18:34 +01:00
a830037eab Default "local only" clipboard handler on non-Windows platforms 2014-08-14 15:03:10 +01:00
309ff44579 Undo IsHovered > IsItemHovered, shorter name wins 2014-08-14 14:32:01 +01:00
f30d23a502 Tweaks, more consistent #define names 2014-08-14 14:31:13 +01:00
a905505cca Added GetItemBoxMin(),GetItemBoxMax(), renamed IsHovered()-->IsItemHovered() 2014-08-14 12:43:30 +01:00
46eee0cee4 Tidying up example applications so it looks easier to just grab code 2014-08-14 00:01:41 +01:00
29863b55ef Fixed logarithmic sliders and HSV conversions on Mac/Linux
Tricky bug, I was calling abs() which resolve to abs(float) under
Windows with the include we have, but abs(int) under Mac/Linux
2014-08-13 23:25:42 +01:00
530f103dfe Tweak MacOS X Makefile for likely scenario 2014-08-13 23:02:30 +01:00
7a3e6aa38d Default Clipboard functions on Windows+ renamed ARRAYSIZE to IM_ARRAYSIZE 2014-08-13 19:53:26 +01:00
cda3aecc6a Fixed combo box (bug introduced earlier today) + adding bit of vertical padding in combo. 2014-08-13 19:26:25 +01:00
b6d1d85d86 Fixed scissoring in OpenGL example 2014-08-13 19:12:50 +01:00
9a426faf4f Added InputFloat2(), SliderFloat2() 2014-08-13 18:46:18 +01:00
b0d5600ffb Merge pull request #14 from Roflraging/constiteratorfix
Fix for gcc type qualifier warnings.
2014-08-13 18:40:18 +01:00
c52a54ef43 Fix for gcc type qualifier warnings.
With -Wall -Wextra -Werror, it is not possible to compile against
imgui.h due to const correctness violation in ImVector.
2014-08-13 11:57:37 -05:00
cc9d63b46a Fixed columns lines not being pixel aligned 2014-08-13 17:08:44 +01:00
d3ad5ce475 Update README.md 2014-08-13 13:23:37 +01:00
7 changed files with 453 additions and 266 deletions

View File

@ -1,11 +1,13 @@
ImGui ImGui
===== =====
ImGui is a bloat-free graphical user interface library for C++. It is portable, renderer agnostic and carries minimal amount of dependencies (only 3 files are needed). It is based on an "immediate" graphical user interface paradigm which allows you to build simple user interfaces with ease. ImGui is a bloat-free graphical user interface library for C++. It outputs vertex buffers that you can render in your 3D-pipeline enabled application. It is portable, renderer agnostic and carries minimal amount of dependencies (only 3 files are needed). It is based on an "immediate" graphical user interface paradigm which allows you to build simple user interfaces with ease.
ImGui is designed to allow programmers to create "content creation" or "debug" tools (as opposed to tools for the average end-user). It favors simplicity and thus lacks certain features normally found in more high-level libraries, such as string localisation. ImGui is designed to enable fast iteration and allow programmers to create "content creation" or "debug" tools (as opposed to tools for the average end-user). It favors simplicity and thus lacks certain features normally found in more high-level libraries, such as string localisation.
After ImGui is setup in your application, you can use it like in this example: ImGui is particularly suited to integration in 3D applications, fullscreen applications, embedded applications, games, or any applications on consoles platforms where operating system features are non-standard.
After ImGui is setup in your engine, you can use it like in this example:
![screenshot of sample code alongside its output with ImGui](/web/code_sample_01.png?raw=true) ![screenshot of sample code alongside its output with ImGui](/web/code_sample_01.png?raw=true)

View File

@ -99,55 +99,6 @@ static void ImImpl_RenderDrawLists(ImDrawList** const cmd_lists, int cmd_lists_c
} }
} }
// Get text data in Win32 clipboard
static const char* ImImpl_GetClipboardTextFn()
{
static char* buf_local = NULL;
if (buf_local)
{
free(buf_local);
buf_local = NULL;
}
if (!OpenClipboard(NULL))
return NULL;
HANDLE buf_handle = GetClipboardData(CF_TEXT);
if (buf_handle == NULL)
return NULL;
if (char* buf_global = (char*)GlobalLock(buf_handle))
buf_local = strdup(buf_global);
GlobalUnlock(buf_handle);
CloseClipboard();
return buf_local;
}
// Set text data in Win32 clipboard
static void ImImpl_SetClipboardTextFn(const char* text, const char* text_end)
{
if (!OpenClipboard(NULL))
return;
if (!text_end)
text_end = text + strlen(text);
const int buf_length = (text_end - text) + 1;
HGLOBAL buf_handle = GlobalAlloc(GMEM_MOVEABLE, buf_length * sizeof(char));
if (buf_handle == NULL)
return;
char* buf_global = (char *)GlobalLock(buf_handle);
memcpy(buf_global, text, text_end - text);
buf_global[text_end - text] = 0;
GlobalUnlock(buf_handle);
EmptyClipboard();
SetClipboardData(CF_TEXT, buf_handle);
CloseClipboard();
}
HRESULT InitD3D(HWND hWnd) HRESULT InitD3D(HWND hWnd)
{ {
if (NULL == (g_pD3D = Direct3DCreate9(D3D_SDK_VERSION))) if (NULL == (g_pD3D = Direct3DCreate9(D3D_SDK_VERSION)))
@ -250,8 +201,6 @@ void InitImGui()
io.KeyMap[ImGuiKey_Z] = 'Z'; io.KeyMap[ImGuiKey_Z] = 'Z';
io.RenderDrawListsFn = ImImpl_RenderDrawLists; io.RenderDrawListsFn = ImImpl_RenderDrawLists;
io.SetClipboardTextFn = ImImpl_SetClipboardTextFn;
io.GetClipboardTextFn = ImImpl_GetClipboardTextFn;
// Create the vertex buffer // Create the vertex buffer
if (g_pd3dDevice->CreateVertexBuffer(10000 * sizeof(CUSTOMVERTEX), D3DUSAGE_DYNAMIC | D3DUSAGE_WRITEONLY, D3DFVF_CUSTOMVERTEX, D3DPOOL_DEFAULT, &g_pVB, NULL) < 0) if (g_pd3dDevice->CreateVertexBuffer(10000 * sizeof(CUSTOMVERTEX), D3DUSAGE_DYNAMIC | D3DUSAGE_WRITEONLY, D3DFVF_CUSTOMVERTEX, D3DPOOL_DEFAULT, &g_pVB, NULL) < 0)
@ -271,6 +220,35 @@ void InitImGui()
} }
} }
INT64 ticks_per_second = 0;
INT64 time = 0;
void UpdateImGui()
{
ImGuiIO& io = ImGui::GetIO();
// Setup timestep
INT64 current_time;
QueryPerformanceCounter((LARGE_INTEGER *)&current_time);
io.DeltaTime = (float)(current_time - time) / ticks_per_second;
time = current_time;
// Setup inputs
// (we already got mouse position, buttons, wheel from the window message callback)
BYTE keystate[256];
GetKeyboardState(keystate);
for (int i = 0; i < 256; i++)
io.KeysDown[i] = (keystate[i] & 0x80) != 0;
io.KeyCtrl = (keystate[VK_CONTROL] & 0x80) != 0;
io.KeyShift = (keystate[VK_SHIFT] & 0x80) != 0;
// io.MousePos : filled by WM_MOUSEMOVE event
// io.MouseDown : filled by WM_*BUTTON* events
// io.MouseWheel : filled by WM_MOUSEWHEEL events
// Start the frame
ImGui::NewFrame();
}
int WINAPI wWinMain(HINSTANCE hInst, HINSTANCE, LPWSTR, int) int WINAPI wWinMain(HINSTANCE hInst, HINSTANCE, LPWSTR, int)
{ {
// Register the window class // Register the window class
@ -280,101 +258,91 @@ int WINAPI wWinMain(HINSTANCE hInst, HINSTANCE, LPWSTR, int)
// Create the application's window // Create the application's window
hWnd = CreateWindow(L"ImGui Example", L"ImGui DirectX9 Example", WS_OVERLAPPEDWINDOW, 100, 100, 1280, 800, NULL, NULL, wc.hInstance, NULL); hWnd = CreateWindow(L"ImGui Example", L"ImGui DirectX9 Example", WS_OVERLAPPEDWINDOW, 100, 100, 1280, 800, NULL, NULL, wc.hInstance, NULL);
INT64 ticks_per_second, time;
if (!QueryPerformanceFrequency((LARGE_INTEGER *)&ticks_per_second)) if (!QueryPerformanceFrequency((LARGE_INTEGER *)&ticks_per_second))
return 1; return 1;
if (!QueryPerformanceCounter((LARGE_INTEGER *)&time)) if (!QueryPerformanceCounter((LARGE_INTEGER *)&time))
return 1; return 1;
// Initialize Direct3D // Initialize Direct3D
if (InitD3D(hWnd) >= 0) if (InitD3D(hWnd) < 0)
{
if (g_pVB)
g_pVB->Release();
UnregisterClass(L"ImGui Example", wc.hInstance);
return 1;
}
// Show the window
ShowWindow(hWnd, SW_SHOWDEFAULT);
UpdateWindow(hWnd);
InitImGui();
// Enter the message loop
MSG msg;
ZeroMemory(&msg, sizeof(msg));
while (msg.message != WM_QUIT)
{ {
// Show the window if (PeekMessage(&msg, NULL, 0U, 0U, PM_REMOVE))
ShowWindow(hWnd, SW_SHOWDEFAULT);
UpdateWindow(hWnd);
InitImGui();
// Enter the message loop
MSG msg;
ZeroMemory(&msg, sizeof(msg));
while (msg.message != WM_QUIT)
{ {
if (PeekMessage(&msg, NULL, 0U, 0U, PM_REMOVE)) TranslateMessage(&msg);
{ DispatchMessage(&msg);
TranslateMessage(&msg); continue;
DispatchMessage(&msg); }
continue;
}
// 1) ImGui start frame, setup time delta & inputs UpdateImGui();
ImGuiIO& io = ImGui::GetIO();
INT64 current_time;
QueryPerformanceCounter((LARGE_INTEGER *)&current_time);
io.DeltaTime = (float)(current_time - time) / ticks_per_second;
time = current_time;
BYTE keystate[256];
GetKeyboardState(keystate);
for (int i = 0; i < 256; i++)
io.KeysDown[i] = (keystate[i] & 0x80) != 0;
io.KeyCtrl = (keystate[VK_CONTROL] & 0x80) != 0;
io.KeyShift = (keystate[VK_SHIFT] & 0x80) != 0;
// io.MousePos : filled by WM_MOUSEMOVE event
// io.MouseDown : filled by WM_*BUTTON* events
// io.MouseWheel : filled by WM_MOUSEWHEEL events
ImGui::NewFrame();
// 2) ImGui usage // Create a simple window
static bool show_test_window = true; // Tip: if we don't call ImGui::Begin()/ImGui::End() the widgets appears in a window automatically called "Debug"
static bool show_another_window = false; static bool show_test_window = true;
static float f; static bool show_another_window = false;
ImGui::Text("Hello, world!"); static float f;
ImGui::SliderFloat("float", &f, 0.0f, 1.0f); ImGui::Text("Hello, world!");
show_test_window ^= ImGui::Button("Test Window"); ImGui::SliderFloat("float", &f, 0.0f, 1.0f);
show_another_window ^= ImGui::Button("Another Window"); show_test_window ^= ImGui::Button("Test Window");
show_another_window ^= ImGui::Button("Another Window");
// Calculate and show framerate // Calculate and show framerate
static float ms_per_frame[120] = { 0 }; static float ms_per_frame[120] = { 0 };
static int ms_per_frame_idx = 0; static int ms_per_frame_idx = 0;
static float ms_per_frame_accum = 0.0f; static float ms_per_frame_accum = 0.0f;
ms_per_frame_accum -= ms_per_frame[ms_per_frame_idx]; ms_per_frame_accum -= ms_per_frame[ms_per_frame_idx];
ms_per_frame[ms_per_frame_idx] = io.DeltaTime * 1000.0f; ms_per_frame[ms_per_frame_idx] = ImGui::GetIO().DeltaTime * 1000.0f;
ms_per_frame_accum += ms_per_frame[ms_per_frame_idx]; ms_per_frame_accum += ms_per_frame[ms_per_frame_idx];
ms_per_frame_idx = (ms_per_frame_idx + 1) % 120; ms_per_frame_idx = (ms_per_frame_idx + 1) % 120;
const float ms_per_frame_avg = ms_per_frame_accum / 120; const float ms_per_frame_avg = ms_per_frame_accum / 120;
ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", ms_per_frame_avg, 1000.0f / ms_per_frame_avg); ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", ms_per_frame_avg, 1000.0f / ms_per_frame_avg);
if (show_test_window) // Show the ImGui test window
{ // Most of user example code is in ImGui::ShowTestWindow()
// More example code in ShowTestWindow() if (show_test_window)
ImGui::SetNewWindowDefaultPos(ImVec2(650, 20)); // Normally user code doesn't need/want to call it because positions are saved in .ini file anyway. Here we just want to make the demo initial state a bit more friendly! {
ImGui::ShowTestWindow(&show_test_window); ImGui::SetNewWindowDefaultPos(ImVec2(650, 20)); // Normally user code doesn't need/want to call it because positions are saved in .ini file anyway. Here we just want to make the demo initial state a bit more friendly!
} ImGui::ShowTestWindow(&show_test_window);
if (show_another_window)
{
ImGui::Begin("Another Window", &show_another_window, ImVec2(200,100));
ImGui::Text("Hello");
ImGui::End();
}
// 3) Rendering
// Clear frame buffer
g_pd3dDevice->SetRenderState(D3DRS_ZENABLE, false);
g_pd3dDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, false);
g_pd3dDevice->SetRenderState(D3DRS_SCISSORTESTENABLE, false);
g_pd3dDevice->Clear(0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, D3DCOLOR_XRGB(204, 153, 153), 1.0f, 0);
if (g_pd3dDevice->BeginScene() >= 0)
{
// Render ImGui
ImGui::Render();
g_pd3dDevice->EndScene();
}
g_pd3dDevice->Present(NULL, NULL, NULL, NULL);
} }
ImGui::Shutdown(); // Show another simple window
} if (show_another_window)
{
ImGui::Begin("Another Window", &show_another_window, ImVec2(200,100));
ImGui::Text("Hello");
ImGui::End();
}
// Rendering
g_pd3dDevice->SetRenderState(D3DRS_ZENABLE, false);
g_pd3dDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, false);
g_pd3dDevice->SetRenderState(D3DRS_SCISSORTESTENABLE, false);
g_pd3dDevice->Clear(0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, D3DCOLOR_XRGB(204, 153, 153), 1.0f, 0);
if (g_pd3dDevice->BeginScene() >= 0)
{
ImGui::Render();
g_pd3dDevice->EndScene();
}
g_pd3dDevice->Present(NULL, NULL, NULL, NULL);
}
ImGui::Shutdown();
if (g_pVB) if (g_pVB)
g_pVB->Release(); g_pVB->Release();

View File

@ -5,7 +5,8 @@
# #
CXXFLAGS=-framework OpenGL -framework Cocoa -framework IOKit CXXFLAGS=-framework OpenGL -framework Cocoa -framework IOKit
#CXXFLAGS+=-L/usr/local/Cellar/glew/1.10.0/lib -L/usr/local/Cellar/glfw3/3.0.4/lib CXXFLAGS+=-I/usr/local/Cellar/glew/1.10.0/include -I/usr/local/Cellar/glfw3/3.0.4/include
CXXFLAGS+=-L/usr/local/Cellar/glew/1.10.0/lib -L/usr/local/Cellar/glfw3/3.0.4/lib
CXXFLAGS+=-lglew -lglfw3 CXXFLAGS+=-lglew -lglfw3
CXXFLAGS+=-I../../ CXXFLAGS+=-I../../
CXXFLAGS+= -D__APPLE__ CXXFLAGS+= -D__APPLE__

View File

@ -19,24 +19,26 @@ static void ImImpl_RenderDrawLists(ImDrawList** const cmd_lists, int cmd_lists_c
if (cmd_lists_count == 0) if (cmd_lists_count == 0)
return; return;
// Setup render state: alpha-blending enabled, no face culling, no depth testing // Setup render state: alpha-blending enabled, no face culling, no depth testing, scissor enabled, vertex/texcoord/color pointers.
glEnable(GL_BLEND); glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glDisable(GL_CULL_FACE); glDisable(GL_CULL_FACE);
glDisable(GL_DEPTH_TEST); glDisable(GL_DEPTH_TEST);
//glEnable(GL_SCISSOR_TEST); glEnable(GL_SCISSOR_TEST);
glEnableClientState(GL_VERTEX_ARRAY); glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_TEXTURE_COORD_ARRAY); glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glEnableClientState(GL_COLOR_ARRAY); glEnableClientState(GL_COLOR_ARRAY);
// Bind texture // Setup texture
glBindTexture(GL_TEXTURE_2D, fontTex); glBindTexture(GL_TEXTURE_2D, fontTex);
glEnable(GL_TEXTURE_2D); glEnable(GL_TEXTURE_2D);
// Setup matrices // Setup orthographic projection matrix
const float width = ImGui::GetIO().DisplaySize.x;
const float height = ImGui::GetIO().DisplaySize.y;
glMatrixMode(GL_PROJECTION); glMatrixMode(GL_PROJECTION);
glLoadIdentity(); glLoadIdentity();
glOrtho(0.0f, ImGui::GetIO().DisplaySize.x, ImGui::GetIO().DisplaySize.y, 0.0f, -1.0f, +1.0f); glOrtho(0.0f, width, height, 0.0f, -1.0f, +1.0f);
glMatrixMode(GL_MODELVIEW); glMatrixMode(GL_MODELVIEW);
glLoadIdentity(); glLoadIdentity();
@ -53,7 +55,7 @@ static void ImImpl_RenderDrawLists(ImDrawList** const cmd_lists, int cmd_lists_c
const ImDrawCmd* pcmd_end = cmd_list->commands.end(); const ImDrawCmd* pcmd_end = cmd_list->commands.end();
for (const ImDrawCmd* pcmd = cmd_list->commands.begin(); pcmd != pcmd_end; pcmd++) for (const ImDrawCmd* pcmd = cmd_list->commands.begin(); pcmd != pcmd_end; pcmd++)
{ {
glScissor((int)pcmd->clip_rect.x, (int)pcmd->clip_rect.y, (int)(pcmd->clip_rect.z - pcmd->clip_rect.x), (int)(pcmd->clip_rect.w - pcmd->clip_rect.y)); glScissor((int)pcmd->clip_rect.x, (int)(height - pcmd->clip_rect.w), (int)(pcmd->clip_rect.z - pcmd->clip_rect.x), (int)(pcmd->clip_rect.w - pcmd->clip_rect.y));
glDrawArrays(GL_TRIANGLES, vtx_offset, pcmd->vtx_count); glDrawArrays(GL_TRIANGLES, vtx_offset, pcmd->vtx_count);
vtx_offset += pcmd->vtx_count; vtx_offset += pcmd->vtx_count;
} }
@ -71,24 +73,33 @@ static void ImImpl_SetClipboardTextFn(const char* text, const char* text_end)
if (!text_end) if (!text_end)
text_end = text + strlen(text); text_end = text + strlen(text);
// Add a zero-terminator because glfw function doesn't take a size if (*text_end == 0)
char* buf = (char*)malloc(text_end - text + 1); {
memcpy(buf, text, text_end-text); // Already got a zero-terminator at 'text_end', we don't need to add one
buf[text_end-text] = '\0'; glfwSetClipboardString(window, text);
glfwSetClipboardString(window, buf); }
free(buf); else
{
// Add a zero-terminator because glfw function doesn't take a size
char* buf = (char*)malloc(text_end - text + 1);
memcpy(buf, text, text_end-text);
buf[text_end-text] = '\0';
glfwSetClipboardString(window, buf);
free(buf);
}
} }
// GLFW callbacks to get events // GLFW callbacks to get events
static void glfw_error_callback(int error, const char* description) static void glfw_error_callback(int error, const char* description)
{ {
fputs(description, stderr); fputs(description, stderr);
} }
static float mouse_wheel = 0.0f;
static void glfw_scroll_callback(GLFWwindow* window, double xoffset, double yoffset) static void glfw_scroll_callback(GLFWwindow* window, double xoffset, double yoffset)
{ {
mouse_wheel = (float)yoffset; ImGuiIO& io = ImGui::GetIO();
io.MouseWheel = (yoffset != 0.0f) ? yoffset > 0.0f ? 1 : - 1 : 0; // Mouse wheel: -1,0,+1
} }
static void glfw_key_callback(GLFWwindow* window, int key, int scancode, int action, int mods) static void glfw_key_callback(GLFWwindow* window, int key, int scancode, int action, int mods)
@ -171,37 +182,43 @@ void InitImGui()
stbi_image_free(tex_data); stbi_image_free(tex_data);
} }
void Shutdown() void UpdateImGui()
{ {
ImGui::Shutdown(); ImGuiIO& io = ImGui::GetIO();
glfwTerminate();
// Setup timestep
static double time = 0.0f;
const double current_time = glfwGetTime();
io.DeltaTime = (float)(current_time - time);
time = current_time;
// Setup inputs
// (we already got mouse wheel, keyboard keys & characters from glfw callbacks polled in glfwPollEvents())
double mouse_x, mouse_y;
glfwGetCursorPos(window, &mouse_x, &mouse_y);
io.MousePos = ImVec2((float)mouse_x, (float)mouse_y); // Mouse position, in pixels (set to -1,-1 if no mouse / on another screen, etc.)
io.MouseDown[0] = glfwGetMouseButton(window, GLFW_MOUSE_BUTTON_LEFT) != 0;
io.MouseDown[1] = glfwGetMouseButton(window, GLFW_MOUSE_BUTTON_RIGHT) != 0;
// Start the frame
ImGui::NewFrame();
} }
// Application code
int main(int argc, char** argv) int main(int argc, char** argv)
{ {
InitGL(); InitGL();
InitImGui(); InitImGui();
double time = glfwGetTime();
while (!glfwWindowShouldClose(window)) while (!glfwWindowShouldClose(window))
{ {
ImGuiIO& io = ImGui::GetIO(); ImGuiIO& io = ImGui::GetIO();
io.MouseWheel = 0;
glfwPollEvents(); glfwPollEvents();
UpdateImGui();
// 1) ImGui start frame, setup time delta & inputs // Create a simple window
const double current_time = glfwGetTime(); // Tip: if we don't call ImGui::Begin()/ImGui::End() the widgets appears in a window automatically called "Debug"
io.DeltaTime = (float)(current_time - time);
time = current_time;
double mouse_x, mouse_y;
glfwGetCursorPos(window, &mouse_x, &mouse_y);
io.MousePos = ImVec2((float)mouse_x, (float)mouse_y); // Mouse position, in pixels (set to -1,-1 if no mouse / on another screen, etc.)
io.MouseDown[0] = glfwGetMouseButton(window, GLFW_MOUSE_BUTTON_LEFT) != 0;
io.MouseDown[1] = glfwGetMouseButton(window, GLFW_MOUSE_BUTTON_RIGHT) != 0;
io.MouseWheel = (mouse_wheel != 0) ? mouse_wheel > 0.0f ? 1 : - 1 : 0; // Mouse wheel: -1,0,+1
mouse_wheel = 0.0f;
ImGui::NewFrame();
// 2) ImGui usage
static bool show_test_window = true; static bool show_test_window = true;
static bool show_another_window = false; static bool show_another_window = false;
static float f; static float f;
@ -215,19 +232,21 @@ int main(int argc, char** argv)
static int ms_per_frame_idx = 0; static int ms_per_frame_idx = 0;
static float ms_per_frame_accum = 0.0f; static float ms_per_frame_accum = 0.0f;
ms_per_frame_accum -= ms_per_frame[ms_per_frame_idx]; ms_per_frame_accum -= ms_per_frame[ms_per_frame_idx];
ms_per_frame[ms_per_frame_idx] = io.DeltaTime * 1000.0f; ms_per_frame[ms_per_frame_idx] = ImGui::GetIO().DeltaTime * 1000.0f;
ms_per_frame_accum += ms_per_frame[ms_per_frame_idx]; ms_per_frame_accum += ms_per_frame[ms_per_frame_idx];
ms_per_frame_idx = (ms_per_frame_idx + 1) % 120; ms_per_frame_idx = (ms_per_frame_idx + 1) % 120;
const float ms_per_frame_avg = ms_per_frame_accum / 120; const float ms_per_frame_avg = ms_per_frame_accum / 120;
ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", ms_per_frame_avg, 1000.0f / ms_per_frame_avg); ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", ms_per_frame_avg, 1000.0f / ms_per_frame_avg);
// Show the ImGui test window
// Most of user example code is in ImGui::ShowTestWindow()
if (show_test_window) if (show_test_window)
{ {
// More example code in ShowTestWindow()
ImGui::SetNewWindowDefaultPos(ImVec2(650, 20)); // Normally user code doesn't need/want to call it because positions are saved in .ini file anyway. Here we just want to make the demo initial state a bit more friendly! ImGui::SetNewWindowDefaultPos(ImVec2(650, 20)); // Normally user code doesn't need/want to call it because positions are saved in .ini file anyway. Here we just want to make the demo initial state a bit more friendly!
ImGui::ShowTestWindow(&show_test_window); ImGui::ShowTestWindow(&show_test_window);
} }
// Show another simple window
if (show_another_window) if (show_another_window)
{ {
ImGui::Begin("Another Window", &show_another_window, ImVec2(200,100)); ImGui::Begin("Another Window", &show_another_window, ImVec2(200,100));
@ -235,15 +254,15 @@ int main(int argc, char** argv)
ImGui::End(); ImGui::End();
} }
// 3) Rendering // Rendering
glViewport(0, 0, (int)io.DisplaySize.x, (int)io.DisplaySize.y); glViewport(0, 0, (int)io.DisplaySize.x, (int)io.DisplaySize.y);
glClearColor(0.8f, 0.6f, 0.6f, 1.0f); glClearColor(0.8f, 0.6f, 0.6f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT); glClear(GL_COLOR_BUFFER_BIT);
ImGui::Render(); ImGui::Render();
glfwSwapBuffers(window); glfwSwapBuffers(window);
} }
Shutdown(); ImGui::Shutdown();
glfwTerminate();
return 0; return 0;
} }

View File

@ -4,15 +4,22 @@
#pragma once #pragma once
//----- Define your own ImVector<> type if you don't want to use the provided implementation defined in imgui.h //---- Define your own ImVector<> type if you don't want to use the provided implementation defined in imgui.h
//#include <vector> //#include <vector>
//#define ImVector std::vector //#define ImVector std::vector
//#define ImVector MyVector //#define ImVector MyVector
//----- Define assertion handler. Default to calling assert(). //---- Define assertion handler. Defaults to calling assert().
// #define IM_ASSERT(_EXPR) MyAssert(_EXPR) //#define IM_ASSERT(_EXPR) MyAssert(_EXPR)
//----- Define implicit cast operators to convert back<>forth from your math types and ImVec2/ImVec4. //---- Don't implement default clipboard handlers for Windows (so as not to link with OpenClipboard(), etc.)
//#define IMGUI_DISABLE_WIN32_DEFAULT_CLIPBOARD_FUNCS
//---- If you are loading a custom font, ImGui expect to find a pure white pixel at (0,0)
// Change it's UV coordinate here if you can't have a white pixel at (0,0)
//#define IMGUI_FONT_TEX_UV_FOR_WHITE ImVec2(0.f/256.f,0.f/256.f)
//---- Define implicit cast operators to convert back<>forth from your math types and ImVec2/ImVec4.
/* /*
#define IM_VEC2_CLASS_EXTRA \ #define IM_VEC2_CLASS_EXTRA \
ImVec2(const MyVec2& f) { x = f.x; y = f.y; } \ ImVec2(const MyVec2& f) { x = f.x; y = f.y; } \
@ -23,8 +30,8 @@
operator MyVec4() const { return MyVec4(x,y,z,w); } operator MyVec4() const { return MyVec4(x,y,z,w); }
*/ */
//----- Freely implement extra functions within the ImGui:: namespace. //---- Freely implement extra functions within the ImGui:: namespace.
//----- e.g. you can create variants of the ImGui::Value() helper for your low-level math types. //---- e.g. you can create variants of the ImGui::Value() helper for your low-level math types.
/* /*
namespace ImGui namespace ImGui
{ {

333
imgui.cpp
View File

@ -101,7 +101,7 @@
- if you want to use a different font than the default - if you want to use a different font than the default
- create bitmap font data using BMFont. allocate ImGui::GetIO().Font and use ->LoadFromFile()/LoadFromMemory(), set ImGui::GetIO().FontHeight - create bitmap font data using BMFont. allocate ImGui::GetIO().Font and use ->LoadFromFile()/LoadFromMemory(), set ImGui::GetIO().FontHeight
- load your texture yourself. texture *MUST* have white pixel at UV coordinate 'IMDRAW_TEX_UV_FOR_WHITE' (you can #define it in imconfig.h), this is used by solid objects. - load your texture yourself. texture *MUST* have white pixel at UV coordinate 'IMGUI_FONT_TEX_UV_FOR_WHITE' (you can #define it in imconfig.h), this is used by solid objects.
- tip: the construct 'if (IMGUI_ONCE_UPON_A_FRAME)' will evaluate to true only once a frame, you can use it to add custom UI in the middle of a deep nested inner loop in your code. - tip: the construct 'if (IMGUI_ONCE_UPON_A_FRAME)' will evaluate to true only once a frame, you can use it to add custom UI in the middle of a deep nested inner loop in your code.
- tip: you can call Render() multiple times (e.g for VR renders), up to you to communicate the extra state to your RenderDrawListFn function. - tip: you can call Render() multiple times (e.g for VR renders), up to you to communicate the extra state to your RenderDrawListFn function.
@ -110,18 +110,20 @@
ISSUES AND TODO-LIST ISSUES AND TODO-LIST
- misc: merge ImVec4 / ImGuiAabb, they are essentially duplicate containers - misc: merge ImVec4 / ImGuiAabb, they are essentially duplicate containers
- main: make IsHovered() more consistent for various type of widgets, widgets with multiple components, etc. also effectively IsHovered() region sometimes differs from hot region, e.g tree nodes
- window: autofit is losing its purpose when user relies on any dynamic layout (window width multiplier, column). maybe just discard autofit? - window: autofit is losing its purpose when user relies on any dynamic layout (window width multiplier, column). maybe just discard autofit?
- window: support horizontal scroll - window: support horizontal scroll
- window: fix resize grip scaling along with Rounding style setting - window: fix resize grip scaling along with Rounding style setting
- window/style: add global alpha modifier (not just "fill_alpha")
- widgets: switching from "widget-label" to "label-widget" would make it more convenient to integrate widgets in trees - widgets: switching from "widget-label" to "label-widget" would make it more convenient to integrate widgets in trees
- widgets: clip text? hover clipped text shows it in a tooltip or in-place overlay - widgets: clip text? hover clipped text shows it in a tooltip or in-place overlay
- main: make IsHovered() more consistent for various type of widgets, widgets with multiple components, etc. also effectively IsHovered() region sometimes differs from hot region, e.g tree nodes
- main: make IsHovered() info stored in a stack? so that 'if TreeNode() { Text; TreePop; } if IsHovered' return the hover state of the TreeNode?
- scrollbar: use relative mouse movement when first-clicking inside of scroll grab box. - scrollbar: use relative mouse movement when first-clicking inside of scroll grab box.
- input number: optional range min/max - input number: optional range min/max
- input number: holding [-]/[+] buttons should increase the step non-linearly - input number: holding [-]/[+] buttons should increase the step non-linearly
- input number: rename Input*() to Input(), Slider*() to Slider() ? - input number: rename Input*() to Input(), Slider*() to Slider() ?
- layout: clean up the InputFloat3/SliderFloat3/ColorEdit4 horrible layout code. item width should include frame padding, then we can have a generic horizontal layout helper. - layout: clean up the InputFloat3/SliderFloat3/ColorEdit4 horrible layout code. item width should include frame padding, then we can have a generic horizontal layout helper.
- add input2/4 helper (once above layout helpers are in they'll be smaller) - add input4 helper (once above layout helpers are in they'll be smaller)
- columns: declare column set (each column: fixed size, %, fill, distribute default size among fills) - columns: declare column set (each column: fixed size, %, fill, distribute default size among fills)
- columns: columns header to act as button (~sort op) and allow resize/reorder - columns: columns header to act as button (~sort op) and allow resize/reorder
- columns: user specify columns size - columns: user specify columns size
@ -144,7 +146,6 @@
- filters: handle wildcards (with implicit leading/trailing *), regexps - filters: handle wildcards (with implicit leading/trailing *), regexps
- shortcuts: add a shortcut api, e.g. parse "&Save" and/or "Save (CTRL+S)", pass in to widgets or provide simple ways to use (button=activate, input=focus) - shortcuts: add a shortcut api, e.g. parse "&Save" and/or "Save (CTRL+S)", pass in to widgets or provide simple ways to use (button=activate, input=focus)
- keyboard: full keyboard navigation and focus - keyboard: full keyboard navigation and focus
- clipboard: add a default "local" implementation of clipboard functions (user will only need to override them to connect to OS clipboard)
- misc: not thread-safe - misc: not thread-safe
- optimisation/render: use indexed rendering - optimisation/render: use indexed rendering
- optimisation/render: move clip-rect to vertex data? would allow merging all commands - optimisation/render: move clip-rect to vertex data? would allow merging all commands
@ -152,8 +153,6 @@
- optimisation: turn some the various stack vectors into statically-sized arrays - optimisation: turn some the various stack vectors into statically-sized arrays
- optimisation: better clipping for multi-component widgets - optimisation: better clipping for multi-component widgets
- optimisation: specialize for height based clipping first (assume widgets never go up + height tests before width tests?) - optimisation: specialize for height based clipping first (assume widgets never go up + height tests before width tests?)
- optimisation/portability: provide ImVector style implementation
- optimisation/portability: remove dependency on <algorithm>
*/ */
#include "imgui.h" #include "imgui.h"
@ -195,6 +194,13 @@ static ImGuiWindow* FindHoveredWindow(ImVec2 pos, bool excluding_childs);
}; // namespace ImGui }; // namespace ImGui
//-----------------------------------------------------------------------------
// Platform dependant default implementations
//-----------------------------------------------------------------------------
static const char* GetClipboardTextFn_DefaultImpl();
static void SetClipboardTextFn_DefaultImpl(const char* text, const char* text_end);
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// User facing structures // User facing structures
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
@ -267,6 +273,10 @@ ImGuiIO::ImGuiIO()
MousePosPrev = ImVec2(-1,-1); MousePosPrev = ImVec2(-1,-1);
MouseDoubleClickTime = 0.30f; MouseDoubleClickTime = 0.30f;
MouseDoubleClickMaxDist = 6.0f; MouseDoubleClickMaxDist = 6.0f;
// Platform dependant default implementations
GetClipboardTextFn = GetClipboardTextFn_DefaultImpl;
SetClipboardTextFn = SetClipboardTextFn_DefaultImpl;
} }
// Pass in translated ASCII characters for text input. // Pass in translated ASCII characters for text input.
@ -286,8 +296,7 @@ void ImGuiIO::AddInputCharacter(char c)
// Helpers // Helpers
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
#undef ARRAYSIZE #define IM_ARRAYSIZE(_ARR) ((int)(sizeof(_ARR)/sizeof(*_ARR)))
#define ARRAYSIZE(_ARR) ((int)(sizeof(_ARR)/sizeof(*_ARR)))
#undef PI #undef PI
const float PI = 3.14159265358979323846f; const float PI = 3.14159265358979323846f;
@ -420,7 +429,7 @@ static void ImConvertColorRGBtoHSV(float r, float g, float b, float& out_h, floa
} }
const float chroma = r - (g < b ? g : b); const float chroma = r - (g < b ? g : b);
out_h = abs(K + (g - b) / (6.f * chroma + 1e-20f)); out_h = fabsf(K + (g - b) / (6.f * chroma + 1e-20f));
out_s = chroma / (r + 1e-20f); out_s = chroma / (r + 1e-20f);
out_v = r; out_v = r;
} }
@ -497,6 +506,7 @@ struct ImGuiDrawContext
float PrevLineHeight; float PrevLineHeight;
float LogLineHeight; float LogLineHeight;
int TreeDepth; int TreeDepth;
ImGuiAabb LastItemAabb;
bool LastItemHovered; bool LastItemHovered;
ImVector<ImGuiWindow*> ChildWindows; ImVector<ImGuiWindow*> ChildWindows;
ImVector<bool> AllowKeyboardFocus; ImVector<bool> AllowKeyboardFocus;
@ -519,6 +529,7 @@ struct ImGuiDrawContext
CurrentLineHeight = PrevLineHeight = 0.0f; CurrentLineHeight = PrevLineHeight = 0.0f;
LogLineHeight = -1.0f; LogLineHeight = -1.0f;
TreeDepth = 0; TreeDepth = 0;
LastItemAabb = ImGuiAabb(0.0f,0.0f,0.0f,0.0f);
LastItemHovered = false; LastItemHovered = false;
StateStorage = NULL; StateStorage = NULL;
OpenNextNode = -1; OpenNextNode = -1;
@ -608,6 +619,7 @@ struct ImGuiState
ImGuiStorage ColorEditModeStorage; // for user selection ImGuiStorage ColorEditModeStorage; // for user selection
ImGuiID ActiveComboID; ImGuiID ActiveComboID;
char Tooltip[1024]; char Tooltip[1024];
char* PrivateClipboard; // if no custom clipboard handler is defined
// Logging // Logging
bool LogEnabled; bool LogEnabled;
@ -631,6 +643,7 @@ struct ImGuiState
SliderAsInputTextId = 0; SliderAsInputTextId = 0;
ActiveComboID = 0; ActiveComboID = 0;
memset(Tooltip, 0, sizeof(Tooltip)); memset(Tooltip, 0, sizeof(Tooltip));
PrivateClipboard = NULL;
LogEnabled = false; LogEnabled = false;
LogFile = NULL; LogFile = NULL;
LogAutoExpandMaxDepth = 2; LogAutoExpandMaxDepth = 2;
@ -794,7 +807,7 @@ void ImGuiTextFilter::Draw(const char* label, float width)
width = ImMax(window->Pos.x + ImGui::GetWindowContentRegionMax().x - window->DC.CursorPos.x - (label_size.x + GImGui.Style.ItemSpacing.x*4), 10.0f); width = ImMax(window->Pos.x + ImGui::GetWindowContentRegionMax().x - window->DC.CursorPos.x - (label_size.x + GImGui.Style.ItemSpacing.x*4), 10.0f);
} }
ImGui::PushItemWidth(width); ImGui::PushItemWidth(width);
ImGui::InputText(label, InputBuf, ARRAYSIZE(InputBuf)); ImGui::InputText(label, InputBuf, IM_ARRAYSIZE(InputBuf));
ImGui::PopItemWidth(); ImGui::PopItemWidth();
Build(); Build();
} }
@ -1036,7 +1049,7 @@ static void LoadSettings()
if (fseek(f, 0, SEEK_SET)) if (fseek(f, 0, SEEK_SET))
return; return;
char* f_data = new char[f_size+1]; char* f_data = new char[f_size+1];
f_size = fread(f_data, 1, f_size, f); // Text conversion alter read size so let's not be fussy about return value f_size = (long)fread(f_data, 1, f_size, f); // Text conversion alter read size so let's not be fussy about return value
fclose(f); fclose(f);
if (f_size == 0) if (f_size == 0)
{ {
@ -1056,7 +1069,7 @@ static void LoadSettings()
if (line_start[0] == '[' && line_end > line_start && line_end[-1] == ']') if (line_start[0] == '[' && line_end > line_start && line_end[-1] == ']')
{ {
char name[64]; char name[64];
ImFormatString(name, ARRAYSIZE(name), "%.*s", line_end-line_start-2, line_start+1); ImFormatString(name, IM_ARRAYSIZE(name), "%.*s", line_end-line_start-2, line_start+1);
settings = FindWindowSettings(name); settings = FindWindowSettings(name);
} }
else if (settings) else if (settings)
@ -1171,7 +1184,7 @@ void NewFrame()
else else
g.IO.MouseDelta = g.IO.MousePos - g.IO.MousePosPrev; g.IO.MouseDelta = g.IO.MousePos - g.IO.MousePosPrev;
g.IO.MousePosPrev = g.IO.MousePos; g.IO.MousePosPrev = g.IO.MousePos;
for (size_t i = 0; i < ARRAYSIZE(g.IO.MouseDown); i++) for (size_t i = 0; i < IM_ARRAYSIZE(g.IO.MouseDown); i++)
{ {
g.IO.MouseDownTime[i] = g.IO.MouseDown[i] ? (g.IO.MouseDownTime[i] < 0.0f ? 0.0f : g.IO.MouseDownTime[i] + g.IO.DeltaTime) : -1.0f; g.IO.MouseDownTime[i] = g.IO.MouseDown[i] ? (g.IO.MouseDownTime[i] < 0.0f ? 0.0f : g.IO.MouseDownTime[i] + g.IO.DeltaTime) : -1.0f;
g.IO.MouseClicked[i] = (g.IO.MouseDownTime[i] == 0.0f); g.IO.MouseClicked[i] = (g.IO.MouseDownTime[i] == 0.0f);
@ -1191,7 +1204,7 @@ void NewFrame()
} }
} }
} }
for (size_t i = 0; i < ARRAYSIZE(g.IO.KeysDown); i++) for (size_t i = 0; i < IM_ARRAYSIZE(g.IO.KeysDown); i++)
g.IO.KeysDownTime[i] = g.IO.KeysDown[i] ? (g.IO.KeysDownTime[i] < 0.0f ? 0.0f : g.IO.KeysDownTime[i] + g.IO.DeltaTime) : -1.0f; g.IO.KeysDownTime[i] = g.IO.KeysDown[i] ? (g.IO.KeysDownTime[i] < 0.0f ? 0.0f : g.IO.KeysDownTime[i] + g.IO.DeltaTime) : -1.0f;
// Clear reference to active widget if the widget isn't alive anymore // Clear reference to active widget if the widget isn't alive anymore
@ -1291,6 +1304,12 @@ void Shutdown()
g.IO.Font = NULL; g.IO.Font = NULL;
} }
if (g.PrivateClipboard)
{
free(g.PrivateClipboard);
g.PrivateClipboard = NULL;
}
g.Initialized = false; g.Initialized = false;
} }
@ -1604,7 +1623,7 @@ static bool IsKeyPressedMap(ImGuiKey key, bool repeat)
bool IsKeyPressed(int key_index, bool repeat) bool IsKeyPressed(int key_index, bool repeat)
{ {
ImGuiState& g = GImGui; ImGuiState& g = GImGui;
IM_ASSERT(key_index >= 0 && key_index < ARRAYSIZE(g.IO.KeysDown)); IM_ASSERT(key_index >= 0 && key_index < IM_ARRAYSIZE(g.IO.KeysDown));
const float t = g.IO.KeysDownTime[key_index]; const float t = g.IO.KeysDownTime[key_index];
if (t == 0.0f) if (t == 0.0f)
return true; return true;
@ -1622,7 +1641,7 @@ bool IsKeyPressed(int key_index, bool repeat)
bool IsMouseClicked(int button, bool repeat) bool IsMouseClicked(int button, bool repeat)
{ {
ImGuiState& g = GImGui; ImGuiState& g = GImGui;
IM_ASSERT(button >= 0 && button < ARRAYSIZE(g.IO.MouseDown)); IM_ASSERT(button >= 0 && button < IM_ARRAYSIZE(g.IO.MouseDown));
const float t = g.IO.MouseDownTime[button]; const float t = g.IO.MouseDownTime[button];
if (t == 0.0f) if (t == 0.0f)
return true; return true;
@ -1640,7 +1659,7 @@ bool IsMouseClicked(int button, bool repeat)
bool IsMouseDoubleClicked(int button) bool IsMouseDoubleClicked(int button)
{ {
ImGuiState& g = GImGui; ImGuiState& g = GImGui;
IM_ASSERT(button >= 0 && button < ARRAYSIZE(g.IO.MouseDown)); IM_ASSERT(button >= 0 && button < IM_ARRAYSIZE(g.IO.MouseDown));
return g.IO.MouseDoubleClicked[button]; return g.IO.MouseDoubleClicked[button];
} }
@ -1655,12 +1674,24 @@ bool IsHovered()
return window->DC.LastItemHovered; return window->DC.LastItemHovered;
} }
ImVec2 GetItemBoxMin()
{
ImGuiWindow* window = GetCurrentWindow();
return window->DC.LastItemAabb.Min;
}
ImVec2 GetItemBoxMax()
{
ImGuiWindow* window = GetCurrentWindow();
return window->DC.LastItemAabb.Max;
}
void SetTooltip(const char* fmt, ...) void SetTooltip(const char* fmt, ...)
{ {
ImGuiState& g = GImGui; ImGuiState& g = GImGui;
va_list args; va_list args;
va_start(args, fmt); va_start(args, fmt);
ImFormatStringV(g.Tooltip, ARRAYSIZE(g.Tooltip), fmt, args); ImFormatStringV(g.Tooltip, IM_ARRAYSIZE(g.Tooltip), fmt, args);
va_end(args); va_end(args);
} }
@ -1713,7 +1744,7 @@ void BeginChild(const char* str_id, ImVec2 size, bool border, ImGuiWindowFlags e
flags |= extra_flags; flags |= extra_flags;
char title[256]; char title[256];
ImFormatString(title, ARRAYSIZE(title), "%s.%s", window->Name, str_id); ImFormatString(title, IM_ARRAYSIZE(title), "%s.%s", window->Name, str_id);
const float alpha = (flags & ImGuiWindowFlags_ComboBox) ? 1.0f : 0.0f; const float alpha = (flags & ImGuiWindowFlags_ComboBox) ? 1.0f : 0.0f;
ImGui::Begin(title, NULL, size, alpha, flags); ImGui::Begin(title, NULL, size, alpha, flags);
@ -1802,13 +1833,13 @@ bool Begin(const char* name, bool* open, ImVec2 size, float fill_alpha, ImGuiWin
parent_window->DC.ChildWindows.push_back(window); parent_window->DC.ChildWindows.push_back(window);
window->Pos = window->PosFloat = parent_window->DC.CursorPos; window->Pos = window->PosFloat = parent_window->DC.CursorPos;
window->SizeFull = size; window->SizeFull = size;
if (!(flags & ImGuiWindowFlags_ComboBox))
ImGui::PushClipRect(parent_window->ClipRectStack.back());
} }
// Outer clipping rectangle
if ((flags & ImGuiWindowFlags_ChildWindow) && !(flags & ImGuiWindowFlags_ComboBox))
ImGui::PushClipRect(g.CurrentWindowStack[g.CurrentWindowStack.size()-2]->ClipRectStack.back());
else else
{
ImGui::PushClipRect(ImVec4(0.0f, 0.0f, g.IO.DisplaySize.x, g.IO.DisplaySize.y)); ImGui::PushClipRect(ImVec4(0.0f, 0.0f, g.IO.DisplaySize.x, g.IO.DisplaySize.y));
}
// ID stack // ID stack
window->IDStack.resize(0); window->IDStack.resize(0);
@ -2049,8 +2080,16 @@ bool Begin(const char* name, bool* open, ImVec2 size, float fill_alpha, ImGuiWin
ImGui::CloseWindowButton(open); ImGui::CloseWindowButton(open);
} }
} }
else
{
// Outer clipping rectangle
if ((flags & ImGuiWindowFlags_ChildWindow) && !(flags & ImGuiWindowFlags_ComboBox))
ImGui::PushClipRect(g.CurrentWindowStack[g.CurrentWindowStack.size()-2]->ClipRectStack.back());
else
ImGui::PushClipRect(ImVec4(0.0f, 0.0f, g.IO.DisplaySize.x, g.IO.DisplaySize.y));
}
// Clip rectangle // Innter clipping rectangle
// We set this up after processing the resize grip so that our clip rectangle doesn't lag by a frame // We set this up after processing the resize grip so that our clip rectangle doesn't lag by a frame
const ImGuiAabb title_bar_aabb = window->TitleBarAabb(); const ImGuiAabb title_bar_aabb = window->TitleBarAabb();
ImVec4 clip_rect(title_bar_aabb.Min.x+0.5f, title_bar_aabb.Max.y+0.5f, window->Aabb().Max.x-1.5f, window->Aabb().Max.y-1.5f); ImVec4 clip_rect(title_bar_aabb.Min.x+0.5f, title_bar_aabb.Max.y+0.5f, window->Aabb().Max.x-1.5f, window->Aabb().Max.y-1.5f);
@ -2074,16 +2113,8 @@ void End()
ImGuiWindow* window = g.CurrentWindow; ImGuiWindow* window = g.CurrentWindow;
ImGui::Columns(1, "#CloseColumns"); ImGui::Columns(1, "#CloseColumns");
ImGui::PopClipRect(); ImGui::PopClipRect(); // inner window clip rectangle
if (window->Flags & ImGuiWindowFlags_ChildWindow) ImGui::PopClipRect(); // outer window clip rectangle
{
if (!(window->Flags & ImGuiWindowFlags_ComboBox))
ImGui::PopClipRect();
}
else
{
ImGui::PopClipRect();
}
// Select window for move/focus when we're done with all our widgets // Select window for move/focus when we're done with all our widgets
ImGuiAabb bb(window->Pos, window->Pos+window->Size); ImGuiAabb bb(window->Pos, window->Pos+window->Size);
@ -2340,7 +2371,7 @@ void TextV(const char* fmt, va_list args)
return; return;
static char buf[1024]; static char buf[1024];
const char* text_end = buf + ImFormatStringV(buf, ARRAYSIZE(buf), fmt, args); const char* text_end = buf + ImFormatStringV(buf, IM_ARRAYSIZE(buf), fmt, args);
TextUnformatted(buf, text_end); TextUnformatted(buf, text_end);
} }
@ -2475,7 +2506,7 @@ void LabelText(const char* label, const char* fmt, ...)
va_list args; va_list args;
va_start(args, fmt); va_start(args, fmt);
const char* text_begin = &buf[0]; const char* text_begin = &buf[0];
const char* text_end = text_begin + ImFormatStringV(buf, ARRAYSIZE(buf), fmt, args); const char* text_end = text_begin + ImFormatStringV(buf, IM_ARRAYSIZE(buf), fmt, args);
va_end(args); va_end(args);
const ImVec2 text_size = CalcTextSize(label); const ImVec2 text_size = CalcTextSize(label);
@ -2783,7 +2814,7 @@ void BulletText(const char* fmt, ...)
va_list args; va_list args;
va_start(args, fmt); va_start(args, fmt);
const char* text_begin = buf; const char* text_begin = buf;
const char* text_end = text_begin + ImFormatStringV(buf, ARRAYSIZE(buf), fmt, args); const char* text_end = text_begin + ImFormatStringV(buf, IM_ARRAYSIZE(buf), fmt, args);
va_end(args); va_end(args);
const float line_height = window->FontSize(); const float line_height = window->FontSize();
@ -2805,7 +2836,7 @@ bool TreeNode(const char* str_id, const char* fmt, ...)
static char buf[1024]; static char buf[1024];
va_list args; va_list args;
va_start(args, fmt); va_start(args, fmt);
ImFormatStringV(buf, ARRAYSIZE(buf), fmt, args); ImFormatStringV(buf, IM_ARRAYSIZE(buf), fmt, args);
va_end(args); va_end(args);
if (!str_id || !str_id[0]) if (!str_id || !str_id[0])
@ -2826,7 +2857,7 @@ bool TreeNode(const void* ptr_id, const char* fmt, ...)
static char buf[1024]; static char buf[1024];
va_list args; va_list args;
va_start(args, fmt); va_start(args, fmt);
ImFormatStringV(buf, ARRAYSIZE(buf), fmt, args); ImFormatStringV(buf, IM_ARRAYSIZE(buf), fmt, args);
va_end(args); va_end(args);
if (!ptr_id) if (!ptr_id)
@ -2986,8 +3017,8 @@ bool SliderFloat(const char* label, float* v, float v_min, float v_max, const ch
if (v_min * v_max < 0.0f) if (v_min * v_max < 0.0f)
{ {
// Different sign // Different sign
const float linear_dist_min_to_0 = powf(abs(0.0f - v_min), 1.0f/power); const float linear_dist_min_to_0 = powf(fabsf(0.0f - v_min), 1.0f/power);
const float linear_dist_max_to_0 = powf(abs(v_max - 0.0f), 1.0f/power); const float linear_dist_max_to_0 = powf(fabsf(v_max - 0.0f), 1.0f/power);
linear_zero_pos = linear_dist_min_to_0 / (linear_dist_min_to_0+linear_dist_max_to_0); linear_zero_pos = linear_dist_min_to_0 / (linear_dist_min_to_0+linear_dist_max_to_0);
} }
else else
@ -3019,12 +3050,12 @@ bool SliderFloat(const char* label, float* v, float v_min, float v_max, const ch
if (start_text_input || (g.ActiveId == id && id == g.SliderAsInputTextId)) if (start_text_input || (g.ActiveId == id && id == g.SliderAsInputTextId))
{ {
char text_buf[64]; char text_buf[64];
ImFormatString(text_buf, ARRAYSIZE(text_buf), "%.*f", decimal_precision, *v); ImFormatString(text_buf, IM_ARRAYSIZE(text_buf), "%.*f", decimal_precision, *v);
g.ActiveId = g.SliderAsInputTextId; g.ActiveId = g.SliderAsInputTextId;
g.HoveredId = 0; g.HoveredId = 0;
window->FocusItemUnregister(); // Our replacement slider will override the focus ID (that we needed to declare previously to allow for a TAB focus to happen before we got selected) window->FocusItemUnregister(); // Our replacement slider will override the focus ID (that we needed to declare previously to allow for a TAB focus to happen before we got selected)
value_changed = ImGui::InputText(label, text_buf, ARRAYSIZE(text_buf), ImGuiInputTextFlags_CharsDecimal | ImGuiInputTextFlags_AutoSelectAll | ImGuiInputTextFlags_AlignCenter); value_changed = ImGui::InputText(label, text_buf, IM_ARRAYSIZE(text_buf), ImGuiInputTextFlags_CharsDecimal | ImGuiInputTextFlags_AutoSelectAll | ImGuiInputTextFlags_AlignCenter);
if (g.SliderAsInputTextId == 0) if (g.SliderAsInputTextId == 0)
{ {
// First frame // First frame
@ -3057,7 +3088,7 @@ bool SliderFloat(const char* label, float* v, float v_min, float v_max, const ch
if (!is_unbound) if (!is_unbound)
{ {
const float normalized_pos = ImClamp((g.IO.MousePos.x - slider_effective_x1) / slider_effective_w, 0.0f, 1.0f); const float normalized_pos = ImClamp((g.IO.MousePos.x - slider_effective_x1) / slider_effective_w, 0.0f, 1.0f);
// Linear slider // Linear slider
//float new_value = ImLerp(v_min, v_max, normalized_pos); //float new_value = ImLerp(v_min, v_max, normalized_pos);
@ -3073,9 +3104,11 @@ bool SliderFloat(const char* label, float* v, float v_min, float v_max, const ch
else else
{ {
// Positive: rescale to the positive range before powering // Positive: rescale to the positive range before powering
float a = normalized_pos; float a;
if (abs(linear_zero_pos - 1.0f) > 1.e-6) if (fabsf(linear_zero_pos - 1.0f) > 1.e-6)
a = (a - linear_zero_pos) / (1.0f - linear_zero_pos); a = (normalized_pos - linear_zero_pos) / (1.0f - linear_zero_pos);
else
a = normalized_pos;
a = powf(a, power); a = powf(a, power);
new_value = ImLerp(ImMax(v_min,0.0f), v_max, a); new_value = ImLerp(ImMax(v_min,0.0f), v_max, a);
} }
@ -3132,7 +3165,7 @@ bool SliderFloat(const char* label, float* v, float v_min, float v_max, const ch
} }
char value_buf[64]; char value_buf[64];
ImFormatString(value_buf, ARRAYSIZE(value_buf), display_format, *v); ImFormatString(value_buf, IM_ARRAYSIZE(value_buf), display_format, *v);
RenderText(ImVec2(slider_bb.GetCenter().x-CalcTextSize(value_buf).x*0.5f, frame_bb.Min.y + style.FramePadding.y), value_buf); RenderText(ImVec2(slider_bb.GetCenter().x-CalcTextSize(value_buf).x*0.5f, frame_bb.Min.y + style.FramePadding.y), value_buf);
RenderText(ImVec2(frame_bb.Max.x + style.ItemInnerSpacing.x, slider_bb.Min.y), label); RenderText(ImVec2(frame_bb.Max.x + style.ItemInnerSpacing.x, slider_bb.Min.y), label);
@ -3158,6 +3191,38 @@ bool SliderInt(const char* label, int* v, int v_min, int v_max, const char* disp
return changed; return changed;
} }
bool SliderFloat2(const char* label, float v[2], float v_min, float v_max, const char* display_format, float power)
{
ImGuiState& g = GImGui;
ImGuiWindow* window = GetCurrentWindow();
if (window->Collapsed)
return false;
const ImGuiStyle& style = g.Style;
bool value_changed = false;
ImGui::PushID(label);
const int components = 2;
const float w_full = window->DC.ItemWidth.back();
const float w_item_one = ImMax(1.0f, (float)(int)((w_full - (style.FramePadding.x*2.0f+style.ItemInnerSpacing.x)*(components-1)) / (float)components));
const float w_item_last = ImMax(1.0f, (float)(int)(w_full - (w_item_one+style.FramePadding.x*2.0f+style.ItemInnerSpacing.x)*(components-1)));
ImGui::PushItemWidth(w_item_one);
value_changed |= ImGui::SliderFloat("##X", &v[0], v_min, v_max, display_format, power);
ImGui::SameLine(0, 0);
ImGui::PopItemWidth();
ImGui::PushItemWidth(w_item_last);
value_changed |= ImGui::SliderFloat("##Y", &v[1], v_min, v_max, display_format, power);
ImGui::SameLine(0, 0);
ImGui::PopItemWidth();
ImGui::TextUnformatted(label, FindTextDisplayEnd(label));
ImGui::PopID();
return value_changed;
}
bool SliderFloat3(const char* label, float v[3], float v_min, float v_max, const char* display_format, float power) bool SliderFloat3(const char* label, float v[3], float v_min, float v_max, const char* display_format, float power)
{ {
ImGuiState& g = GImGui; ImGuiState& g = GImGui;
@ -3168,7 +3233,6 @@ bool SliderFloat3(const char* label, float v[3], float v_min, float v_max, const
const ImGuiStyle& style = g.Style; const ImGuiStyle& style = g.Style;
bool value_changed = false; bool value_changed = false;
ImGui::PushID(label); ImGui::PushID(label);
const int components = 3; const int components = 3;
@ -3191,7 +3255,6 @@ bool SliderFloat3(const char* label, float v[3], float v_min, float v_max, const
ImGui::TextUnformatted(label, FindTextDisplayEnd(label)); ImGui::TextUnformatted(label, FindTextDisplayEnd(label));
ImGui::PopID(); ImGui::PopID();
return value_changed; return value_changed;
} }
@ -3571,11 +3634,11 @@ bool InputFloat(const char* label, float *v, float step, float step_fast, int de
char buf[64]; char buf[64];
if (decimal_precision < 0) if (decimal_precision < 0)
ImFormatString(buf, ARRAYSIZE(buf), "%f", *v); // Ideally we'd have a minimum decimal precision of 1 to visually denote that it is a float, while hiding non-significant digits? ImFormatString(buf, IM_ARRAYSIZE(buf), "%f", *v); // Ideally we'd have a minimum decimal precision of 1 to visually denote that it is a float, while hiding non-significant digits?
else else
ImFormatString(buf, ARRAYSIZE(buf), "%.*f", decimal_precision, *v); ImFormatString(buf, IM_ARRAYSIZE(buf), "%.*f", decimal_precision, *v);
bool value_changed = false; bool value_changed = false;
if (ImGui::InputText("", buf, ARRAYSIZE(buf), ImGuiInputTextFlags_CharsDecimal|ImGuiInputTextFlags_AlignCenter|ImGuiInputTextFlags_AutoSelectAll)) if (ImGui::InputText("", buf, IM_ARRAYSIZE(buf), ImGuiInputTextFlags_CharsDecimal|ImGuiInputTextFlags_AlignCenter|ImGuiInputTextFlags_AutoSelectAll))
{ {
ApplyNumericalTextInput(buf, v); ApplyNumericalTextInput(buf, v);
value_changed = true; value_changed = true;
@ -3680,7 +3743,7 @@ bool InputText(const char* label, char* buf, size_t buf_size, ImGuiInputTextFlag
bool cancel_edit = false; bool cancel_edit = false;
if (g.ActiveId == id) if (g.ActiveId == id)
{ {
edit_state.BufSize = buf_size < ARRAYSIZE(edit_state.Text) ? buf_size : ARRAYSIZE(edit_state.Text); edit_state.BufSize = buf_size < IM_ARRAYSIZE(edit_state.Text) ? buf_size : IM_ARRAYSIZE(edit_state.Text);
edit_state.Font = window->Font(); edit_state.Font = window->Font();
edit_state.FontSize = window->FontSize(); edit_state.FontSize = window->FontSize();
@ -3763,7 +3826,7 @@ bool InputText(const char* label, char* buf, size_t buf_size, ImGuiInputTextFlag
else if (g.IO.InputCharacters[0]) else if (g.IO.InputCharacters[0])
{ {
// Text input // Text input
for (int n = 0; n < ARRAYSIZE(g.IO.InputCharacters) && g.IO.InputCharacters[n]; n++) for (int n = 0; n < IM_ARRAYSIZE(g.IO.InputCharacters) && g.IO.InputCharacters[n]; n++)
{ {
const char c = g.IO.InputCharacters[n]; const char c = g.IO.InputCharacters[n];
if (c) if (c)
@ -3840,6 +3903,38 @@ bool InputText(const char* label, char* buf, size_t buf_size, ImGuiInputTextFlag
return value_changed; return value_changed;
} }
bool InputFloat2(const char* label, float v[2], int decimal_precision)
{
ImGuiState& g = GImGui;
ImGuiWindow* window = GetCurrentWindow();
if (window->Collapsed)
return false;
const ImGuiStyle& style = g.Style;
bool value_changed = false;
ImGui::PushID(label);
const int components = 2;
const float w_full = window->DC.ItemWidth.back();
const float w_item_one = ImMax(1.0f, (float)(int)((w_full - (style.FramePadding.x*2.0f+style.ItemInnerSpacing.x) * (components-1)) / (float)components));
const float w_item_last = ImMax(1.0f, (float)(int)(w_full - (w_item_one+style.FramePadding.x*2.0f+style.ItemInnerSpacing.x) * (components-1)));
ImGui::PushItemWidth(w_item_one);
value_changed |= ImGui::InputFloat("##X", &v[0], 0, 0, decimal_precision);
ImGui::SameLine(0, 0);
ImGui::PopItemWidth();
ImGui::PushItemWidth(w_item_last);
value_changed |= ImGui::InputFloat("##Y", &v[1], 0, 0, decimal_precision);
ImGui::SameLine(0, 0);
ImGui::PopItemWidth();
ImGui::TextUnformatted(label, FindTextDisplayEnd(label));
ImGui::PopID();
return value_changed;
}
bool InputFloat3(const char* label, float v[3], int decimal_precision) bool InputFloat3(const char* label, float v[3], int decimal_precision)
{ {
ImGuiState& g = GImGui; ImGuiState& g = GImGui;
@ -3850,7 +3945,6 @@ bool InputFloat3(const char* label, float v[3], int decimal_precision)
const ImGuiStyle& style = g.Style; const ImGuiStyle& style = g.Style;
bool value_changed = false; bool value_changed = false;
ImGui::PushID(label); ImGui::PushID(label);
const int components = 3; const int components = 3;
@ -3873,7 +3967,6 @@ bool InputFloat3(const char* label, float v[3], int decimal_precision)
ImGui::TextUnformatted(label, FindTextDisplayEnd(label)); ImGui::TextUnformatted(label, FindTextDisplayEnd(label));
ImGui::PopID(); ImGui::PopID();
return value_changed; return value_changed;
} }
@ -3982,6 +4075,7 @@ bool Combo(const char* label, int* current_item, bool (*items_getter)(void*, int
ImGuiWindowFlags flags = ImGuiWindowFlags_ComboBox | ((window->Flags & ImGuiWindowFlags_ShowBorders) ? ImGuiWindowFlags_ShowBorders : 0); ImGuiWindowFlags flags = ImGuiWindowFlags_ComboBox | ((window->Flags & ImGuiWindowFlags_ShowBorders) ? ImGuiWindowFlags_ShowBorders : 0);
ImGui::BeginChild("#ComboBox", popup_aabb.GetSize(), false, flags); ImGui::BeginChild("#ComboBox", popup_aabb.GetSize(), false, flags);
ImGuiWindow* child_window = GetCurrentWindow(); ImGuiWindow* child_window = GetCurrentWindow();
ImGui::Spacing();
bool combo_item_active = false; bool combo_item_active = false;
combo_item_active |= (g.ActiveId == child_window->GetID("#SCROLLY")); combo_item_active |= (g.ActiveId == child_window->GetID("#SCROLLY"));
@ -4164,7 +4258,7 @@ bool ColorEdit4(const char* label, float col[4], bool alpha)
else else
sprintf(buf, "#%02X%02X%02X", ix, iy, iz); sprintf(buf, "#%02X%02X%02X", ix, iy, iz);
ImGui::PushItemWidth(w_slider_all - g.Style.ItemInnerSpacing.x); ImGui::PushItemWidth(w_slider_all - g.Style.ItemInnerSpacing.x);
value_changed |= ImGui::InputText("##Text", buf, ARRAYSIZE(buf), ImGuiInputTextFlags_CharsHexadecimal); value_changed |= ImGui::InputText("##Text", buf, IM_ARRAYSIZE(buf), ImGuiInputTextFlags_CharsHexadecimal);
ImGui::PopItemWidth(); ImGui::PopItemWidth();
char* p = buf; char* p = buf;
while (*p == '#' || *p == ' ' || *p == '\t') while (*p == '#' || *p == ' ' || *p == '\t')
@ -4322,6 +4416,7 @@ bool IsClipped(ImVec2 item_size)
static bool ClipAdvance(const ImGuiAabb& bb) static bool ClipAdvance(const ImGuiAabb& bb)
{ {
ImGuiWindow* window = GetCurrentWindow(); ImGuiWindow* window = GetCurrentWindow();
window->DC.LastItemAabb = bb;
if (ImGui::IsClipped(bb)) if (ImGui::IsClipped(bb))
{ {
window->DC.LastItemHovered = false; window->DC.LastItemHovered = false;
@ -4442,7 +4537,8 @@ void Columns(int columns_count, const char* id, bool border)
// Draw before resize so our items positioning are in sync with the line // Draw before resize so our items positioning are in sync with the line
const ImU32 col = window->Color(held ? ImGuiCol_ColumnActive : hovered ? ImGuiCol_ColumnHovered : ImGuiCol_Column); const ImU32 col = window->Color(held ? ImGuiCol_ColumnActive : hovered ? ImGuiCol_ColumnHovered : ImGuiCol_Column);
window->DrawList->AddLine(ImVec2(x, y1), ImVec2(x, y2), col); const float xi = (float)(int)x;
window->DrawList->AddLine(ImVec2(xi, y1), ImVec2(xi, y2), col);
if (held) if (held)
{ {
@ -4610,7 +4706,7 @@ void ImDrawList::AddVtx(const ImVec2& pos, ImU32 col)
{ {
vtx_write->pos = pos; vtx_write->pos = pos;
vtx_write->col = col; vtx_write->col = col;
vtx_write->uv = IMDRAW_TEX_UV_FOR_WHITE; vtx_write->uv = IMGUI_FONT_TEX_UV_FOR_WHITE;
vtx_write++; vtx_write++;
} }
@ -4643,9 +4739,9 @@ void ImDrawList::AddArc(const ImVec2& center, float rad, ImU32 col, int a_min, i
static bool circle_vtx_builds = false; static bool circle_vtx_builds = false;
if (!circle_vtx_builds) if (!circle_vtx_builds)
{ {
for (int i = 0; i < ARRAYSIZE(circle_vtx); i++) for (int i = 0; i < IM_ARRAYSIZE(circle_vtx); i++)
{ {
const float a = ((float)i / (float)ARRAYSIZE(circle_vtx)) * 2*PI; const float a = ((float)i / (float)IM_ARRAYSIZE(circle_vtx)) * 2*PI;
circle_vtx[i].x = cos(a + PI); circle_vtx[i].x = cos(a + PI);
circle_vtx[i].y = sin(a + PI); circle_vtx[i].y = sin(a + PI);
} }
@ -4657,8 +4753,8 @@ void ImDrawList::AddArc(const ImVec2& center, float rad, ImU32 col, int a_min, i
ReserveVertices((a_max-a_min) * 3); ReserveVertices((a_max-a_min) * 3);
for (int a = a_min; a < a_max; a++) for (int a = a_min; a < a_max; a++)
{ {
AddVtx(center + circle_vtx[a % ARRAYSIZE(circle_vtx)] * rad, col); AddVtx(center + circle_vtx[a % IM_ARRAYSIZE(circle_vtx)] * rad, col);
AddVtx(center + circle_vtx[(a+1) % ARRAYSIZE(circle_vtx)] * rad, col); AddVtx(center + circle_vtx[(a+1) % IM_ARRAYSIZE(circle_vtx)] * rad, col);
AddVtx(center + third_point_offset, col); AddVtx(center + third_point_offset, col);
} }
} }
@ -4666,7 +4762,7 @@ void ImDrawList::AddArc(const ImVec2& center, float rad, ImU32 col, int a_min, i
{ {
ReserveVertices((a_max-a_min) * 6); ReserveVertices((a_max-a_min) * 6);
for (int a = a_min; a < a_max; a++) for (int a = a_min; a < a_max; a++)
AddVtxLine(center + circle_vtx[a % ARRAYSIZE(circle_vtx)] * rad, center + circle_vtx[(a+1) % ARRAYSIZE(circle_vtx)] * rad, col); AddVtxLine(center + circle_vtx[a % IM_ARRAYSIZE(circle_vtx)] * rad, center + circle_vtx[(a+1) % IM_ARRAYSIZE(circle_vtx)] * rad, col);
} }
} }
@ -4675,10 +4771,10 @@ void ImDrawList::AddRect(const ImVec2& a, const ImVec2& b, ImU32 col, float roun
if ((col >> 24) == 0) if ((col >> 24) == 0)
return; return;
//const float r = ImMin(rounding, ImMin(abs(b.x-a.x), abs(b.y-a.y))*0.5f); //const float r = ImMin(rounding, ImMin(fabsf(b.x-a.x), fabsf(b.y-a.y))*0.5f);
float r = rounding; float r = rounding;
r = ImMin(r, abs(b.x-a.x) * ( ((rounding_corners&(1|2))==(1|2)) || ((rounding_corners&(4|8))==(4|8)) ? 0.5f : 1.0f )); r = ImMin(r, fabsf(b.x-a.x) * ( ((rounding_corners&(1|2))==(1|2)) || ((rounding_corners&(4|8))==(4|8)) ? 0.5f : 1.0f ));
r = ImMin(r, abs(b.y-a.y) * ( ((rounding_corners&(1|8))==(1|8)) || ((rounding_corners&(2|4))==(2|4)) ? 0.5f : 1.0f )); r = ImMin(r, fabsf(b.y-a.y) * ( ((rounding_corners&(1|8))==(1|8)) || ((rounding_corners&(2|4))==(2|4)) ? 0.5f : 1.0f ));
if (r == 0.0f || rounding_corners == 0) if (r == 0.0f || rounding_corners == 0)
{ {
@ -4708,10 +4804,10 @@ void ImDrawList::AddRectFilled(const ImVec2& a, const ImVec2& b, ImU32 col, floa
if ((col >> 24) == 0) if ((col >> 24) == 0)
return; return;
//const float r = ImMin(rounding, ImMin(abs(b.x-a.x), abs(b.y-a.y))*0.5f); //const float r = ImMin(rounding, ImMin(fabsf(b.x-a.x), fabsf(b.y-a.y))*0.5f);
float r = rounding; float r = rounding;
r = ImMin(r, abs(b.x-a.x) * ( ((rounding_corners&(1|2))==(1|2)) || ((rounding_corners&(4|8))==(4|8)) ? 0.5f : 1.0f )); r = ImMin(r, fabsf(b.x-a.x) * ( ((rounding_corners&(1|2))==(1|2)) || ((rounding_corners&(4|8))==(4|8)) ? 0.5f : 1.0f ));
r = ImMin(r, abs(b.y-a.y) * ( ((rounding_corners&(1|8))==(1|8)) || ((rounding_corners&(2|4))==(2|4)) ? 0.5f : 1.0f )); r = ImMin(r, fabsf(b.y-a.y) * ( ((rounding_corners&(1|8))==(1|8)) || ((rounding_corners&(2|4))==(2|4)) ? 0.5f : 1.0f ));
if (r == 0.0f || rounding_corners == 0) if (r == 0.0f || rounding_corners == 0)
{ {
@ -5104,6 +5200,81 @@ void ImBitmapFont::RenderText(float size, ImVec2 pos, ImU32 col, const ImVec4& c
} }
} }
//-----------------------------------------------------------------------------
// PLATFORM DEPENDANT HELPERS
//-----------------------------------------------------------------------------
#if defined(_MSC_VER) && !defined(IMGUI_DISABLE_WIN32_DEFAULT_CLIPBOARD_FUNCS)
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
// Win32 API clipboard implementation
static const char* GetClipboardTextFn_DefaultImpl()
{
static char* buf_local = NULL;
if (buf_local)
{
free(buf_local);
buf_local = NULL;
}
if (!OpenClipboard(NULL))
return NULL;
HANDLE buf_handle = GetClipboardData(CF_TEXT);
if (buf_handle == NULL)
return NULL;
if (char* buf_global = (char*)GlobalLock(buf_handle))
buf_local = strdup(buf_global);
GlobalUnlock(buf_handle);
CloseClipboard();
return buf_local;
}
// Win32 API clipboard implementation
static void SetClipboardTextFn_DefaultImpl(const char* text, const char* text_end)
{
if (!OpenClipboard(NULL))
return;
if (!text_end)
text_end = text + strlen(text);
const int buf_length = (text_end - text) + 1;
HGLOBAL buf_handle = GlobalAlloc(GMEM_MOVEABLE, buf_length * sizeof(char));
if (buf_handle == NULL)
return;
char* buf_global = (char *)GlobalLock(buf_handle);
memcpy(buf_global, text, text_end - text);
buf_global[text_end - text] = 0;
GlobalUnlock(buf_handle);
EmptyClipboard();
SetClipboardData(CF_TEXT, buf_handle);
CloseClipboard();
}
#else
// Local ImGui-only clipboard implementation, if user hasn't defined better clipboard handlers
static const char* GetClipboardTextFn_DefaultImpl()
{
return GImGui.PrivateClipboard;
}
// Local ImGui-only clipboard implementation, if user hasn't defined better clipboard handlers
static void SetClipboardTextFn_DefaultImpl(const char* text, const char* text_end)
{
if (GImGui.PrivateClipboard)
{
free(GImGui.PrivateClipboard);
GImGui.PrivateClipboard = NULL;
}
if (!text_end)
text_end = text + strlen(text);
GImGui.PrivateClipboard = (char*)malloc(text_end - text + 1);
memcpy(GImGui.PrivateClipboard, text, text_end - text);
GImGui.PrivateClipboard[text_end - text] = 0;
}
#endif
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// HELP // HELP
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
@ -5282,15 +5453,18 @@ void ShowTestWindow(bool* open)
const char* items[] = { "AAAA", "BBBB", "CCCC", "DDDD", "EEEE", "FFFF", "GGGG", "HHHH", "IIII", "JJJJ", "KKKK" }; const char* items[] = { "AAAA", "BBBB", "CCCC", "DDDD", "EEEE", "FFFF", "GGGG", "HHHH", "IIII", "JJJJ", "KKKK" };
static int item2 = -1; static int item2 = -1;
ImGui::Combo("combo scroll", &item2, items, ARRAYSIZE(items)); ImGui::Combo("combo scroll", &item2, items, IM_ARRAYSIZE(items));
static char str0[128] = "Hello, world!"; static char str0[128] = "Hello, world!";
static int i0=123; static int i0=123;
static float f0=0.001f; static float f0=0.001f;
ImGui::InputText("string", str0, ARRAYSIZE(str0)); ImGui::InputText("string", str0, IM_ARRAYSIZE(str0));
ImGui::InputInt("input int", &i0); ImGui::InputInt("input int", &i0);
ImGui::InputFloat("input float", &f0, 0.01f, 1.0f); ImGui::InputFloat("input float", &f0, 0.01f, 1.0f);
//static float vec2b[3] = { 0.10f, 0.20f };
//ImGui::InputFloat2("input float2", vec2b);
static float vec3b[3] = { 0.10f, 0.20f, 0.30f }; static float vec3b[3] = { 0.10f, 0.20f, 0.30f };
ImGui::InputFloat3("input float3", vec3b); ImGui::InputFloat3("input float3", vec3b);
@ -5310,6 +5484,9 @@ void ShowTestWindow(bool* open)
static float angle = 0.0f; static float angle = 0.0f;
ImGui::SliderAngle("angle", &angle); ImGui::SliderAngle("angle", &angle);
//static float vec2a[3] = { 0.10f, 0.20f };
//ImGui::SliderFloat2("slider float2", vec2a, 0.0f, 1.0f);
static float vec3a[3] = { 0.10f, 0.20f, 0.30f }; static float vec3a[3] = { 0.10f, 0.20f, 0.30f };
ImGui::SliderFloat3("slider float3", vec3a, 0.0f, 1.0f); ImGui::SliderFloat3("slider float3", vec3a, 0.0f, 1.0f);
@ -5324,7 +5501,7 @@ void ShowTestWindow(bool* open)
if (ImGui::CollapsingHeader("Graphs widgets")) if (ImGui::CollapsingHeader("Graphs widgets"))
{ {
static float arr[] = { 0.6f, 0.1f, 1.0f, 0.5f, 0.92f, 0.1f, 0.2f }; static float arr[] = { 0.6f, 0.1f, 1.0f, 0.5f, 0.92f, 0.1f, 0.2f };
ImGui::PlotLines("Frame Times", arr, ARRAYSIZE(arr)); ImGui::PlotLines("Frame Times", arr, IM_ARRAYSIZE(arr));
static bool pause; static bool pause;
static ImVector<float> values; if (values.empty()) { values.resize(100); memset(&values.front(), 0, values.size()*sizeof(float)); } static ImVector<float> values; if (values.empty()) { values.resize(100); memset(&values.front(), 0, values.size()*sizeof(float)); }
@ -5342,10 +5519,10 @@ void ShowTestWindow(bool* open)
phase += 0.10f*values_offset; phase += 0.10f*values_offset;
} }
} }
ImGui::PlotLines("Frame Times", &values.front(), values.size(), values_offset, "avg 0.0", -1.0f, 1.0f, ImVec2(0,70)); ImGui::PlotLines("Frame Times", &values.front(), (int)values.size(), values_offset, "avg 0.0", -1.0f, 1.0f, ImVec2(0,70));
ImGui::SameLine(); ImGui::Checkbox("pause", &pause); ImGui::SameLine(); ImGui::Checkbox("pause", &pause);
ImGui::PlotHistogram("Histogram", arr, ARRAYSIZE(arr), 0, NULL, 0.0f, 1.0f, ImVec2(0,70)); ImGui::PlotHistogram("Histogram", arr, IM_ARRAYSIZE(arr), 0, NULL, 0.0f, 1.0f, ImVec2(0,70));
} }
if (ImGui::CollapsingHeader("Widgets on same line")) if (ImGui::CollapsingHeader("Widgets on same line"))
@ -5435,7 +5612,7 @@ void ShowTestWindow(bool* open)
for (int i = 0; i < 100; i++) for (int i = 0; i < 100; i++)
{ {
char buf[32]; char buf[32];
ImFormatString(buf, ARRAYSIZE(buf), "%08x", i*5731); ImFormatString(buf, IM_ARRAYSIZE(buf), "%08x", i*5731);
ImGui::Button(buf); ImGui::Button(buf);
ImGui::NextColumn(); ImGui::NextColumn();
} }
@ -5534,7 +5711,7 @@ void ShowTestWindow(bool* open)
static ImGuiTextFilter filter; static ImGuiTextFilter filter;
filter.Draw(); filter.Draw();
const char* lines[] = { "aaa1.c", "bbb1.c", "ccc1.c", "aaa2.cpp", "bbb2.cpp", "ccc2.cpp", "abc.h", "hello, world" }; const char* lines[] = { "aaa1.c", "bbb1.c", "ccc1.c", "aaa2.cpp", "bbb2.cpp", "ccc2.cpp", "abc.h", "hello, world" };
for (size_t i = 0; i < ARRAYSIZE(lines); i++) for (size_t i = 0; i < IM_ARRAYSIZE(lines); i++)
if (filter.PassFilter(lines[i])) if (filter.PassFilter(lines[i]))
ImGui::BulletText("%s", lines[i]); ImGui::BulletText("%s", lines[i]);
} }

31
imgui.h
View File

@ -85,9 +85,9 @@ public:
inline void clear() { if (_data) { _size = _capacity = 0; free(_data); _data = NULL; } } inline void clear() { if (_data) { _size = _capacity = 0; free(_data); _data = NULL; } }
inline iterator begin() { return _data; } inline iterator begin() { return _data; }
inline const iterator begin() const { return _data; } inline const_iterator begin() const { return _data; }
inline iterator end() { return _data + _size; } inline iterator end() { return _data + _size; }
inline const iterator end() const { return _data + _size; } inline const_iterator end() const { return _data + _size; }
inline value_type& front() { return at(0); } inline value_type& front() { return at(0); }
inline const value_type& front() const { return at(0); } inline const value_type& front() const { return at(0); }
inline value_type& back() { IM_ASSERT(_size > 0); return at(_size-1); } inline value_type& back() { IM_ASSERT(_size > 0); return at(_size-1); }
@ -183,6 +183,7 @@ namespace ImGui
bool SmallButton(const char* label); bool SmallButton(const char* label);
bool CollapsingHeader(const char* label, const char* str_id = NULL, const bool display_frame = true, const bool default_open = false); bool CollapsingHeader(const char* label, const char* str_id = NULL, const bool display_frame = true, const bool default_open = false);
bool SliderFloat(const char* label, float* v, float v_min, float v_max, const char* display_format = "%.3f", float power = 1.0f); bool SliderFloat(const char* label, float* v, float v_min, float v_max, const char* display_format = "%.3f", float power = 1.0f);
bool SliderFloat2(const char* label, float v[2], float v_min, float v_max, const char* display_format = "%.3f", float power = 1.0f);
bool SliderFloat3(const char* label, float v[3], float v_min, float v_max, const char* display_format = "%.3f", float power = 1.0f); bool SliderFloat3(const char* label, float v[3], float v_min, float v_max, const char* display_format = "%.3f", float power = 1.0f);
bool SliderAngle(const char* label, float* v, float v_degrees_min = -360.0f, float v_degrees_max = +360.0f); // *v in radians bool SliderAngle(const char* label, float* v, float v_degrees_min = -360.0f, float v_degrees_max = +360.0f); // *v in radians
bool SliderInt(const char* label, int* v, int v_min, int v_max, const char* display_format = "%.0f"); bool SliderInt(const char* label, int* v, int v_min, int v_max, const char* display_format = "%.0f");
@ -193,6 +194,7 @@ namespace ImGui
bool RadioButton(const char* label, bool active); bool RadioButton(const char* label, bool active);
bool RadioButton(const char* label, int* v, int v_button); bool RadioButton(const char* label, int* v, int v_button);
bool InputFloat(const char* label, float* v, float step = 0.0f, float step_fast = 0.0f, int decimal_precision = -1); bool InputFloat(const char* label, float* v, float step = 0.0f, float step_fast = 0.0f, int decimal_precision = -1);
bool InputFloat2(const char* label, float v[2], int decimal_precision = -1);
bool InputFloat3(const char* label, float v[3], int decimal_precision = -1); bool InputFloat3(const char* label, float v[3], int decimal_precision = -1);
bool InputInt(const char* label, int* v, int step = 1, int step_fast = 100); bool InputInt(const char* label, int* v, int step = 1, int step_fast = 100);
bool InputText(const char* label, char* buf, size_t buf_size, ImGuiInputTextFlags flags = 0); bool InputText(const char* label, char* buf, size_t buf_size, ImGuiInputTextFlags flags = 0);
@ -230,6 +232,8 @@ namespace ImGui
void SetTooltip(const char* fmt, ...); // set tooltip under mouse-cursor, typically use with ImGui::IsHovered(). (currently no contention handling, last call win) void SetTooltip(const char* fmt, ...); // set tooltip under mouse-cursor, typically use with ImGui::IsHovered(). (currently no contention handling, last call win)
void SetNewWindowDefaultPos(ImVec2 pos); // set position of window that do void SetNewWindowDefaultPos(ImVec2 pos); // set position of window that do
bool IsHovered(); // was the last item active area hovered by mouse? bool IsHovered(); // was the last item active area hovered by mouse?
ImVec2 GetItemBoxMin(); // get bounding box of last item
ImVec2 GetItemBoxMax(); // get bounding box of last item
bool IsClipped(ImVec2 item_size); // to perform coarse clipping on user's side (as an optimisation) bool IsClipped(ImVec2 item_size); // to perform coarse clipping on user's side (as an optimisation)
bool IsKeyPressed(int key_index, bool repeat = true); // key_index into the keys_down[512] array, imgui doesn't know the semantic of each entry bool IsKeyPressed(int key_index, bool repeat = true); // key_index into the keys_down[512] array, imgui doesn't know the semantic of each entry
bool IsMouseClicked(int button, bool repeat = false); bool IsMouseClicked(int button, bool repeat = false);
@ -380,10 +384,16 @@ struct ImGuiIO
bool FontAllowScaling; // = false // Set to allow scaling text with CTRL+Wheel. bool FontAllowScaling; // = false // Set to allow scaling text with CTRL+Wheel.
float PixelCenterOffset; // = 0.5f // Set to 0.0f for DirectX <= 9, 0.5f for Direct3D >= 10 and OpenGL. float PixelCenterOffset; // = 0.5f // Set to 0.0f for DirectX <= 9, 0.5f for Direct3D >= 10 and OpenGL.
// Settings - Functions (fill once) // Settings - Rendering function (REQUIRED)
void (*RenderDrawListsFn)(ImDrawList** const draw_lists, int count); // Required // See example code if you are unsure of how to implement this.
const char* (*GetClipboardTextFn)(); // Required for clipboard support void (*RenderDrawListsFn)(ImDrawList** const draw_lists, int count);
void (*SetClipboardTextFn)(const char* text, const char* text_end); // Required for clipboard support (nb- the string is *NOT* zero-terminated at 'text_end')
// Settings - Clipboard Support
// Override to provide your clipboard handlers.
// On Windows architecture, defaults to use the native Win32 clipboard, otherwise default to use a ImGui private clipboard.
// NB- for SetClipboardTextFn, the string is *NOT* zero-terminated at 'text_end'
const char* (*GetClipboardTextFn)();
void (*SetClipboardTextFn)(const char* text, const char* text_end);
// Input - Fill before calling NewFrame() // Input - Fill before calling NewFrame()
ImVec2 MousePos; // Mouse position, in pixels (set to -1,-1 if no mouse / on another screen, etc.) ImVec2 MousePos; // Mouse position, in pixels (set to -1,-1 if no mouse / on another screen, etc.)
@ -505,8 +515,8 @@ struct ImDrawCmd
ImVec4 clip_rect; ImVec4 clip_rect;
}; };
#ifndef IMDRAW_TEX_UV_FOR_WHITE #ifndef IMGUI_FONT_TEX_UV_FOR_WHITE
#define IMDRAW_TEX_UV_FOR_WHITE ImVec2(0,0) #define IMGUI_FONT_TEX_UV_FOR_WHITE ImVec2(0.f,0.f)
#endif #endif
// sizeof() == 20 // sizeof() == 20
@ -521,8 +531,11 @@ struct ImDrawVert
// User is responsible for providing a renderer for this in ImGuiIO::RenderDrawListFn // User is responsible for providing a renderer for this in ImGuiIO::RenderDrawListFn
struct ImDrawList struct ImDrawList
{ {
ImVector<ImDrawCmd> commands; // This is what you have to render
ImVector<ImDrawCmd> commands; // commands
ImVector<ImDrawVert> vtx_buffer; // each command consume ImDrawCmd::vtx_count of those ImVector<ImDrawVert> vtx_buffer; // each command consume ImDrawCmd::vtx_count of those
// [Internal to ImGui]
ImVector<ImVec4> clip_rect_stack; // [internal] clip rect stack while building the command-list (so text command can perform clipping early on) ImVector<ImVec4> clip_rect_stack; // [internal] clip rect stack while building the command-list (so text command can perform clipping early on)
ImDrawVert* vtx_write; // [internal] point within vtx_buffer after each add command (to avoid using the ImVector<> operators too much) ImDrawVert* vtx_write; // [internal] point within vtx_buffer after each add command (to avoid using the ImVector<> operators too much)