Merge branch 'master' into docking

# Conflicts:
#	backends/imgui_impl_opengl3.cpp
#	examples/imgui_examples.sln
#	imgui.cpp
#	imgui.h
docking
ocornut 3 years ago
commit dedb381c51

@ -1,12 +1,12 @@
(Click "Preview" above ^ to turn URL into clickable links) (Click "Preview" above ^ to turn URL into clickable links)
1. PLEASE CAREFULLY READ: [FAQ](https://github.com/ocornut/imgui/blob/master/docs/FAQ.md) 1. FOR FIRST-TIME USERS ISSUES COMPILING/LINKING/RUNNING or LOADING FONTS, please use [GitHub Discussions](https://github.com/ocornut/imgui/discussions).
2. PLEASE CAREFULLY READ: [Issue Submitting Guidelines](https://github.com/ocornut/imgui/issues/2261) 2. PLEASE CAREFULLY READ: [FAQ](https://github.com/ocornut/imgui/blob/master/docs/FAQ.md)
3. FOR FIRST-TIME USERS ISSUES COMPILING/LINKING/RUNNING/LOADING FONTS, please use [GitHub Discussions](https://github.com/ocornut/imgui/discussions). 3. PLEASE CAREFULLY READ: [Issue Submitting Guidelines](https://github.com/ocornut/imgui/issues/2261)
4. PLEASE MAKE SURE that you have: read the FAQ; explored the contents of `ShowDemoWindow()` including the Examples menu; searched among Issues; used your IDE to search for keywords in all sources and text files; and read the link provided in (1) (2). 4. PLEASE MAKE SURE that you have: read the FAQ; explored the contents of `ShowDemoWindow()` including the Examples menu; searched among Issues; used your IDE to search for keywords in all sources and text files; and read the links above.
5. Be mindful that messages are being sent to the e-mail box of "Watching" users. Try to proof-read your messages before sending them. Edits are not seen by those users. 5. Be mindful that messages are being sent to the e-mail box of "Watching" users. Try to proof-read your messages before sending them. Edits are not seen by those users.

@ -1,6 +1,6 @@
(Click "Preview" to turn any http URL into a clickable link) (Click "Preview" to turn any http URL into a clickable link)
PLEASE CAREFULLY READ: 1. PLEASE CAREFULLY READ: [Issue Submitting Guidelines](https://github.com/ocornut/imgui/issues/2261)
https://github.com/ocornut/imgui/issues/2261
2. Clear this template before submitting your PR.
(Clear this template before submitting your PR)

@ -226,6 +226,18 @@ jobs:
make -C examples/example_null clean make -C examples/example_null clean
CXXFLAGS="$CXXFLAGS -m64 -Werror" CXX=clang++ make -C examples/example_null WITH_EXTRA_WARNINGS=1 CXXFLAGS="$CXXFLAGS -m64 -Werror" CXX=clang++ make -C examples/example_null WITH_EXTRA_WARNINGS=1
- name: Build example_null (extra warnings, empty IM_ASSERT)
run: |
cat > example_single_file.cpp <<'EOF'
#define IM_ASSERT(x)
#define IMGUI_IMPLEMENTATION
#include "misc/single_file/imgui_single_file.h"
#include "examples/example_null/main.cpp"
EOF
g++ -I. -Wall -Wformat -Wextra -Werror -Wno-zero-as-null-pointer-constant -Wno-double-promotion -Wno-variadic-macros -Wno-empty-body -o example_single_file example_single_file.cpp
- name: Build example_null (freetype) - name: Build example_null (freetype)
run: | run: |
make -C examples/example_null clean make -C examples/example_null clean

@ -171,9 +171,15 @@ void ImGui_ImplAllegro5_RenderDrawData(ImDrawData* draw_data)
} }
else else
{ {
// Draw // Project scissor/clipping rectangles into framebuffer space
ImVec2 clip_min(pcmd->ClipRect.x - clip_off.x, pcmd->ClipRect.y - clip_off.y);
ImVec2 clip_max(pcmd->ClipRect.z - clip_off.x, pcmd->ClipRect.w - clip_off.y);
if (clip_max.x < clip_min.x || clip_max.y < clip_min.y)
continue;
// Apply scissor/clipping rectangle, Draw
ALLEGRO_BITMAP* texture = (ALLEGRO_BITMAP*)pcmd->GetTexID(); ALLEGRO_BITMAP* texture = (ALLEGRO_BITMAP*)pcmd->GetTexID();
al_set_clipping_rectangle(pcmd->ClipRect.x - clip_off.x, pcmd->ClipRect.y - clip_off.y, pcmd->ClipRect.z - pcmd->ClipRect.x, pcmd->ClipRect.w - pcmd->ClipRect.y); al_set_clipping_rectangle(clip_min.x, clip_min.y, clip_max.x, clip_max.y);
al_draw_prim(&vertices[0], bd->VertexDecl, texture, idx_offset, idx_offset + pcmd->ElemCount, ALLEGRO_PRIM_TRIANGLE_LIST); al_draw_prim(&vertices[0], bd->VertexDecl, texture, idx_offset, idx_offset + pcmd->ElemCount, ALLEGRO_PRIM_TRIANGLE_LIST);
} }
idx_offset += pcmd->ElemCount; idx_offset += pcmd->ElemCount;

@ -259,8 +259,14 @@ void ImGui_ImplDX10_RenderDrawData(ImDrawData* draw_data)
} }
else else
{ {
// Project scissor/clipping rectangles into framebuffer space
ImVec2 clip_min(pcmd->ClipRect.x - clip_off.x, pcmd->ClipRect.y - clip_off.y);
ImVec2 clip_max(pcmd->ClipRect.z - clip_off.x, pcmd->ClipRect.w - clip_off.y);
if (clip_max.x < clip_min.x || clip_max.y < clip_min.y)
continue;
// Apply scissor/clipping rectangle // Apply scissor/clipping rectangle
const D3D10_RECT r = { (LONG)(pcmd->ClipRect.x - clip_off.x), (LONG)(pcmd->ClipRect.y - clip_off.y), (LONG)(pcmd->ClipRect.z - clip_off.x), (LONG)(pcmd->ClipRect.w - clip_off.y)}; const D3D10_RECT r = { (LONG)clip_min.x, (LONG)clip_min.y, (LONG)clip_max.x, (LONG)clip_max.y };
ctx->RSSetScissorRects(1, &r); ctx->RSSetScissorRects(1, &r);
// Bind texture, Draw // Bind texture, Draw

@ -269,8 +269,14 @@ void ImGui_ImplDX11_RenderDrawData(ImDrawData* draw_data)
} }
else else
{ {
// Project scissor/clipping rectangles into framebuffer space
ImVec2 clip_min(pcmd->ClipRect.x - clip_off.x, pcmd->ClipRect.y - clip_off.y);
ImVec2 clip_max(pcmd->ClipRect.z - clip_off.x, pcmd->ClipRect.w - clip_off.y);
if (clip_max.x < clip_min.x || clip_max.y < clip_min.y)
continue;
// Apply scissor/clipping rectangle // Apply scissor/clipping rectangle
const D3D11_RECT r = { (LONG)(pcmd->ClipRect.x - clip_off.x), (LONG)(pcmd->ClipRect.y - clip_off.y), (LONG)(pcmd->ClipRect.z - clip_off.x), (LONG)(pcmd->ClipRect.w - clip_off.y) }; const D3D11_RECT r = { (LONG)clip_min.x, (LONG)clip_min.y, (LONG)clip_max.x, (LONG)clip_max.y };
ctx->RSSetScissorRects(1, &r); ctx->RSSetScissorRects(1, &r);
// Bind texture, Draw // Bind texture, Draw

@ -337,16 +337,19 @@ void ImGui_ImplDX12_RenderDrawData(ImDrawData* draw_data, ID3D12GraphicsCommandL
} }
else else
{ {
// Apply Scissor, Bind texture, Draw // Project scissor/clipping rectangles into framebuffer space
const D3D12_RECT r = { (LONG)(pcmd->ClipRect.x - clip_off.x), (LONG)(pcmd->ClipRect.y - clip_off.y), (LONG)(pcmd->ClipRect.z - clip_off.x), (LONG)(pcmd->ClipRect.w - clip_off.y) }; ImVec2 clip_min(pcmd->ClipRect.x - clip_off.x, pcmd->ClipRect.y - clip_off.y);
if (r.right > r.left && r.bottom > r.top) ImVec2 clip_max(pcmd->ClipRect.z - clip_off.x, pcmd->ClipRect.w - clip_off.y);
{ if (clip_max.x < clip_min.x || clip_max.y < clip_min.y)
D3D12_GPU_DESCRIPTOR_HANDLE texture_handle = {}; continue;
texture_handle.ptr = (UINT64)pcmd->GetTexID();
ctx->SetGraphicsRootDescriptorTable(1, texture_handle); // Apply Scissor/clipping rectangle, Bind texture, Draw
ctx->RSSetScissorRects(1, &r); const D3D12_RECT r = { (LONG)clip_min.x, (LONG)clip_min.y, (LONG)clip_max.x, (LONG)clip_max.y };
ctx->DrawIndexedInstanced(pcmd->ElemCount, 1, pcmd->IdxOffset + global_idx_offset, pcmd->VtxOffset + global_vtx_offset, 0); D3D12_GPU_DESCRIPTOR_HANDLE texture_handle = {};
} texture_handle.ptr = (UINT64)pcmd->GetTexID();
ctx->SetGraphicsRootDescriptorTable(1, texture_handle);
ctx->RSSetScissorRects(1, &r);
ctx->DrawIndexedInstanced(pcmd->ElemCount, 1, pcmd->IdxOffset + global_idx_offset, pcmd->VtxOffset + global_vtx_offset, 0);
} }
} }
global_idx_offset += cmd_list->IdxBuffer.Size; global_idx_offset += cmd_list->IdxBuffer.Size;

@ -256,7 +256,14 @@ void ImGui_ImplDX9_RenderDrawData(ImDrawData* draw_data)
} }
else else
{ {
const RECT r = { (LONG)(pcmd->ClipRect.x - clip_off.x), (LONG)(pcmd->ClipRect.y - clip_off.y), (LONG)(pcmd->ClipRect.z - clip_off.x), (LONG)(pcmd->ClipRect.w - clip_off.y) }; // Project scissor/clipping rectangles into framebuffer space
ImVec2 clip_min(pcmd->ClipRect.x - clip_off.x, pcmd->ClipRect.y - clip_off.y);
ImVec2 clip_max(pcmd->ClipRect.z - clip_off.x, pcmd->ClipRect.w - clip_off.y);
if (clip_max.x < clip_min.x || clip_max.y < clip_min.y)
continue;
// Apply Scissor/clipping rectangle, Bind texture, Draw
const RECT r = { (LONG)clip_min.x, (LONG)clip_min.y, (LONG)clip_max.x, (LONG)clip_max.y };
const LPDIRECT3DTEXTURE9 texture = (LPDIRECT3DTEXTURE9)pcmd->GetTexID(); const LPDIRECT3DTEXTURE9 texture = (LPDIRECT3DTEXTURE9)pcmd->GetTexID();
bd->pd3dDevice->SetTexture(0, texture); bd->pd3dDevice->SetTexture(0, texture);
bd->pd3dDevice->SetScissorRect(&r); bd->pd3dDevice->SetScissorRect(&r);

@ -7,13 +7,14 @@
// Missing features: // Missing features:
// [ ] Renderer: Multi-viewport / platform windows. // [ ] Renderer: Multi-viewport / platform windows.
// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this. // You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
// Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need. // Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
// If you are new to Dear ImGui, read documentation from the docs/ folder + read the top of imgui.cpp. // If you are new to Dear ImGui, read documentation from the docs/ folder + read the top of imgui.cpp.
// Read online: https://github.com/ocornut/imgui/tree/master/docs // Read online: https://github.com/ocornut/imgui/tree/master/docs
// CHANGELOG // CHANGELOG
// (minor and older changes stripped away, please see git history for details) // (minor and older changes stripped away, please see git history for details)
// 2021-08-24: Metal: Fixed a crash when clipping rect larger than framebuffer is submitted. (#4464)
// 2021-05-19: Metal: Replaced direct access to ImDrawCmd::TextureId with a call to ImDrawCmd::GetTexID(). (will become a requirement) // 2021-05-19: Metal: Replaced direct access to ImDrawCmd::TextureId with a call to ImDrawCmd::GetTexID(). (will become a requirement)
// 2021-02-18: Metal: Change blending equation to preserve alpha in output buffer. // 2021-02-18: Metal: Change blending equation to preserve alpha in output buffer.
// 2021-01-25: Metal: Fixed texture storage mode when building on Mac Catalyst. // 2021-01-25: Metal: Fixed texture storage mode when building on Mac Catalyst.
@ -506,36 +507,37 @@ void ImGui_ImplMetal_DestroyDeviceObjects()
else else
{ {
// Project scissor/clipping rectangles into framebuffer space // Project scissor/clipping rectangles into framebuffer space
ImVec4 clip_rect; ImVec2 clip_min((pcmd->ClipRect.x - clip_off.x) * clip_scale.x, (pcmd->ClipRect.y - clip_off.y) * clip_scale.y);
clip_rect.x = (pcmd->ClipRect.x - clip_off.x) * clip_scale.x; ImVec2 clip_max((pcmd->ClipRect.z - clip_off.x) * clip_scale.x, (pcmd->ClipRect.w - clip_off.y) * clip_scale.y);
clip_rect.y = (pcmd->ClipRect.y - clip_off.y) * clip_scale.y;
clip_rect.z = (pcmd->ClipRect.z - clip_off.x) * clip_scale.x; // Clamp to viewport as setScissorRect() won't accept values that are off bounds
clip_rect.w = (pcmd->ClipRect.w - clip_off.y) * clip_scale.y; if (clip_min.x < 0.0f) { clip_min.x = 0.0f; }
if (clip_min.y < 0.0f) { clip_min.y = 0.0f; }
if (clip_rect.x < fb_width && clip_rect.y < fb_height && clip_rect.z >= 0.0f && clip_rect.w >= 0.0f) if (clip_max.x > fb_width) { clip_max.x = (float)fb_width; }
if (clip_max.y > fb_height) { clip_max.y = (float)fb_height; }
if (clip_max.x < clip_min.x || clip_max.y < clip_min.y)
continue;
// Apply scissor/clipping rectangle
MTLScissorRect scissorRect =
{ {
// Apply scissor/clipping rectangle .x = NSUInteger(clip_min.x),
MTLScissorRect scissorRect = .y = NSUInteger(clip_min.y),
{ .width = NSUInteger(clip_max.x - clip_min.x),
.x = NSUInteger(clip_rect.x), .height = NSUInteger(clip_max.y - clip_min.y)
.y = NSUInteger(clip_rect.y), };
.width = NSUInteger(clip_rect.z - clip_rect.x), [commandEncoder setScissorRect:scissorRect];
.height = NSUInteger(clip_rect.w - clip_rect.y)
}; // Bind texture, Draw
[commandEncoder setScissorRect:scissorRect]; if (ImTextureID tex_id = pcmd->GetTexID())
[commandEncoder setFragmentTexture:(__bridge id<MTLTexture>)(tex_id) atIndex:0];
// Bind texture, Draw [commandEncoder setVertexBufferOffset:(vertexBufferOffset + pcmd->VtxOffset * sizeof(ImDrawVert)) atIndex:0];
if (ImTextureID tex_id = pcmd->GetTexID()) [commandEncoder drawIndexedPrimitives:MTLPrimitiveTypeTriangle
[commandEncoder setFragmentTexture:(__bridge id<MTLTexture>)(tex_id) atIndex:0]; indexCount:pcmd->ElemCount
indexType:sizeof(ImDrawIdx) == 2 ? MTLIndexTypeUInt16 : MTLIndexTypeUInt32
[commandEncoder setVertexBufferOffset:(vertexBufferOffset + pcmd->VtxOffset * sizeof(ImDrawVert)) atIndex:0]; indexBuffer:indexBuffer.buffer
[commandEncoder drawIndexedPrimitives:MTLPrimitiveTypeTriangle indexBufferOffset:indexBufferOffset + pcmd->IdxOffset * sizeof(ImDrawIdx)];
indexCount:pcmd->ElemCount
indexType:sizeof(ImDrawIdx) == 2 ? MTLIndexTypeUInt16 : MTLIndexTypeUInt32
indexBuffer:indexBuffer.buffer
indexBufferOffset:indexBufferOffset + pcmd->IdxOffset * sizeof(ImDrawIdx)];
}
} }
} }

@ -211,21 +211,17 @@ void ImGui_ImplOpenGL2_RenderDrawData(ImDrawData* draw_data)
else else
{ {
// Project scissor/clipping rectangles into framebuffer space // Project scissor/clipping rectangles into framebuffer space
ImVec4 clip_rect; ImVec2 clip_min((pcmd->ClipRect.x - clip_off.x) * clip_scale.x, (pcmd->ClipRect.y - clip_off.y) * clip_scale.y);
clip_rect.x = (pcmd->ClipRect.x - clip_off.x) * clip_scale.x; ImVec2 clip_max((pcmd->ClipRect.z - clip_off.x) * clip_scale.x, (pcmd->ClipRect.w - clip_off.y) * clip_scale.y);
clip_rect.y = (pcmd->ClipRect.y - clip_off.y) * clip_scale.y; if (clip_max.x < clip_min.x || clip_max.y < clip_min.y)
clip_rect.z = (pcmd->ClipRect.z - clip_off.x) * clip_scale.x; continue;
clip_rect.w = (pcmd->ClipRect.w - clip_off.y) * clip_scale.y;
// Apply scissor/clipping rectangle (Y is inverted in OpenGL)
if (clip_rect.x < fb_width && clip_rect.y < fb_height && clip_rect.z >= 0.0f && clip_rect.w >= 0.0f) glScissor((int)clip_min.x, (int)(fb_height - clip_max.y), (int)(clip_max.x - clip_min.x), (int)(clip_max.y - clip_min.y));
{
// Apply scissor/clipping rectangle // Bind texture, Draw
glScissor((int)clip_rect.x, (int)(fb_height - clip_rect.w), (int)(clip_rect.z - clip_rect.x), (int)(clip_rect.w - clip_rect.y)); glBindTexture(GL_TEXTURE_2D, (GLuint)(intptr_t)pcmd->GetTexID());
glDrawElements(GL_TRIANGLES, (GLsizei)pcmd->ElemCount, sizeof(ImDrawIdx) == 2 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT, idx_buffer);
// Bind texture, Draw
glBindTexture(GL_TEXTURE_2D, (GLuint)(intptr_t)pcmd->GetTexID());
glDrawElements(GL_TRIANGLES, (GLsizei)pcmd->ElemCount, sizeof(ImDrawIdx) == 2 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT, idx_buffer);
}
} }
idx_buffer += pcmd->ElemCount; idx_buffer += pcmd->ElemCount;
} }

@ -16,6 +16,7 @@
// CHANGELOG // CHANGELOG
// (minor and older changes stripped away, please see git history for details) // (minor and older changes stripped away, please see git history for details)
// 2021-XX-XX: Platform: Added support for multiple windows via the ImGuiPlatformIO interface. // 2021-XX-XX: Platform: Added support for multiple windows via the ImGuiPlatformIO interface.
// 2021-08-23: OpenGL: Fixed ES 3.0 shader ("#version 300 es") use normal precision floats to avoid wobbly rendering at HD resolutions.
// 2021-08-19: OpenGL: Embed and use our own minimal GL loader (imgui_impl_opengl3_loader.h), removing requirement and support for third-party loader. // 2021-08-19: OpenGL: Embed and use our own minimal GL loader (imgui_impl_opengl3_loader.h), removing requirement and support for third-party loader.
// 2021-06-29: Reorganized backend to pull data from a single structure to facilitate usage with multiple-contexts (all g_XXXX access changed to bd->XXXX). // 2021-06-29: Reorganized backend to pull data from a single structure to facilitate usage with multiple-contexts (all g_XXXX access changed to bd->XXXX).
// 2021-06-25: OpenGL: Use OES_vertex_array extension on Emscripten + backup/restore current state. // 2021-06-25: OpenGL: Use OES_vertex_array extension on Emscripten + backup/restore current state.
@ -106,6 +107,9 @@
#include <GLES2/gl2ext.h> #include <GLES2/gl2ext.h>
#endif #endif
#elif defined(IMGUI_IMPL_OPENGL_ES3) #elif defined(IMGUI_IMPL_OPENGL_ES3)
#if defined(__APPLE__)
#include <TargetConditionals.h>
#endif
#if (defined(__APPLE__) && (TARGET_OS_IOS || TARGET_OS_TV)) #if (defined(__APPLE__) && (TARGET_OS_IOS || TARGET_OS_TV))
#include <OpenGLES/ES3/gl.h> // Use GL ES 3 #include <OpenGLES/ES3/gl.h> // Use GL ES 3
#else #else
@ -449,26 +453,22 @@ void ImGui_ImplOpenGL3_RenderDrawData(ImDrawData* draw_data)
else else
{ {
// Project scissor/clipping rectangles into framebuffer space // Project scissor/clipping rectangles into framebuffer space
ImVec4 clip_rect; ImVec2 clip_min((pcmd->ClipRect.x - clip_off.x) * clip_scale.x, (pcmd->ClipRect.y - clip_off.y) * clip_scale.y);
clip_rect.x = (pcmd->ClipRect.x - clip_off.x) * clip_scale.x; ImVec2 clip_max((pcmd->ClipRect.z - clip_off.x) * clip_scale.x, (pcmd->ClipRect.w - clip_off.y) * clip_scale.y);
clip_rect.y = (pcmd->ClipRect.y - clip_off.y) * clip_scale.y; if (clip_max.x < clip_min.x || clip_max.y < clip_min.y)
clip_rect.z = (pcmd->ClipRect.z - clip_off.x) * clip_scale.x; continue;
clip_rect.w = (pcmd->ClipRect.w - clip_off.y) * clip_scale.y;
// Apply scissor/clipping rectangle (Y is inverted in OpenGL)
if (clip_rect.x < fb_width && clip_rect.y < fb_height && clip_rect.z >= 0.0f && clip_rect.w >= 0.0f) glScissor((int)clip_min.x, (int)(fb_height - clip_max.y), (int)(clip_max.x - clip_min.x), (int)(clip_max.y - clip_min.y));
{
// Apply scissor/clipping rectangle // Bind texture, Draw
glScissor((int)clip_rect.x, (int)(fb_height - clip_rect.w), (int)(clip_rect.z - clip_rect.x), (int)(clip_rect.w - clip_rect.y)); glBindTexture(GL_TEXTURE_2D, (GLuint)(intptr_t)pcmd->GetTexID());
// Bind texture, Draw
glBindTexture(GL_TEXTURE_2D, (GLuint)(intptr_t)pcmd->GetTexID());
#ifdef IMGUI_IMPL_OPENGL_MAY_HAVE_VTX_OFFSET #ifdef IMGUI_IMPL_OPENGL_MAY_HAVE_VTX_OFFSET
if (bd->GlVersion >= 320) if (bd->GlVersion >= 320)
glDrawElementsBaseVertex(GL_TRIANGLES, (GLsizei)pcmd->ElemCount, sizeof(ImDrawIdx) == 2 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT, (void*)(intptr_t)(pcmd->IdxOffset * sizeof(ImDrawIdx)), (GLint)pcmd->VtxOffset); glDrawElementsBaseVertex(GL_TRIANGLES, (GLsizei)pcmd->ElemCount, sizeof(ImDrawIdx) == 2 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT, (void*)(intptr_t)(pcmd->IdxOffset * sizeof(ImDrawIdx)), (GLint)pcmd->VtxOffset);
else else
#endif #endif
glDrawElements(GL_TRIANGLES, (GLsizei)pcmd->ElemCount, sizeof(ImDrawIdx) == 2 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT, (void*)(intptr_t)(pcmd->IdxOffset * sizeof(ImDrawIdx))); glDrawElements(GL_TRIANGLES, (GLsizei)pcmd->ElemCount, sizeof(ImDrawIdx) == 2 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT, (void*)(intptr_t)(pcmd->IdxOffset * sizeof(ImDrawIdx)));
}
} }
} }
} }
@ -636,7 +636,7 @@ bool ImGui_ImplOpenGL3_CreateDeviceObjects()
"}\n"; "}\n";
const GLchar* vertex_shader_glsl_300_es = const GLchar* vertex_shader_glsl_300_es =
"precision mediump float;\n" "precision highp float;\n"
"layout (location = 0) in vec2 Position;\n" "layout (location = 0) in vec2 Position;\n"
"layout (location = 1) in vec2 UV;\n" "layout (location = 1) in vec2 UV;\n"
"layout (location = 2) in vec4 Color;\n" "layout (location = 2) in vec4 Color;\n"

@ -43,7 +43,7 @@ IMGUI_IMPL_API void ImGui_ImplOpenGL3_DestroyDeviceObjects();
// Try to detect GLES on matching platforms // Try to detect GLES on matching platforms
#if defined(__APPLE__) #if defined(__APPLE__)
#include "TargetConditionals.h" #include <TargetConditionals.h>
#endif #endif
#if (defined(__APPLE__) && (TARGET_OS_IOS || TARGET_OS_TV)) || (defined(__ANDROID__)) #if (defined(__APPLE__) && (TARGET_OS_IOS || TARGET_OS_TV)) || (defined(__ANDROID__))
#define IMGUI_IMPL_OPENGL_ES3 // iOS, Android -> GL ES 3, "#version 300 es" #define IMGUI_IMPL_OPENGL_ES3 // iOS, Android -> GL ES 3, "#version 300 es"

@ -473,61 +473,61 @@ union GL3WProcs {
} gl; } gl;
}; };
GL3W_API extern union GL3WProcs gl3wProcs; GL3W_API extern union GL3WProcs imgl3wProcs;
/* OpenGL functions */ /* OpenGL functions */
#define glActiveTexture gl3wProcs.gl.ActiveTexture #define glActiveTexture imgl3wProcs.gl.ActiveTexture
#define glAttachShader gl3wProcs.gl.AttachShader #define glAttachShader imgl3wProcs.gl.AttachShader
#define glBindBuffer gl3wProcs.gl.BindBuffer #define glBindBuffer imgl3wProcs.gl.BindBuffer
#define glBindSampler gl3wProcs.gl.BindSampler #define glBindSampler imgl3wProcs.gl.BindSampler
#define glBindTexture gl3wProcs.gl.BindTexture #define glBindTexture imgl3wProcs.gl.BindTexture
#define glBindVertexArray gl3wProcs.gl.BindVertexArray #define glBindVertexArray imgl3wProcs.gl.BindVertexArray
#define glBlendEquation gl3wProcs.gl.BlendEquation #define glBlendEquation imgl3wProcs.gl.BlendEquation
#define glBlendEquationSeparate gl3wProcs.gl.BlendEquationSeparate #define glBlendEquationSeparate imgl3wProcs.gl.BlendEquationSeparate
#define glBlendFuncSeparate gl3wProcs.gl.BlendFuncSeparate #define glBlendFuncSeparate imgl3wProcs.gl.BlendFuncSeparate
#define glBufferData gl3wProcs.gl.BufferData #define glBufferData imgl3wProcs.gl.BufferData
#define glClear gl3wProcs.gl.Clear #define glClear imgl3wProcs.gl.Clear
#define glClearColor gl3wProcs.gl.ClearColor #define glClearColor imgl3wProcs.gl.ClearColor
#define glCompileShader gl3wProcs.gl.CompileShader #define glCompileShader imgl3wProcs.gl.CompileShader
#define glCreateProgram gl3wProcs.gl.CreateProgram #define glCreateProgram imgl3wProcs.gl.CreateProgram
#define glCreateShader gl3wProcs.gl.CreateShader #define glCreateShader imgl3wProcs.gl.CreateShader
#define glDeleteBuffers gl3wProcs.gl.DeleteBuffers #define glDeleteBuffers imgl3wProcs.gl.DeleteBuffers
#define glDeleteProgram gl3wProcs.gl.DeleteProgram #define glDeleteProgram imgl3wProcs.gl.DeleteProgram
#define glDeleteShader gl3wProcs.gl.DeleteShader #define glDeleteShader imgl3wProcs.gl.DeleteShader
#define glDeleteTextures gl3wProcs.gl.DeleteTextures #define glDeleteTextures imgl3wProcs.gl.DeleteTextures
#define glDeleteVertexArrays gl3wProcs.gl.DeleteVertexArrays #define glDeleteVertexArrays imgl3wProcs.gl.DeleteVertexArrays
#define glDetachShader gl3wProcs.gl.DetachShader #define glDetachShader imgl3wProcs.gl.DetachShader
#define glDisable gl3wProcs.gl.Disable #define glDisable imgl3wProcs.gl.Disable
#define glDrawElements gl3wProcs.gl.DrawElements #define glDrawElements imgl3wProcs.gl.DrawElements
#define glDrawElementsBaseVertex gl3wProcs.gl.DrawElementsBaseVertex #define glDrawElementsBaseVertex imgl3wProcs.gl.DrawElementsBaseVertex
#define glEnable gl3wProcs.gl.Enable #define glEnable imgl3wProcs.gl.Enable
#define glEnableVertexAttribArray gl3wProcs.gl.EnableVertexAttribArray #define glEnableVertexAttribArray imgl3wProcs.gl.EnableVertexAttribArray
#define glGenBuffers gl3wProcs.gl.GenBuffers #define glGenBuffers imgl3wProcs.gl.GenBuffers
#define glGenTextures gl3wProcs.gl.GenTextures #define glGenTextures imgl3wProcs.gl.GenTextures
#define glGenVertexArrays gl3wProcs.gl.GenVertexArrays #define glGenVertexArrays imgl3wProcs.gl.GenVertexArrays
#define glGetAttribLocation gl3wProcs.gl.GetAttribLocation #define glGetAttribLocation imgl3wProcs.gl.GetAttribLocation
#define glGetIntegerv gl3wProcs.gl.GetIntegerv #define glGetIntegerv imgl3wProcs.gl.GetIntegerv
#define glGetProgramInfoLog gl3wProcs.gl.GetProgramInfoLog #define glGetProgramInfoLog imgl3wProcs.gl.GetProgramInfoLog
#define glGetProgramiv gl3wProcs.gl.GetProgramiv #define glGetProgramiv imgl3wProcs.gl.GetProgramiv
#define glGetShaderInfoLog gl3wProcs.gl.GetShaderInfoLog #define glGetShaderInfoLog imgl3wProcs.gl.GetShaderInfoLog
#define glGetShaderiv gl3wProcs.gl.GetShaderiv #define glGetShaderiv imgl3wProcs.gl.GetShaderiv
#define glGetString gl3wProcs.gl.GetString #define glGetString imgl3wProcs.gl.GetString
#define glGetStringi gl3wProcs.gl.GetStringi #define glGetStringi imgl3wProcs.gl.GetStringi
#define glGetUniformLocation gl3wProcs.gl.GetUniformLocation #define glGetUniformLocation imgl3wProcs.gl.GetUniformLocation
#define glIsEnabled gl3wProcs.gl.IsEnabled #define glIsEnabled imgl3wProcs.gl.IsEnabled
#define glLinkProgram gl3wProcs.gl.LinkProgram #define glLinkProgram imgl3wProcs.gl.LinkProgram
#define glPixelStorei gl3wProcs.gl.PixelStorei #define glPixelStorei imgl3wProcs.gl.PixelStorei
#define glPolygonMode gl3wProcs.gl.PolygonMode #define glPolygonMode imgl3wProcs.gl.PolygonMode
#define glReadPixels gl3wProcs.gl.ReadPixels #define glReadPixels imgl3wProcs.gl.ReadPixels
#define glScissor gl3wProcs.gl.Scissor #define glScissor imgl3wProcs.gl.Scissor
#define glShaderSource gl3wProcs.gl.ShaderSource #define glShaderSource imgl3wProcs.gl.ShaderSource
#define glTexImage2D gl3wProcs.gl.TexImage2D #define glTexImage2D imgl3wProcs.gl.TexImage2D
#define glTexParameteri gl3wProcs.gl.TexParameteri #define glTexParameteri imgl3wProcs.gl.TexParameteri
#define glUniform1i gl3wProcs.gl.Uniform1i #define glUniform1i imgl3wProcs.gl.Uniform1i
#define glUniformMatrix4fv gl3wProcs.gl.UniformMatrix4fv #define glUniformMatrix4fv imgl3wProcs.gl.UniformMatrix4fv
#define glUseProgram gl3wProcs.gl.UseProgram #define glUseProgram imgl3wProcs.gl.UseProgram
#define glVertexAttribPointer gl3wProcs.gl.VertexAttribPointer #define glVertexAttribPointer imgl3wProcs.gl.VertexAttribPointer
#define glViewport gl3wProcs.gl.Viewport #define glViewport imgl3wProcs.gl.Viewport
#ifdef __cplusplus #ifdef __cplusplus
} }
@ -715,13 +715,13 @@ static const char *proc_names[] = {
"glViewport", "glViewport",
}; };
GL3W_API union GL3WProcs gl3wProcs; GL3W_API union GL3WProcs imgl3wProcs;
static void load_procs(GL3WGetProcAddressProc proc) static void load_procs(GL3WGetProcAddressProc proc)
{ {
size_t i; size_t i;
for (i = 0; i < ARRAY_SIZE(proc_names); i++) for (i = 0; i < ARRAY_SIZE(proc_names); i++)
gl3wProcs.ptr[i] = proc(proc_names[i]); imgl3wProcs.ptr[i] = proc(proc_names[i]);
} }
#ifdef __cplusplus #ifdef __cplusplus

@ -61,7 +61,7 @@
#include <SDL.h> #include <SDL.h>
#include <SDL_syswm.h> #include <SDL_syswm.h>
#if defined(__APPLE__) #if defined(__APPLE__)
#include "TargetConditionals.h" #include <TargetConditionals.h>
#endif #endif
#if SDL_VERSION_ATLEAST(2,0,4) && !defined(__EMSCRIPTEN__) && !defined(__ANDROID__) && !(defined(__APPLE__) && TARGET_OS_IOS) #if SDL_VERSION_ATLEAST(2,0,4) && !defined(__EMSCRIPTEN__) && !defined(__ANDROID__) && !(defined(__APPLE__) && TARGET_OS_IOS)

@ -543,31 +543,27 @@ void ImGui_ImplVulkan_RenderDrawData(ImDrawData* draw_data, VkCommandBuffer comm
else else
{ {
// Project scissor/clipping rectangles into framebuffer space // Project scissor/clipping rectangles into framebuffer space
ImVec4 clip_rect; ImVec2 clip_min((pcmd->ClipRect.x - clip_off.x) * clip_scale.x, (pcmd->ClipRect.y - clip_off.y) * clip_scale.y);
clip_rect.x = (pcmd->ClipRect.x - clip_off.x) * clip_scale.x; ImVec2 clip_max((pcmd->ClipRect.z - clip_off.x) * clip_scale.x, (pcmd->ClipRect.w - clip_off.y) * clip_scale.y);
clip_rect.y = (pcmd->ClipRect.y - clip_off.y) * clip_scale.y;
clip_rect.z = (pcmd->ClipRect.z - clip_off.x) * clip_scale.x; // Clamp to viewport as vkCmdSetScissor() won't accept values that are off bounds
clip_rect.w = (pcmd->ClipRect.w - clip_off.y) * clip_scale.y; if (clip_min.x < 0.0f) { clip_min.x = 0.0f; }
if (clip_min.y < 0.0f) { clip_min.y = 0.0f; }
if (clip_rect.x < fb_width && clip_rect.y < fb_height && clip_rect.z >= 0.0f && clip_rect.w >= 0.0f) if (clip_max.x > fb_width) { clip_max.x = (float)fb_width; }
{ if (clip_max.y > fb_height) { clip_max.y = (float)fb_height; }
// Negative offsets are illegal for vkCmdSetScissor if (clip_max.x < clip_min.x || clip_max.y < clip_min.y)
if (clip_rect.x < 0.0f) continue;
clip_rect.x = 0.0f;
if (clip_rect.y < 0.0f) // Apply scissor/clipping rectangle
clip_rect.y = 0.0f; VkRect2D scissor;
scissor.offset.x = (int32_t)(clip_min.x);
// Apply scissor/clipping rectangle scissor.offset.y = (int32_t)(clip_min.y);
VkRect2D scissor; scissor.extent.width = (uint32_t)(clip_max.x - clip_min.x);
scissor.offset.x = (int32_t)(clip_rect.x); scissor.extent.height = (uint32_t)(clip_max.y - clip_min.y);
scissor.offset.y = (int32_t)(clip_rect.y); vkCmdSetScissor(command_buffer, 0, 1, &scissor);
scissor.extent.width = (uint32_t)(clip_rect.z - clip_rect.x);
scissor.extent.height = (uint32_t)(clip_rect.w - clip_rect.y); // Draw
vkCmdSetScissor(command_buffer, 0, 1, &scissor); vkCmdDrawIndexed(command_buffer, pcmd->ElemCount, 1, pcmd->IdxOffset + global_idx_offset, pcmd->VtxOffset + global_vtx_offset, 0);
// Draw
vkCmdDrawIndexed(command_buffer, pcmd->ElemCount, 1, pcmd->IdxOffset + global_idx_offset, pcmd->VtxOffset + global_vtx_offset, 0);
}
} }
} }
global_idx_offset += cmd_list->IdxBuffer.Size; global_idx_offset += cmd_list->IdxBuffer.Size;
@ -732,7 +728,7 @@ static void ImGui_ImplVulkan_CreateShaderModules(VkDevice device, const VkAlloca
{ {
// Create the shader modules // Create the shader modules
ImGui_ImplVulkan_Data* bd = ImGui_ImplVulkan_GetBackendData(); ImGui_ImplVulkan_Data* bd = ImGui_ImplVulkan_GetBackendData();
if (bd->ShaderModuleVert == NULL) if (bd->ShaderModuleVert == VK_NULL_HANDLE)
{ {
VkShaderModuleCreateInfo vert_info = {}; VkShaderModuleCreateInfo vert_info = {};
vert_info.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO; vert_info.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;
@ -741,7 +737,7 @@ static void ImGui_ImplVulkan_CreateShaderModules(VkDevice device, const VkAlloca
VkResult err = vkCreateShaderModule(device, &vert_info, allocator, &bd->ShaderModuleVert); VkResult err = vkCreateShaderModule(device, &vert_info, allocator, &bd->ShaderModuleVert);
check_vk_result(err); check_vk_result(err);
} }
if (bd->ShaderModuleFrag == NULL) if (bd->ShaderModuleFrag == VK_NULL_HANDLE)
{ {
VkShaderModuleCreateInfo frag_info = {}; VkShaderModuleCreateInfo frag_info = {};
frag_info.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO; frag_info.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;
@ -1284,7 +1280,7 @@ void ImGui_ImplVulkanH_CreateWindowSwapChain(VkPhysicalDevice physical_device, V
{ {
VkResult err; VkResult err;
VkSwapchainKHR old_swapchain = wd->Swapchain; VkSwapchainKHR old_swapchain = wd->Swapchain;
wd->Swapchain = NULL; wd->Swapchain = VK_NULL_HANDLE;
err = vkDeviceWaitIdle(device); err = vkDeviceWaitIdle(device);
check_vk_result(err); check_vk_result(err);

@ -6,13 +6,14 @@
// [X] Renderer: User texture binding. Use 'WGPUTextureView' as ImTextureID. Read the FAQ about ImTextureID! // [X] Renderer: User texture binding. Use 'WGPUTextureView' as ImTextureID. Read the FAQ about ImTextureID!
// [X] Renderer: Support for large meshes (64k+ vertices) with 16-bit indices. // [X] Renderer: Support for large meshes (64k+ vertices) with 16-bit indices.
// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this. // You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
// Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need. // Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
// If you are new to Dear ImGui, read documentation from the docs/ folder + read the top of imgui.cpp. // If you are new to Dear ImGui, read documentation from the docs/ folder + read the top of imgui.cpp.
// Read online: https://github.com/ocornut/imgui/tree/master/docs // Read online: https://github.com/ocornut/imgui/tree/master/docs
// CHANGELOG // CHANGELOG
// (minor and older changes stripped away, please see git history for details) // (minor and older changes stripped away, please see git history for details)
// 2021-08-24: Fix for latest specs.
// 2021-05-24: Add support for draw_data->FramebufferScale. // 2021-05-24: Add support for draw_data->FramebufferScale.
// 2021-05-19: Replaced direct access to ImDrawCmd::TextureId with a call to ImDrawCmd::GetTexID(). (will become a requirement) // 2021-05-19: Replaced direct access to ImDrawCmd::TextureId with a call to ImDrawCmd::GetTexID(). (will become a requirement)
// 2021-05-16: Update to latest WebGPU specs (compatible with Emscripten 2.0.20 and Chrome Canary 92). // 2021-05-16: Update to latest WebGPU specs (compatible with Emscripten 2.0.20 and Chrome Canary 92).
@ -442,13 +443,14 @@ void ImGui_ImplWGPU_RenderDrawData(ImDrawData* draw_data, WGPURenderPassEncoder
wgpuRenderPassEncoderSetBindGroup(pass_encoder, 1, image_bind_group, 0, NULL); wgpuRenderPassEncoderSetBindGroup(pass_encoder, 1, image_bind_group, 0, NULL);
} }
// Apply Scissor, Bind texture, Draw // Project scissor/clipping rectangles into framebuffer space
uint32_t clip_rect[4]; ImVec2 clip_min((pcmd->ClipRect.x - clip_off.x) * clip_scale.x, (pcmd->ClipRect.y - clip_off.y) * clip_scale.y);
clip_rect[0] = (uint32_t)(clip_scale.x * (pcmd->ClipRect.x - clip_off.x)); ImVec2 clip_max((pcmd->ClipRect.z - clip_off.x) * clip_scale.x, (pcmd->ClipRect.w - clip_off.y) * clip_scale.y);
clip_rect[1] = (uint32_t)(clip_scale.y * (pcmd->ClipRect.y - clip_off.y)); if (clip_max.x < clip_min.x || clip_max.y < clip_min.y)
clip_rect[2] = (uint32_t)(clip_scale.x * (pcmd->ClipRect.z - clip_off.x)); continue;
clip_rect[3] = (uint32_t)(clip_scale.y * (pcmd->ClipRect.w - clip_off.y));
wgpuRenderPassEncoderSetScissorRect(pass_encoder, clip_rect[0], clip_rect[1], clip_rect[2] - clip_rect[0], clip_rect[3] - clip_rect[1]); // Apply scissor/clipping rectangle, Draw
wgpuRenderPassEncoderSetScissorRect(pass_encoder, (uint32_t)clip_min.x, (uint32_t)clip_min.y, (uint32_t)(clip_max.x - clip_min.x), (uint32_t)(clip_max.y - clip_min.y));
wgpuRenderPassEncoderDrawIndexed(pass_encoder, pcmd->ElemCount, 1, pcmd->IdxOffset + global_idx_offset, pcmd->VtxOffset + global_vtx_offset, 0); wgpuRenderPassEncoderDrawIndexed(pass_encoder, pcmd->ElemCount, 1, pcmd->IdxOffset + global_idx_offset, pcmd->VtxOffset + global_vtx_offset, 0);
} }
} }
@ -544,7 +546,7 @@ bool ImGui_ImplWGPU_CreateDeviceObjects()
ImGui_ImplWGPU_InvalidateDeviceObjects(); ImGui_ImplWGPU_InvalidateDeviceObjects();
// Create render pipeline // Create render pipeline
WGPURenderPipelineDescriptor2 graphics_pipeline_desc = {}; WGPURenderPipelineDescriptor graphics_pipeline_desc = {};
graphics_pipeline_desc.primitive.topology = WGPUPrimitiveTopology_TriangleList; graphics_pipeline_desc.primitive.topology = WGPUPrimitiveTopology_TriangleList;
graphics_pipeline_desc.primitive.stripIndexFormat = WGPUIndexFormat_Undefined; graphics_pipeline_desc.primitive.stripIndexFormat = WGPUIndexFormat_Undefined;
graphics_pipeline_desc.primitive.frontFace = WGPUFrontFace_CW; graphics_pipeline_desc.primitive.frontFace = WGPUFrontFace_CW;
@ -610,7 +612,7 @@ bool ImGui_ImplWGPU_CreateDeviceObjects()
// Configure disabled depth-stencil state // Configure disabled depth-stencil state
graphics_pipeline_desc.depthStencil = nullptr; graphics_pipeline_desc.depthStencil = nullptr;
g_pipelineState = wgpuDeviceCreateRenderPipeline2(g_wgpuDevice, &graphics_pipeline_desc); g_pipelineState = wgpuDeviceCreateRenderPipeline(g_wgpuDevice, &graphics_pipeline_desc);
ImGui_ImplWGPU_CreateFontsTexture(); ImGui_ImplWGPU_CreateFontsTexture();
ImGui_ImplWGPU_CreateUniformBuffer(); ImGui_ImplWGPU_CreateUniformBuffer();

@ -30,6 +30,55 @@ HOW TO UPDATE?
and API updates have been a little more frequent lately. They are documented below and in imgui.cpp and should not affect all users. and API updates have been a little more frequent lately. They are documented below and in imgui.cpp and should not affect all users.
- Please report any issue! - Please report any issue!
-----------------------------------------------------------------------
VERSION 1.85 WIP (In Progress)
-----------------------------------------------------------------------
Breaking Changes:
- Removed GetWindowContentRegionWidth() function. keep inline redirection helper.
Can use 'GetWindowContentRegionMax().x - GetWindowContentRegionMin().x' instead but it's not
very useful in practice, and the only use of it in the demo was illfit.
Other Changes:
- Windows: fixed background order of overlapping childs submitted sequentially. (#4493)
- InputTextMultiline: Fixed label size not being included into window contents rect unless
the whole widget is clipped.
- TextUnformatted: Accept null ranges including (NULL,NULL) without asserting, in order to conform
to common idioms (e.g. passing .data(), .data() + .size() from a null string). (#3615)
- IO: Added 'io.WantCaptureMouseUnlessPopupClose' alternative to `io.WantCaptureMouse'. (#4480)
This allows apps to receive the click on void when that click is used to close popup (by default,
clicking on a void when a popup is open will close the popup but not release io.WantCaptureMouse).
- Fonts: imgui_freetype: Fixed crash when FT_Render_Glyph() fails to render a glyph and returns NULL
(which apparently happens with Freetype 2.11). (#4394, #4145?).
- Fonts: Fixed ImFontAtlas::ClearInputData() marking atlas as not built. (#4455, #3487)
- Backends: OpenGL3: Fixed our new GL loader conflicting with user using GL3W. (#4445)
- Backends: WebGPU: Fixed for latest specs. (#4472) [@Kangz]
- Backends: Metal: Fixed a crash when clipping rect larger than framebuffer is submitted via
a direct unclipped PushClipRect() call. (#4464)
- Backends: All renderers: Normalize clipping rect handling across backends. (#4464)
-----------------------------------------------------------------------
VERSION 1.84.2 (Released 2021-08-23)
-----------------------------------------------------------------------
Decorated log: https://github.com/ocornut/imgui/releases/tag/v1.84.2
- Disabled: Fixed nested BeginDisabled()/EndDisabled() calls. (#211, #4452, #4453, #4462) [@Legulysse]
- Backends: OpenGL3: OpenGL: Fixed ES 3.0 shader ("#version 300 es") to use normal precision
floats. Avoid wobbly rendering at HD resolutions. (#4463) [@nicolasnoble]
-----------------------------------------------------------------------
VERSION 1.84.1 (Released 2021-08-20)
-----------------------------------------------------------------------
Decorated log: https://github.com/ocornut/imgui/releases/tag/v1.84.1
- Disabled: Fixed BeginDisabled(false) - BeginDisabled(true) was working. (#211, #4452, #4453)
----------------------------------------------------------------------- -----------------------------------------------------------------------
DOCKING+MULTI-VIEWPORT BRANCH (In Progress) DOCKING+MULTI-VIEWPORT BRANCH (In Progress)

@ -94,6 +94,8 @@ Read [BACKENDS.md](https://github.com/ocornut/imgui/blob/master/docs/BACKENDS.md
Read `PROGRAMMER GUIDE` section of [imgui.cpp](https://github.com/ocornut/imgui/blob/master/imgui.cpp). <BR> Read `PROGRAMMER GUIDE` section of [imgui.cpp](https://github.com/ocornut/imgui/blob/master/imgui.cpp). <BR>
The [Wiki](https://github.com/ocornut/imgui/wiki) is a hub to many resources and links. The [Wiki](https://github.com/ocornut/imgui/wiki) is a hub to many resources and links.
For first-time users having issues compiling/linking/running or issues loading fonts, please use [GitHub Discussions](https://github.com/ocornut/imgui/discussions).
##### [Return to Index](#index) ##### [Return to Index](#index)
--- ---

@ -162,7 +162,9 @@ See: [Wiki](https://github.com/ocornut/imgui/wiki) for many links, references, a
See: [Articles about the IMGUI paradigm](https://github.com/ocornut/imgui/wiki#about-the-imgui-paradigm) to read/learn about the Immediate Mode GUI paradigm. See: [Articles about the IMGUI paradigm](https://github.com/ocornut/imgui/wiki#about-the-imgui-paradigm) to read/learn about the Immediate Mode GUI paradigm.
For questions, bug reports, requests, feedback, you may post on [GitHub Issues](https://github.com/ocornut/imgui/issues) or [GitHub Discussions](https://github.com/ocornut/imgui/discussions). Please read and fill the New Issue template carefully. Getting started? For first-time users having issues compiling/linking/running or issues loading fonts, please use [GitHub Discussions](https://github.com/ocornut/imgui/discussions).
For other questions, bug reports, requests, feedback, you may post on [GitHub Issues](https://github.com/ocornut/imgui/issues). Please read and fill the New Issue template carefully.
Private support is available for paying business customers (E-mail: _contact @ dearimgui dot com_). Private support is available for paying business customers (E-mail: _contact @ dearimgui dot com_).

@ -8,9 +8,10 @@
#include "imgui_impl_opengl3.h" #include "imgui_impl_opengl3.h"
#include <stdio.h> #include <stdio.h>
#include <SDL.h> #include <SDL.h>
#include <SDL_opengl.h>
#if defined(IMGUI_IMPL_OPENGL_ES2) #if defined(IMGUI_IMPL_OPENGL_ES2)
#include <SDL_opengles2.h> #include <SDL_opengles2.h>
#else
#include <SDL_opengl.h>
#endif #endif
// Main code // Main code

@ -1,4 +1,4 @@
// dear imgui, v1.84 // dear imgui, v1.85 WIP
// (main code and documentation) // (main code and documentation)
// Help: // Help:
@ -15,7 +15,10 @@
// - Wiki https://github.com/ocornut/imgui/wiki (lots of good stuff there) // - Wiki https://github.com/ocornut/imgui/wiki (lots of good stuff there)
// - Glossary https://github.com/ocornut/imgui/wiki/Glossary // - Glossary https://github.com/ocornut/imgui/wiki/Glossary
// - Issues & support https://github.com/ocornut/imgui/issues // - Issues & support https://github.com/ocornut/imgui/issues
// - Discussions https://github.com/ocornut/imgui/discussions
// Getting Started?
// - For first-time users having issues compiling/linking/running or issues loading fonts:
// please post in https://github.com/ocornut/imgui/discussions if you cannot find a solution in resources above.
// Developed by Omar Cornut and every direct or indirect contributors to the GitHub. // Developed by Omar Cornut and every direct or indirect contributors to the GitHub.
// See LICENSE.txt for copyright and licensing details (standard MIT License). // See LICENSE.txt for copyright and licensing details (standard MIT License).
@ -386,6 +389,7 @@ CODE
- 2021/XX/XX (1.XX) - Moved IME support functions from io.ImeSetInputScreenPosFn, io.ImeWindowHandle to the PlatformIO api. - 2021/XX/XX (1.XX) - Moved IME support functions from io.ImeSetInputScreenPosFn, io.ImeWindowHandle to the PlatformIO api.
- 2021/08/23 (1.85) - removed GetWindowContentRegionWidth() function. keep inline redirection helper. can use 'GetWindowContentRegionMax().x - GetWindowContentRegionMin().x' instead.
- 2021/07/26 (1.84) - commented out redirecting functions/enums names that were marked obsolete in 1.67 and 1.69 (March 2019): - 2021/07/26 (1.84) - commented out redirecting functions/enums names that were marked obsolete in 1.67 and 1.69 (March 2019):
- ImGui::GetOverlayDrawList() -> use ImGui::GetForegroundDrawList() - ImGui::GetOverlayDrawList() -> use ImGui::GetForegroundDrawList()
- ImFont::GlyphRangesBuilder -> use ImFontGlyphRangesBuilder - ImFont::GlyphRangesBuilder -> use ImFontGlyphRangesBuilder
@ -919,8 +923,9 @@ namespace ImGui
static void NavUpdate(); static void NavUpdate();
static void NavUpdateWindowing(); static void NavUpdateWindowing();
static void NavUpdateWindowingOverlay(); static void NavUpdateWindowingOverlay();
static void NavUpdateMoveResult();
static void NavUpdateInitResult(); static void NavUpdateInitResult();
static void NavUpdateCancelRequest();
static void NavUpdateCreateMoveRequest();
static float NavUpdatePageUpPageDown(); static float NavUpdatePageUpPageDown();
static inline void NavUpdateAnyRequestFlag(); static inline void NavUpdateAnyRequestFlag();
static void NavEndFrame(); static void NavEndFrame();
@ -4004,6 +4009,7 @@ void ImGui::UpdateTabFocus()
void ImGui::UpdateHoveredWindowAndCaptureFlags() void ImGui::UpdateHoveredWindowAndCaptureFlags()
{ {
ImGuiContext& g = *GImGui; ImGuiContext& g = *GImGui;
ImGuiIO& io = g.IO;
g.WindowsHoverPadding = ImMax(g.Style.TouchExtraPadding, ImVec2(WINDOWS_HOVER_PADDING, WINDOWS_HOVER_PADDING)); g.WindowsHoverPadding = ImMax(g.Style.TouchExtraPadding, ImVec2(WINDOWS_HOVER_PADDING, WINDOWS_HOVER_PADDING));
// Find the window hovered by mouse: // Find the window hovered by mouse:
@ -4020,48 +4026,61 @@ void ImGui::UpdateHoveredWindowAndCaptureFlags()
clear_hovered_windows = true; clear_hovered_windows = true;
// Disabled mouse? // Disabled mouse?
if (g.IO.ConfigFlags & ImGuiConfigFlags_NoMouse) if (io.ConfigFlags & ImGuiConfigFlags_NoMouse)
clear_hovered_windows = true; clear_hovered_windows = true;
// We track click ownership. When clicked outside of a window the click is owned by the application and won't report hovering nor request capture even while dragging over our windows afterward. // We track click ownership. When clicked outside of a window the click is owned by the application and
int mouse_earliest_button_down = -1; // won't report hovering nor request capture even while dragging over our windows afterward.
const bool has_open_popup = (g.OpenPopupStack.Size > 0);
const bool has_open_modal = (modal_window != NULL);
int mouse_earliest_down = -1;
bool mouse_any_down = false; bool mouse_any_down = false;
for (int i = 0; i < IM_ARRAYSIZE(g.IO.MouseDown); i++) for (int i = 0; i < IM_ARRAYSIZE(io.MouseDown); i++)
{ {
if (g.IO.MouseClicked[i]) if (io.MouseClicked[i])
g.IO.MouseDownOwned[i] = (g.HoveredWindow != NULL) || (g.OpenPopupStack.Size > 0); {
mouse_any_down |= g.IO.MouseDown[i]; io.MouseDownOwned[i] = (g.HoveredWindow != NULL) || has_open_popup;
if (g.IO.MouseDown[i]) io.MouseDownOwnedUnlessPopupClose[i] = (g.HoveredWindow != NULL) || has_open_modal;
if (mouse_earliest_button_down == -1 || g.IO.MouseClickedTime[i] < g.IO.MouseClickedTime[mouse_earliest_button_down]) }
mouse_earliest_button_down = i; mouse_any_down |= io.MouseDown[i];
if (io.MouseDown[i])
if (mouse_earliest_down == -1 || io.MouseClickedTime[i] < io.MouseClickedTime[mouse_earliest_down])
mouse_earliest_down = i;
} }
const bool mouse_avail_to_imgui = (mouse_earliest_button_down == -1) || g.IO.MouseDownOwned[mouse_earliest_button_down]; const bool mouse_avail = (mouse_earliest_down == -1) || io.MouseDownOwned[mouse_earliest_down];
const bool mouse_avail_unless_popup_close = (mouse_earliest_down == -1) || io.MouseDownOwnedUnlessPopupClose[mouse_earliest_down];
// If mouse was first clicked outside of ImGui bounds we also cancel out hovering. // If mouse was first clicked outside of ImGui bounds we also cancel out hovering.
// FIXME: For patterns of drag and drop across OS windows, we may need to rework/remove this test (first committed 311c0ca9 on 2015/02) // FIXME: For patterns of drag and drop across OS windows, we may need to rework/remove this test (first committed 311c0ca9 on 2015/02)
const bool mouse_dragging_extern_payload = g.DragDropActive && (g.DragDropSourceFlags & ImGuiDragDropFlags_SourceExtern) != 0; const bool mouse_dragging_extern_payload = g.DragDropActive && (g.DragDropSourceFlags & ImGuiDragDropFlags_SourceExtern) != 0;
if (!mouse_avail_to_imgui && !mouse_dragging_extern_payload) if (!mouse_avail && !mouse_dragging_extern_payload)
clear_hovered_windows = true; clear_hovered_windows = true;
if (clear_hovered_windows) if (clear_hovered_windows)
g.HoveredWindow = g.HoveredWindowUnderMovingWindow = NULL; g.HoveredWindow = g.HoveredWindowUnderMovingWindow = NULL;
// Update io.WantCaptureMouse for the user application (true = dispatch mouse info to imgui, false = dispatch mouse info to Dear ImGui + app) // Update io.WantCaptureMouse for the user application (true = dispatch mouse info to Dear ImGui only, false = dispatch mouse to Dear ImGui + underlying app)
// Update io.WantCaptureMouseAllowPopupClose (experimental) to give a chance for app to react to popup closure with a drag
if (g.WantCaptureMouseNextFrame != -1) if (g.WantCaptureMouseNextFrame != -1)
g.IO.WantCaptureMouse = (g.WantCaptureMouseNextFrame != 0); {
io.WantCaptureMouse = io.WantCaptureMouseUnlessPopupClose = (g.WantCaptureMouseNextFrame != 0);
}
else else
g.IO.WantCaptureMouse = (mouse_avail_to_imgui && (g.HoveredWindow != NULL || mouse_any_down)) || (g.OpenPopupStack.Size > 0); {
io.WantCaptureMouse = (mouse_avail && (g.HoveredWindow != NULL || mouse_any_down)) || has_open_popup;
io.WantCaptureMouseUnlessPopupClose = (mouse_avail_unless_popup_close && (g.HoveredWindow != NULL || mouse_any_down)) || has_open_modal;
}
// Update io.WantCaptureKeyboard for the user application (true = dispatch keyboard info to imgui, false = dispatch keyboard info to Dear ImGui + app) // Update io.WantCaptureKeyboard for the user application (true = dispatch keyboard info to Dear ImGui only, false = dispatch keyboard info to Dear ImGui + underlying app)
if (g.WantCaptureKeyboardNextFrame != -1) if (g.WantCaptureKeyboardNextFrame != -1)
g.IO.WantCaptureKeyboard = (g.WantCaptureKeyboardNextFrame != 0); io.WantCaptureKeyboard = (g.WantCaptureKeyboardNextFrame != 0);
else else
g.IO.WantCaptureKeyboard = (g.ActiveId != 0) || (modal_window != NULL); io.WantCaptureKeyboard = (g.ActiveId != 0) || (modal_window != NULL);
if (g.IO.NavActive && (g.IO.ConfigFlags & ImGuiConfigFlags_NavEnableKeyboard) && !(g.IO.ConfigFlags & ImGuiConfigFlags_NavNoCaptureKeyboard)) if (io.NavActive && (io.ConfigFlags & ImGuiConfigFlags_NavEnableKeyboard) && !(io.ConfigFlags & ImGuiConfigFlags_NavNoCaptureKeyboard))
g.IO.WantCaptureKeyboard = true; io.WantCaptureKeyboard = true;
// Update io.WantTextInput flag, this is to allow systems without a keyboard (e.g. mobile, hand-held) to show a software keyboard if possible // Update io.WantTextInput flag, this is to allow systems without a keyboard (e.g. mobile, hand-held) to show a software keyboard if possible
g.IO.WantTextInput = (g.WantTextInputNextFrame != -1) ? (g.WantTextInputNextFrame != 0) : false; io.WantTextInput = (g.WantTextInputNextFrame != -1) ? (g.WantTextInputNextFrame != 0) : false;
} }
ImGuiKeyModFlags ImGui::GetMergedKeyModFlags() ImGuiKeyModFlags ImGui::GetMergedKeyModFlags()
@ -6687,18 +6706,23 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags)
window->DrawList->AddRectFilled(bb.Min, bb.Max, GetColorU32(ImGuiCol_NavWindowingHighlight, g.NavWindowingHighlightAlpha * 0.25f), g.Style.WindowRounding); window->DrawList->AddRectFilled(bb.Min, bb.Max, GetColorU32(ImGuiCol_NavWindowingHighlight, g.NavWindowingHighlightAlpha * 0.25f), g.Style.WindowRounding);
} }
// Since 1.71, child window can render their decoration (bg color, border, scrollbars, etc.) within their parent to save a draw call. // Child windows can render their decoration (bg color, border, scrollbars, etc.) within their parent to save a draw call (since 1.71)
// When using overlapping child windows, this will break the assumption that child z-order is mapped to submission order. // When using overlapping child windows, this will break the assumption that child z-order is mapped to submission order.
// We disable this when the parent window has zero vertices, which is a common pattern leading to laying out multiple overlapping child. // FIXME: User code may rely on explicit sorting of overlapping child window and would need to disable this somehow. Please get in contact if you are affected (github #4493)
// We also disabled this when we have dimming overlay behind this specific one child.
// FIXME: More code may rely on explicit sorting of overlapping child window and would need to disable this somehow. Please get in contact if you are affected.
const bool is_undocked_or_docked_visible = !window->DockIsActive || window->DockTabIsVisible; const bool is_undocked_or_docked_visible = !window->DockIsActive || window->DockTabIsVisible;
if (is_undocked_or_docked_visible) if (is_undocked_or_docked_visible)
{ {
bool render_decorations_in_parent = false; bool render_decorations_in_parent = false;
if ((flags & ImGuiWindowFlags_ChildWindow) && !(flags & ImGuiWindowFlags_Popup) && !window_is_child_tooltip) if ((flags & ImGuiWindowFlags_ChildWindow) && !(flags & ImGuiWindowFlags_Popup) && !window_is_child_tooltip)
if (window->DrawList->CmdBuffer.back().ElemCount == 0 && parent_window->DrawList->VtxBuffer.Size > 0) {
// - We test overlap with the previous child window only (testing all would end up being O(log N) not a good investment here)
// - We disable this when the parent window has zero vertices, which is a common pattern leading to laying out multiple overlapping childs
ImGuiWindow* previous_child = parent_window->DC.ChildWindows.Size >= 2 ? parent_window->DC.ChildWindows[parent_window->DC.ChildWindows.Size - 2] : NULL;
bool previous_child_overlapping = previous_child ? previous_child->Rect().Overlaps(window->Rect()) : false;
bool parent_is_empty = parent_window->DrawList->VtxBuffer.Size > 0;
if (window->DrawList->CmdBuffer.back().ElemCount == 0 && parent_is_empty && !previous_child_overlapping)
render_decorations_in_parent = true; render_decorations_in_parent = true;
}
if (render_decorations_in_parent) if (render_decorations_in_parent)
window->DrawList = parent_window->DrawList; window->DrawList = parent_window->DrawList;
@ -7162,7 +7186,7 @@ void ImGui::PopItemFlag()
} }
// BeginDisabled()/EndDisabled() // BeginDisabled()/EndDisabled()
// - Those can be nested but this cannot be used to enable an already disabled section (a single BeginDisabled(true) in the stack is enough to keep things disabled) // - Those can be nested but it cannot be used to enable an already disabled section (a single BeginDisabled(true) in the stack is enough to keep everything disabled)
// - Visually this is currently altering alpha, but it is expected that in a future styling system this would work differently. // - Visually this is currently altering alpha, but it is expected that in a future styling system this would work differently.
// - Feedback welcome at https://github.com/ocornut/imgui/issues/211 // - Feedback welcome at https://github.com/ocornut/imgui/issues/211
// - BeginDisabled(false) essentially does nothing useful but is provided to facilitate use of boolean expressions. If you can avoid calling BeginDisabled(False)/EndDisabled() best to avoid it. // - BeginDisabled(false) essentially does nothing useful but is provided to facilitate use of boolean expressions. If you can avoid calling BeginDisabled(False)/EndDisabled() best to avoid it.
@ -7173,7 +7197,10 @@ void ImGui::BeginDisabled(bool disabled)
bool was_disabled = (g.CurrentItemFlags & ImGuiItemFlags_Disabled) != 0; bool was_disabled = (g.CurrentItemFlags & ImGuiItemFlags_Disabled) != 0;
g.DisabledAlphaBackup = g.Style.Alpha; g.DisabledAlphaBackup = g.Style.Alpha;
if (!was_disabled && disabled) if (!was_disabled && disabled)
{
g.DisabledAlphaBackup = g.Style.Alpha;
g.Style.Alpha *= g.Style.DisabledAlpha; // PushStyleVar(ImGuiStyleVar_Alpha, g.Style.Alpha * g.Style.DisabledAlpha); g.Style.Alpha *= g.Style.DisabledAlpha; // PushStyleVar(ImGuiStyleVar_Alpha, g.Style.Alpha * g.Style.DisabledAlpha);
}
if (was_disabled || disabled) if (was_disabled || disabled)
g.CurrentItemFlags |= ImGuiItemFlags_Disabled; g.CurrentItemFlags |= ImGuiItemFlags_Disabled;
g.ItemFlagsStack.push_back(g.CurrentItemFlags); g.ItemFlagsStack.push_back(g.CurrentItemFlags);
@ -7185,7 +7212,7 @@ void ImGui::EndDisabled()
bool was_disabled = (g.CurrentItemFlags & ImGuiItemFlags_Disabled) != 0; bool was_disabled = (g.CurrentItemFlags & ImGuiItemFlags_Disabled) != 0;
//PopItemFlag(); //PopItemFlag();
g.ItemFlagsStack.pop_back(); g.ItemFlagsStack.pop_back();
g.CurrentItemFlags &= ~ImGuiItemFlags_Disabled; g.CurrentItemFlags = g.ItemFlagsStack.back();
if (was_disabled && (g.CurrentItemFlags & ImGuiItemFlags_Disabled) == 0) if (was_disabled && (g.CurrentItemFlags & ImGuiItemFlags_Disabled) == 0)
g.Style.Alpha = g.DisabledAlphaBackup; //PopStyleVar(); g.Style.Alpha = g.DisabledAlphaBackup; //PopStyleVar();
} }
@ -8048,7 +8075,6 @@ void ImGuiStackSizes::CompareWithCurrentState()
// - GetContentRegionMaxAbs() [Internal] // - GetContentRegionMaxAbs() [Internal]
// - GetContentRegionAvail(), // - GetContentRegionAvail(),
// - GetWindowContentRegionMin(), GetWindowContentRegionMax() // - GetWindowContentRegionMin(), GetWindowContentRegionMax()
// - GetWindowContentRegionWidth()
// - BeginGroup() // - BeginGroup()
// - EndGroup() // - EndGroup()
// Also see in imgui_widgets: tab bars, columns. // Also see in imgui_widgets: tab bars, columns.
@ -8416,12 +8442,6 @@ ImVec2 ImGui::GetWindowContentRegionMax()
return window->ContentRegionRect.Max - window->Pos; return window->ContentRegionRect.Max - window->Pos;
} }
float ImGui::GetWindowContentRegionWidth()
{
ImGuiWindow* window = GImGui->CurrentWindow;
return window->ContentRegionRect.GetWidth();
}
// Lock horizontal starting position + capture group bounding box into one "item" (so you can use IsItemHovered() or layout primitives such as SameLine() on whole group, etc.) // Lock horizontal starting position + capture group bounding box into one "item" (so you can use IsItemHovered() or layout primitives such as SameLine() on whole group, etc.)
// Groups are currently a mishmash of functionalities which should perhaps be clarified and separated. // Groups are currently a mishmash of functionalities which should perhaps be clarified and separated.
void ImGui::BeginGroup() void ImGui::BeginGroup()
@ -9074,7 +9094,7 @@ void ImGui::EndPopup()
IM_ASSERT(window->Flags & ImGuiWindowFlags_Popup); // Mismatched BeginPopup()/EndPopup() calls IM_ASSERT(window->Flags & ImGuiWindowFlags_Popup); // Mismatched BeginPopup()/EndPopup() calls
IM_ASSERT(g.BeginPopupStack.Size > 0); IM_ASSERT(g.BeginPopupStack.Size > 0);
// Make all menus and popups wrap around for now, may need to expose that policy. // Make all menus and popups wrap around for now, may need to expose that policy (e.g. focus scope could include wrap/loop policy flags used by new move requests)
if (g.NavWindow == window) if (g.NavWindow == window)
NavMoveRequestTryWrapping(window, ImGuiNavMoveFlags_LoopY); NavMoveRequestTryWrapping(window, ImGuiNavMoveFlags_LoopY);
@ -9587,26 +9607,26 @@ void ImGui::NavMoveRequestCancel()
NavUpdateAnyRequestFlag(); NavUpdateAnyRequestFlag();
} }
void ImGui::NavMoveRequestForward(ImGuiDir move_dir, ImGuiDir clip_dir, const ImRect& bb_rel, ImGuiNavMoveFlags move_flags) // Forward will reuse the move request again on the next frame (generally with modifications done to it)
void ImGui::NavMoveRequestForward(ImGuiDir move_dir, ImGuiDir clip_dir, ImGuiNavMoveFlags move_flags)
{ {
ImGuiContext& g = *GImGui; ImGuiContext& g = *GImGui;
IM_ASSERT(g.NavMoveRequestForward == ImGuiNavForward_None); IM_ASSERT(g.NavMoveRequestForwardToNextFrame == false);
NavMoveRequestCancel(); NavMoveRequestCancel();
g.NavMoveRequestForwardToNextFrame = true;
g.NavMoveDir = move_dir; g.NavMoveDir = move_dir;
g.NavMoveClipDir = clip_dir; g.NavMoveClipDir = clip_dir;
g.NavMoveRequestForward = ImGuiNavForward_ForwardQueued; g.NavMoveRequestFlags = move_flags | ImGuiNavMoveFlags_Forwarded;
g.NavMoveRequestFlags = move_flags;
g.NavWindow->NavRectRel[g.NavLayer] = bb_rel;
} }
void ImGui::NavMoveRequestTryWrapping(ImGuiWindow* window, ImGuiNavMoveFlags move_flags) // Navigation wrap-around logic is delayed to the end of the frame because this operation is only valid after entire
// popup is assembled and in case of appended popups it is not clear which EndPopup() call is final.
void ImGui::NavMoveRequestTryWrapping(ImGuiWindow* window, ImGuiNavMoveFlags wrap_flags)
{ {
ImGuiContext& g = *GImGui; ImGuiContext& g = *GImGui;
IM_ASSERT(wrap_flags != 0); // Call with _WrapX, _WrapY, _LoopX, _LoopY
// Navigation wrap-around logic is delayed to the end of the frame because this operation is only valid after entire if (g.NavWindow == window && g.NavMoveRequest && g.NavLayer == ImGuiNavLayer_Main)
// popup is assembled and in case of appended popups it is not clear which EndPopup() call is final. g.NavMoveRequestFlags |= wrap_flags;
g.NavWrapRequestWindow = window;
g.NavWrapRequestFlags = move_flags;
} }
// FIXME: This could be replaced by updating a frame number in each window when (window == NavWindow) and (NavLayer == 0). // FIXME: This could be replaced by updating a frame number in each window when (window == NavWindow) and (NavLayer == 0).
@ -9756,16 +9776,14 @@ static void ImGui::NavUpdate()
ImGuiIO& io = g.IO; ImGuiIO& io = g.IO;
io.WantSetMousePos = false; io.WantSetMousePos = false;
g.NavWrapRequestWindow = NULL;
g.NavWrapRequestFlags = ImGuiNavMoveFlags_None;
#if 0 #if 0
if (g.NavScoringCount > 0) IMGUI_DEBUG_LOG("NavScoringCount %d for '%s' layer %d (Init:%d, Move:%d)\n", g.FrameCount, g.NavScoringCount, g.NavWindow ? g.NavWindow->Name : "NULL", g.NavLayer, g.NavInitRequest || g.NavInitResultId != 0, g.NavMoveRequest); if (g.NavScoringCount > 0) IMGUI_DEBUG_LOG("NavScoringCount %d for '%s' layer %d (Init:%d, Move:%d)\n", g.FrameCount, g.NavScoringCount, g.NavWindow ? g.NavWindow->Name : "NULL", g.NavLayer, g.NavInitRequest || g.NavInitResultId != 0, g.NavMoveRequest);
#endif #endif
// Set input source as Gamepad when buttons are pressed (as some features differs when used with Gamepad vs Keyboard) // Set input source as Gamepad when buttons are pressed (as some features differs when used with Gamepad vs Keyboard)
// (do it before we map Keyboard input!) // (do it before we map Keyboard input!)
bool nav_keyboard_active = (io.ConfigFlags & ImGuiConfigFlags_NavEnableKeyboard) != 0; const bool nav_keyboard_active = (io.ConfigFlags & ImGuiConfigFlags_NavEnableKeyboard) != 0;
bool nav_gamepad_active = (io.ConfigFlags & ImGuiConfigFlags_NavEnableGamepad) != 0 && (io.BackendFlags & ImGuiBackendFlags_HasGamepad) != 0; const bool nav_gamepad_active = (io.ConfigFlags & ImGuiConfigFlags_NavEnableGamepad) != 0 && (io.BackendFlags & ImGuiBackendFlags_HasGamepad) != 0;
if (nav_gamepad_active && g.NavInputSource != ImGuiInputSource_Gamepad) if (nav_gamepad_active && g.NavInputSource != ImGuiInputSource_Gamepad)
{ {
if (io.NavInputs[ImGuiNavInput_Activate] > 0.0f || io.NavInputs[ImGuiNavInput_Input] > 0.0f || io.NavInputs[ImGuiNavInput_Cancel] > 0.0f || io.NavInputs[ImGuiNavInput_Menu] > 0.0f if (io.NavInputs[ImGuiNavInput_Activate] > 0.0f || io.NavInputs[ImGuiNavInput_Input] > 0.0f || io.NavInputs[ImGuiNavInput_Cancel] > 0.0f || io.NavInputs[ImGuiNavInput_Menu] > 0.0f
@ -9804,16 +9822,8 @@ static void ImGui::NavUpdate()
// Process navigation move request // Process navigation move request
if (g.NavMoveRequest) if (g.NavMoveRequest)
NavUpdateMoveResult(); NavMoveRequestApplyResult();
g.NavMoveRequest = false;
// When a forwarded move request failed, we restore the highlight that we disabled during the forward frame
if (g.NavMoveRequestForward == ImGuiNavForward_ForwardActive)
{
IM_ASSERT(g.NavMoveRequest);
if (g.NavMoveResultLocal.ID == 0 && g.NavMoveResultOther.ID == 0)
g.NavDisableHighlight = false;
g.NavMoveRequestForward = ImGuiNavForward_None;
}
// Apply application mouse position movement, after we had a chance to process move request result. // Apply application mouse position movement, after we had a chance to process move request result.
if (g.NavMousePosDirty && g.NavIdIsAlive) if (g.NavMousePosDirty && g.NavIdIsAlive)
@ -9831,7 +9841,7 @@ static void ImGui::NavUpdate()
g.NavJustTabbedId = 0; g.NavJustTabbedId = 0;
IM_ASSERT(g.NavLayer == 0 || g.NavLayer == 1); IM_ASSERT(g.NavLayer == 0 || g.NavLayer == 1);
// Store our return window (for returning from Layer 1 to Layer 0) and clear it as soon as we step back in our own Layer 0 // Store our return window (for returning from Menu Layer to Main Layer) and clear it as soon as we step back in our own Layer 0
if (g.NavWindow) if (g.NavWindow)
NavSaveLastChildNavWindowIntoParent(g.NavWindow); NavSaveLastChildNavWindowIntoParent(g.NavWindow);
if (g.NavWindow && g.NavWindow->NavLastChildNavWindow != NULL && g.NavLayer == ImGuiNavLayer_Main) if (g.NavWindow && g.NavWindow->NavLastChildNavWindow != NULL && g.NavLayer == ImGuiNavLayer_Main)
@ -9845,43 +9855,7 @@ static void ImGui::NavUpdate()
io.NavVisible = (io.NavActive && g.NavId != 0 && !g.NavDisableHighlight) || (g.NavWindowingTarget != NULL); io.NavVisible = (io.NavActive && g.NavId != 0 && !g.NavDisableHighlight) || (g.NavWindowingTarget != NULL);
// Process NavCancel input (to close a popup, get back to parent, clear focus) // Process NavCancel input (to close a popup, get back to parent, clear focus)
if (IsNavInputTest(ImGuiNavInput_Cancel, ImGuiInputReadMode_Pressed)) NavUpdateCancelRequest();
{
IMGUI_DEBUG_LOG_NAV("[nav] ImGuiNavInput_Cancel\n");
if (g.ActiveId != 0)
{
if (!IsActiveIdUsingNavInput(ImGuiNavInput_Cancel))
ClearActiveID();
}
else if (g.NavLayer != ImGuiNavLayer_Main)
{
// Leave the "menu" layer
NavRestoreLayer(ImGuiNavLayer_Main);
}
else if (g.NavWindow && g.NavWindow != g.NavWindow->RootWindow && !(g.NavWindow->Flags & ImGuiWindowFlags_Popup) && g.NavWindow->ParentWindow)
{
// Exit child window
ImGuiWindow* child_window = g.NavWindow;
ImGuiWindow* parent_window = g.NavWindow->ParentWindow;
IM_ASSERT(child_window->ChildId != 0);
ImRect child_rect = child_window->Rect();
FocusWindow(parent_window);
SetNavID(child_window->ChildId, ImGuiNavLayer_Main, 0, ImRect(child_rect.Min - parent_window->Pos, child_rect.Max - parent_window->Pos));
}
else if (g.OpenPopupStack.Size > 0)
{
// Close open popup/menu
if (!(g.OpenPopupStack.back().Window->Flags & ImGuiWindowFlags_Modal))
ClosePopupToLevel(g.OpenPopupStack.Size - 1, true);
}
else
{
// Clear NavLastId for popups but keep it for regular child window so we can leave one and come back where we were
if (g.NavWindow && ((g.NavWindow->Flags & ImGuiWindowFlags_Popup) || !(g.NavWindow->Flags & ImGuiWindowFlags_ChildWindow)))
g.NavWindow->NavLastIds[0] = 0;
g.NavId = g.NavFocusScopeId = 0;
}
}
// Process manual activation request // Process manual activation request
g.NavActivateId = g.NavActivateDownId = g.NavActivatePressedId = g.NavInputId = 0; g.NavActivateId = g.NavActivateDownId = g.NavActivatePressedId = g.NavInputId = 0;
@ -9902,59 +9876,14 @@ static void ImGui::NavUpdate()
g.NavDisableHighlight = true; g.NavDisableHighlight = true;
if (g.NavActivateId != 0) if (g.NavActivateId != 0)
IM_ASSERT(g.NavActivateDownId == g.NavActivateId); IM_ASSERT(g.NavActivateDownId == g.NavActivateId);
g.NavMoveRequest = false;
// Process programmatic activation request // Process programmatic activation request
if (g.NavNextActivateId != 0) if (g.NavNextActivateId != 0)
g.NavActivateId = g.NavActivateDownId = g.NavActivatePressedId = g.NavInputId = g.NavNextActivateId; g.NavActivateId = g.NavActivateDownId = g.NavActivatePressedId = g.NavInputId = g.NavNextActivateId;
g.NavNextActivateId = 0; g.NavNextActivateId = 0;
// Initiate directional inputs request // Process move requests
if (g.NavMoveRequestForward == ImGuiNavForward_None) NavUpdateCreateMoveRequest();
{
g.NavMoveDir = ImGuiDir_None;
g.NavMoveRequestFlags = ImGuiNavMoveFlags_None;
if (g.NavWindow && !g.NavWindowingTarget && !(g.NavWindow->Flags & ImGuiWindowFlags_NoNavInputs))
{
const ImGuiInputReadMode read_mode = ImGuiInputReadMode_Repeat;
if (!IsActiveIdUsingNavDir(ImGuiDir_Left) && (IsNavInputTest(ImGuiNavInput_DpadLeft, read_mode) || IsNavInputTest(ImGuiNavInput_KeyLeft_, read_mode))) { g.NavMoveDir = ImGuiDir_Left; }
if (!IsActiveIdUsingNavDir(ImGuiDir_Right) && (IsNavInputTest(ImGuiNavInput_DpadRight, read_mode) || IsNavInputTest(ImGuiNavInput_KeyRight_, read_mode))) { g.NavMoveDir = ImGuiDir_Right; }
if (!IsActiveIdUsingNavDir(ImGuiDir_Up) && (IsNavInputTest(ImGuiNavInput_DpadUp, read_mode) || IsNavInputTest(ImGuiNavInput_KeyUp_, read_mode))) { g.NavMoveDir = ImGuiDir_Up; }
if (!IsActiveIdUsingNavDir(ImGuiDir_Down) && (IsNavInputTest(ImGuiNavInput_DpadDown, read_mode) || IsNavInputTest(ImGuiNavInput_KeyDown_, read_mode))) { g.NavMoveDir = ImGuiDir_Down; }
}
g.NavMoveClipDir = g.NavMoveDir;
}
else
{
// Forwarding previous request (which has been modified, e.g. wrap around menus rewrite the requests with a starting rectangle at the other side of the window)
// (Preserve g.NavMoveRequestFlags, g.NavMoveClipDir which were set by the NavMoveRequestForward() function)
IM_ASSERT(g.NavMoveDir != ImGuiDir_None && g.NavMoveClipDir != ImGuiDir_None);
IM_ASSERT(g.NavMoveRequestForward == ImGuiNavForward_ForwardQueued);
IMGUI_DEBUG_LOG_NAV("[nav] NavMoveRequestForward %d\n", g.NavMoveDir);
g.NavMoveRequestForward = ImGuiNavForward_ForwardActive;
}
// Update PageUp/PageDown/Home/End scroll
// FIXME-NAV: Consider enabling those keys even without the master ImGuiConfigFlags_NavEnableKeyboard flag?
float nav_scoring_rect_offset_y = 0.0f;
if (nav_keyboard_active)
nav_scoring_rect_offset_y = NavUpdatePageUpPageDown();
// If we initiate a movement request and have no current NavId, we initiate a InitDefautRequest that will be used as a fallback if the direction fails to find a match
if (g.NavMoveDir != ImGuiDir_None)
{
g.NavMoveRequest = true;
g.NavMoveRequestKeyMods = io.KeyMods;
g.NavMoveDirLast = g.NavMoveDir;
}
if (g.NavMoveRequest && g.NavId == 0)
{
IMGUI_DEBUG_LOG_NAV("[nav] NavInitRequest: from move, window \"%s\", layer=%d\n", g.NavWindow->Name, g.NavLayer);
g.NavInitRequest = g.NavInitRequestFromMove = true;
// Reassigning with same value, we're being explicit here.
g.NavInitResultId = 0; // -V1048
g.NavDisableHighlight = false;
}
NavUpdateAnyRequestFlag(); NavUpdateAnyRequestFlag();
// Scrolling // Scrolling
@ -9963,7 +9892,7 @@ static void ImGui::NavUpdate()
// *Fallback* manual-scroll with Nav directional keys when window has no navigable item // *Fallback* manual-scroll with Nav directional keys when window has no navigable item
ImGuiWindow* window = g.NavWindow; ImGuiWindow* window = g.NavWindow;
const float scroll_speed = IM_ROUND(window->CalcFontSize() * 100 * io.DeltaTime); // We need round the scrolling speed because sub-pixel scroll isn't reliably supported. const float scroll_speed = IM_ROUND(window->CalcFontSize() * 100 * io.DeltaTime); // We need round the scrolling speed because sub-pixel scroll isn't reliably supported.
if (window->DC.NavLayersActiveMask == 0x00 && window->DC.NavHasScroll && g.NavMoveRequest) if (window->DC.NavLayersActiveMask == 0x00 && window->DC.NavHasScroll && g.NavMoveRequest) //-V560
{ {
if (g.NavMoveDir == ImGuiDir_Left || g.NavMoveDir == ImGuiDir_Right) if (g.NavMoveDir == ImGuiDir_Left || g.NavMoveDir == ImGuiDir_Right)
SetScrollX(window, ImFloor(window->Scroll.x + ((g.NavMoveDir == ImGuiDir_Left) ? -1.0f : +1.0f) * scroll_speed)); SetScrollX(window, ImFloor(window->Scroll.x + ((g.NavMoveDir == ImGuiDir_Left) ? -1.0f : +1.0f) * scroll_speed));
@ -9980,36 +9909,7 @@ static void ImGui::NavUpdate()
SetScrollY(window, ImFloor(window->Scroll.y + scroll_dir.y * scroll_speed)); SetScrollY(window, ImFloor(window->Scroll.y + scroll_dir.y * scroll_speed));
} }
// Reset search results // [DEBUG]
g.NavMoveResultLocal.Clear();
g.NavMoveResultLocalVisibleSet.Clear();
g.NavMoveResultOther.Clear();
// When using gamepad, we project the reference nav bounding box into window visible area.
// This is to allow resuming navigation inside the visible area after doing a large amount of scrolling, since with gamepad every movements are relative
// (can't focus a visible object like we can with the mouse).
if (g.NavMoveRequest && g.NavInputSource == ImGuiInputSource_Gamepad && g.NavLayer == ImGuiNavLayer_Main)
{
ImGuiWindow* window = g.NavWindow;
ImRect window_rect_rel(window->InnerRect.Min - window->Pos - ImVec2(1, 1), window->InnerRect.Max - window->Pos + ImVec2(1, 1));
if (!window_rect_rel.Contains(window->NavRectRel[g.NavLayer]))
{
IMGUI_DEBUG_LOG_NAV("[nav] NavMoveRequest: clamp NavRectRel\n");
float pad = window->CalcFontSize() * 0.5f;
window_rect_rel.Expand(ImVec2(-ImMin(window_rect_rel.GetWidth(), pad), -ImMin(window_rect_rel.GetHeight(), pad))); // Terrible approximation for the intent of starting navigation from first fully visible item
window->NavRectRel[g.NavLayer].ClipWithFull(window_rect_rel);
g.NavId = g.NavFocusScopeId = 0;
}
}
// For scoring we use a single segment on the left side our current item bounding box (not touching the edge to avoid box overlap with zero-spaced items)
ImRect nav_rect_rel = (g.NavWindow && !g.NavWindow->NavRectRel[g.NavLayer].IsInverted()) ? g.NavWindow->NavRectRel[g.NavLayer] : ImRect(0, 0, 0, 0);
g.NavScoringRect = g.NavWindow ? ImRect(g.NavWindow->Pos + nav_rect_rel.Min, g.NavWindow->Pos + nav_rect_rel.Max) : ImRect(0, 0, 0, 0);
g.NavScoringRect.TranslateY(nav_scoring_rect_offset_y);
g.NavScoringRect.Min.x = ImMin(g.NavScoringRect.Min.x + 1.0f, g.NavScoringRect.Max.x);
g.NavScoringRect.Max.x = g.NavScoringRect.Min.x;
IM_ASSERT(!g.NavScoringRect.IsInverted()); // Ensure if we have a finite, non-inverted bounding box here will allows us to remove extraneous ImFabs() calls in NavScoreItem().
//GetForegroundDrawList()->AddRect(g.NavScoringRectScreen.Min, g.NavScoringRectScreen.Max, IM_COL32(255,200,0,255)); // [DEBUG]
g.NavScoringCount = 0; g.NavScoringCount = 0;
#if IMGUI_DEBUG_NAV_RECTS #if IMGUI_DEBUG_NAV_RECTS
if (g.NavWindow) if (g.NavWindow)
@ -10039,10 +9939,100 @@ static void ImGui::NavUpdateInitResult()
} }
} }
// Apply result from previous frame navigation directional move request void ImGui::NavUpdateCreateMoveRequest()
static void ImGui::NavUpdateMoveResult()
{ {
ImGuiContext& g = *GImGui; ImGuiContext& g = *GImGui;
ImGuiIO& io = g.IO;
ImGuiWindow* window = g.NavWindow;
if (g.NavMoveRequestForwardToNextFrame)
{
// Forwarding previous request (which has been modified, e.g. wrap around menus rewrite the requests with a starting rectangle at the other side of the window)
// (preserve most state, which were already set by the NavMoveRequestForward() function)
IM_ASSERT(g.NavMoveDir != ImGuiDir_None && g.NavMoveClipDir != ImGuiDir_None);
IM_ASSERT(g.NavMoveRequestFlags & ImGuiNavMoveFlags_Forwarded);
IMGUI_DEBUG_LOG_NAV("[nav] NavMoveRequestForward %d\n", g.NavMoveDir);
g.NavMoveRequestForwardToNextFrame = false;
}
else
{
// Initiate directional inputs request
g.NavMoveDir = ImGuiDir_None;
g.NavMoveRequestFlags = ImGuiNavMoveFlags_None;
if (window && !g.NavWindowingTarget && !(window->Flags & ImGuiWindowFlags_NoNavInputs))
{
const ImGuiInputReadMode read_mode = ImGuiInputReadMode_Repeat;
if (!IsActiveIdUsingNavDir(ImGuiDir_Left) && (IsNavInputTest(ImGuiNavInput_DpadLeft, read_mode) || IsNavInputTest(ImGuiNavInput_KeyLeft_, read_mode))) { g.NavMoveDir = ImGuiDir_Left; }
if (!IsActiveIdUsingNavDir(ImGuiDir_Right) && (IsNavInputTest(ImGuiNavInput_DpadRight, read_mode) || IsNavInputTest(ImGuiNavInput_KeyRight_, read_mode))) { g.NavMoveDir = ImGuiDir_Right; }
if (!IsActiveIdUsingNavDir(ImGuiDir_Up) && (IsNavInputTest(ImGuiNavInput_DpadUp, read_mode) || IsNavInputTest(ImGuiNavInput_KeyUp_, read_mode))) { g.NavMoveDir = ImGuiDir_Up; }
if (!IsActiveIdUsingNavDir(ImGuiDir_Down) && (IsNavInputTest(ImGuiNavInput_DpadDown, read_mode) || IsNavInputTest(ImGuiNavInput_KeyDown_, read_mode))) { g.NavMoveDir = ImGuiDir_Down; }
}
g.NavMoveClipDir = g.NavMoveDir;
}
// Update PageUp/PageDown/Home/End scroll
// FIXME-NAV: Consider enabling those keys even without the master ImGuiConfigFlags_NavEnableKeyboard flag?
const bool nav_keyboard_active = (io.ConfigFlags & ImGuiConfigFlags_NavEnableKeyboard) != 0;
float nav_scoring_rect_offset_y = 0.0f;
if (nav_keyboard_active)
nav_scoring_rect_offset_y = NavUpdatePageUpPageDown();
// If we initiate a movement request and have no current NavId, we initiate a InitDefaultRequest that will be used as a fallback if the direction fails to find a match
if (g.NavMoveDir != ImGuiDir_None)
{
IM_ASSERT(window != NULL);
g.NavMoveRequest = true;
g.NavMoveRequestKeyMods = io.KeyMods;
g.NavMoveDirLast = g.NavMoveDir;
g.NavMoveResultLocal.Clear();
g.NavMoveResultLocalVisibleSet.Clear();
g.NavMoveResultOther.Clear();
}
// Moving with no reference triggers a init request
if (g.NavMoveRequest && g.NavId == 0)
{
IMGUI_DEBUG_LOG_NAV("[nav] NavInitRequest: from move, window \"%s\", layer=%d\n", g.NavWindow->Name, g.NavLayer);
g.NavInitRequest = g.NavInitRequestFromMove = true;
g.NavInitResultId = 0;
g.NavDisableHighlight = false;
}
// When using gamepad, we project the reference nav bounding box into window visible area.
// This is to allow resuming navigation inside the visible area after doing a large amount of scrolling, since with gamepad every movements are relative
// (can't focus a visible object like we can with the mouse).
if (g.NavMoveRequest && g.NavInputSource == ImGuiInputSource_Gamepad && g.NavLayer == ImGuiNavLayer_Main && window != NULL)
{
ImRect window_rect_rel(window->InnerRect.Min - window->Pos - ImVec2(1, 1), window->InnerRect.Max - window->Pos + ImVec2(1, 1));
if (!window_rect_rel.Contains(window->NavRectRel[g.NavLayer]))
{
IMGUI_DEBUG_LOG_NAV("[nav] NavMoveRequest: clamp NavRectRel\n");
float pad = window->CalcFontSize() * 0.5f;
window_rect_rel.Expand(ImVec2(-ImMin(window_rect_rel.GetWidth(), pad), -ImMin(window_rect_rel.GetHeight(), pad))); // Terrible approximation for the intent of starting navigation from first fully visible item
window->NavRectRel[g.NavLayer].ClipWithFull(window_rect_rel);
g.NavId = g.NavFocusScopeId = 0;
}
}
// For scoring we use a single segment on the left side our current item bounding box (not touching the edge to avoid box overlap with zero-spaced items)
g.NavScoringRect = ImRect();
if (window)
{
ImRect nav_rect_rel = !window->NavRectRel[g.NavLayer].IsInverted() ? window->NavRectRel[g.NavLayer] : ImRect(0, 0, 0, 0);
g.NavScoringRect = ImRect(window->Pos + nav_rect_rel.Min, window->Pos + nav_rect_rel.Max);
g.NavScoringRect.TranslateY(nav_scoring_rect_offset_y);
g.NavScoringRect.Min.x = ImMin(g.NavScoringRect.Min.x + 1.0f, g.NavScoringRect.Max.x);
g.NavScoringRect.Max.x = g.NavScoringRect.Min.x;
IM_ASSERT(!g.NavScoringRect.IsInverted()); // Ensure if we have a finite, non-inverted bounding box here will allows us to remove extraneous ImFabs() calls in NavScoreItem().
//GetForegroundDrawList()->AddRect(g.NavScoringRect.Min, g.NavScoringRect.Max, IM_COL32(255,200,0,255)); // [DEBUG]
}
}
// Apply result from previous frame navigation directional move request. Always called from NavUpdate()
void ImGui::NavMoveRequestApplyResult()
{
ImGuiContext& g = *GImGui;
if (g.NavMoveResultLocal.ID == 0 && g.NavMoveResultOther.ID == 0) if (g.NavMoveResultLocal.ID == 0 && g.NavMoveResultOther.ID == 0)
{ {
// In a situation when there is no results but NavId != 0, re-enable the Navigation highlight (because g.NavId is not considered as a possible result) // In a situation when there is no results but NavId != 0, re-enable the Navigation highlight (because g.NavId is not considered as a possible result)
@ -10104,7 +10094,54 @@ static void ImGui::NavUpdateMoveResult()
g.NavDisableMouseHover = g.NavMousePosDirty = true; g.NavDisableMouseHover = g.NavMousePosDirty = true;
} }
// Process NavCancel input (to close a popup, get back to parent, clear focus)
// FIXME: In order to support e.g. Escape to clear a selection we'll need:
// - either to store the equivalent of ActiveIdUsingKeyInputMask for a FocusScope and test for it.
// - either to move most/all of those tests to the epilogue/end functions of the scope they are dealing with (e.g. exit child window in EndChild()) or in EndFrame(), to allow an earlier intercept
static void ImGui::NavUpdateCancelRequest()
{
ImGuiContext& g = *GImGui;
if (!IsNavInputTest(ImGuiNavInput_Cancel, ImGuiInputReadMode_Pressed))
return;
IMGUI_DEBUG_LOG_NAV("[nav] ImGuiNavInput_Cancel\n");
if (g.ActiveId != 0)
{
if (!IsActiveIdUsingNavInput(ImGuiNavInput_Cancel))
ClearActiveID();
}
else if (g.NavLayer != ImGuiNavLayer_Main)
{
// Leave the "menu" layer
NavRestoreLayer(ImGuiNavLayer_Main);
}
else if (g.NavWindow && g.NavWindow != g.NavWindow->RootWindow && !(g.NavWindow->Flags & ImGuiWindowFlags_Popup) && g.NavWindow->ParentWindow)
{
// Exit child window
ImGuiWindow* child_window = g.NavWindow;
ImGuiWindow* parent_window = g.NavWindow->ParentWindow;
IM_ASSERT(child_window->ChildId != 0);
ImRect child_rect = child_window->Rect();
FocusWindow(parent_window);
SetNavID(child_window->ChildId, ImGuiNavLayer_Main, 0, ImRect(child_rect.Min - parent_window->Pos, child_rect.Max - parent_window->Pos));
}
else if (g.OpenPopupStack.Size > 0)
{
// Close open popup/menu
if (!(g.OpenPopupStack.back().Window->Flags & ImGuiWindowFlags_Modal))
ClosePopupToLevel(g.OpenPopupStack.Size - 1, true);
}
else
{
// Clear NavLastId for popups but keep it for regular child window so we can leave one and come back where we were
if (g.NavWindow && ((g.NavWindow->Flags & ImGuiWindowFlags_Popup) || !(g.NavWindow->Flags & ImGuiWindowFlags_ChildWindow)))
g.NavWindow->NavLastIds[0] = 0;
g.NavId = g.NavFocusScopeId = 0;
}
}
// Handle PageUp/PageDown/Home/End keys // Handle PageUp/PageDown/Home/End keys
// FIXME-NAV: how to get Home/End to aim at the beginning/end of a 2D grid?
static float ImGui::NavUpdatePageUpPageDown() static float ImGui::NavUpdatePageUpPageDown()
{ {
ImGuiContext& g = *GImGui; ImGuiContext& g = *GImGui;
@ -10120,60 +10157,60 @@ static float ImGui::NavUpdatePageUpPageDown()
const bool page_down_held = IsKeyDown(io.KeyMap[ImGuiKey_PageDown]) && !IsActiveIdUsingKey(ImGuiKey_PageDown); const bool page_down_held = IsKeyDown(io.KeyMap[ImGuiKey_PageDown]) && !IsActiveIdUsingKey(ImGuiKey_PageDown);
const bool home_pressed = IsKeyPressed(io.KeyMap[ImGuiKey_Home]) && !IsActiveIdUsingKey(ImGuiKey_Home); const bool home_pressed = IsKeyPressed(io.KeyMap[ImGuiKey_Home]) && !IsActiveIdUsingKey(ImGuiKey_Home);
const bool end_pressed = IsKeyPressed(io.KeyMap[ImGuiKey_End]) && !IsActiveIdUsingKey(ImGuiKey_End); const bool end_pressed = IsKeyPressed(io.KeyMap[ImGuiKey_End]) && !IsActiveIdUsingKey(ImGuiKey_End);
if (page_up_held != page_down_held || home_pressed != end_pressed) // If either (not both) are pressed if (page_up_held == page_down_held && home_pressed == end_pressed) // Proceed if either (not both) are pressed, otherwise early out
return 0.0f;
if (window->DC.NavLayersActiveMask == 0x00 && window->DC.NavHasScroll)
{ {
if (window->DC.NavLayersActiveMask == 0x00 && window->DC.NavHasScroll) // Fallback manual-scroll when window has no navigable item
if (IsKeyPressed(io.KeyMap[ImGuiKey_PageUp], true))
SetScrollY(window, window->Scroll.y - window->InnerRect.GetHeight());
else if (IsKeyPressed(io.KeyMap[ImGuiKey_PageDown], true))
SetScrollY(window, window->Scroll.y + window->InnerRect.GetHeight());
else if (home_pressed)
SetScrollY(window, 0.0f);
else if (end_pressed)
SetScrollY(window, window->ScrollMax.y);
}
else
{
ImRect& nav_rect_rel = window->NavRectRel[g.NavLayer];
const float page_offset_y = ImMax(0.0f, window->InnerRect.GetHeight() - window->CalcFontSize() * 1.0f + nav_rect_rel.GetHeight());
float nav_scoring_rect_offset_y = 0.0f;
if (IsKeyPressed(io.KeyMap[ImGuiKey_PageUp], true))
{ {
// Fallback manual-scroll when window has no navigable item nav_scoring_rect_offset_y = -page_offset_y;
if (IsKeyPressed(io.KeyMap[ImGuiKey_PageUp], true)) g.NavMoveDir = ImGuiDir_Down; // Because our scoring rect is offset up, we request the down direction (so we can always land on the last item)
SetScrollY(window, window->Scroll.y - window->InnerRect.GetHeight()); g.NavMoveClipDir = ImGuiDir_Up;
else if (IsKeyPressed(io.KeyMap[ImGuiKey_PageDown], true)) g.NavMoveRequestFlags = ImGuiNavMoveFlags_AllowCurrentNavId | ImGuiNavMoveFlags_AlsoScoreVisibleSet;
SetScrollY(window, window->Scroll.y + window->InnerRect.GetHeight());
else if (home_pressed)
SetScrollY(window, 0.0f);
else if (end_pressed)
SetScrollY(window, window->ScrollMax.y);
} }
else else if (IsKeyPressed(io.KeyMap[ImGuiKey_PageDown], true))
{ {
ImRect& nav_rect_rel = window->NavRectRel[g.NavLayer]; nav_scoring_rect_offset_y = +page_offset_y;
const float page_offset_y = ImMax(0.0f, window->InnerRect.GetHeight() - window->CalcFontSize() * 1.0f + nav_rect_rel.GetHeight()); g.NavMoveDir = ImGuiDir_Up; // Because our scoring rect is offset down, we request the up direction (so we can always land on the last item)
float nav_scoring_rect_offset_y = 0.0f; g.NavMoveClipDir = ImGuiDir_Down;
if (IsKeyPressed(io.KeyMap[ImGuiKey_PageUp], true)) g.NavMoveRequestFlags = ImGuiNavMoveFlags_AllowCurrentNavId | ImGuiNavMoveFlags_AlsoScoreVisibleSet;
{ }
nav_scoring_rect_offset_y = -page_offset_y; else if (home_pressed)
g.NavMoveDir = ImGuiDir_Down; // Because our scoring rect is offset up, we request the down direction (so we can always land on the last item) {
g.NavMoveClipDir = ImGuiDir_Up; // FIXME-NAV: handling of Home/End is assuming that the top/bottom most item will be visible with Scroll.y == 0/ScrollMax.y
g.NavMoveRequestFlags = ImGuiNavMoveFlags_AllowCurrentNavId | ImGuiNavMoveFlags_AlsoScoreVisibleSet; // Scrolling will be handled via the ImGuiNavMoveFlags_ScrollToEdge flag, we don't scroll immediately to avoid scrolling happening before nav result.
} // Preserve current horizontal position if we have any.
else if (IsKeyPressed(io.KeyMap[ImGuiKey_PageDown], true)) nav_rect_rel.Min.y = nav_rect_rel.Max.y = -window->Scroll.y;
{ if (nav_rect_rel.IsInverted())
nav_scoring_rect_offset_y = +page_offset_y; nav_rect_rel.Min.x = nav_rect_rel.Max.x = 0.0f;
g.NavMoveDir = ImGuiDir_Up; // Because our scoring rect is offset down, we request the up direction (so we can always land on the last item) g.NavMoveDir = ImGuiDir_Down;
g.NavMoveClipDir = ImGuiDir_Down; g.NavMoveRequestFlags = ImGuiNavMoveFlags_AllowCurrentNavId | ImGuiNavMoveFlags_ScrollToEdge;
g.NavMoveRequestFlags = ImGuiNavMoveFlags_AllowCurrentNavId | ImGuiNavMoveFlags_AlsoScoreVisibleSet;
}
else if (home_pressed)
{
// FIXME-NAV: handling of Home/End is assuming that the top/bottom most item will be visible with Scroll.y == 0/ScrollMax.y
// Scrolling will be handled via the ImGuiNavMoveFlags_ScrollToEdge flag, we don't scroll immediately to avoid scrolling happening before nav result.
// Preserve current horizontal position if we have any.
nav_rect_rel.Min.y = nav_rect_rel.Max.y = -window->Scroll.y;
if (nav_rect_rel.IsInverted())
nav_rect_rel.Min.x = nav_rect_rel.Max.x = 0.0f;
g.NavMoveDir = ImGuiDir_Down;
g.NavMoveRequestFlags = ImGuiNavMoveFlags_AllowCurrentNavId | ImGuiNavMoveFlags_ScrollToEdge;
}
else if (end_pressed)
{
nav_rect_rel.Min.y = nav_rect_rel.Max.y = window->ScrollMax.y + window->SizeFull.y - window->Scroll.y;
if (nav_rect_rel.IsInverted())
nav_rect_rel.Min.x = nav_rect_rel.Max.x = 0.0f;
g.NavMoveDir = ImGuiDir_Up;
g.NavMoveRequestFlags = ImGuiNavMoveFlags_AllowCurrentNavId | ImGuiNavMoveFlags_ScrollToEdge;
}
return nav_scoring_rect_offset_y;
} }
else if (end_pressed)
{
nav_rect_rel.Min.y = nav_rect_rel.Max.y = window->ScrollMax.y + window->SizeFull.y - window->Scroll.y;
if (nav_rect_rel.IsInverted())
nav_rect_rel.Min.x = nav_rect_rel.Max.x = 0.0f;
g.NavMoveDir = ImGuiDir_Up;
g.NavMoveRequestFlags = ImGuiNavMoveFlags_AllowCurrentNavId | ImGuiNavMoveFlags_ScrollToEdge;
}
return nav_scoring_rect_offset_y;
} }
return 0.0f; return 0.0f;
} }
@ -10187,13 +10224,14 @@ static void ImGui::NavEndFrame()
NavUpdateWindowingOverlay(); NavUpdateWindowingOverlay();
// Perform wrap-around in menus // Perform wrap-around in menus
ImGuiWindow* window = g.NavWrapRequestWindow; // FIXME-NAV: Wrap (not Loop) support could be handled by the scoring function and then WrapX would function without an extra frame.
ImGuiNavMoveFlags move_flags = g.NavWrapRequestFlags; ImGuiWindow* window = g.NavWindow;
if (window != NULL && g.NavWindow == window && NavMoveRequestButNoResultYet() && g.NavMoveRequestForward == ImGuiNavForward_None && g.NavLayer == ImGuiNavLayer_Main) const ImGuiNavMoveFlags move_flags = g.NavMoveRequestFlags;
const ImGuiNavMoveFlags wanted_flags = ImGuiNavMoveFlags_WrapX | ImGuiNavMoveFlags_LoopX | ImGuiNavMoveFlags_WrapY | ImGuiNavMoveFlags_LoopY;
if (window && NavMoveRequestButNoResultYet() && (g.NavMoveRequestFlags & wanted_flags) && (g.NavMoveRequestFlags & ImGuiNavMoveFlags_Forwarded) == 0)
{ {
IM_ASSERT(move_flags != 0); // No points calling this with no wrapping bool do_forward = false;
ImRect bb_rel = window->NavRectRel[0]; ImRect bb_rel = window->NavRectRel[g.NavLayer];
ImGuiDir clip_dir = g.NavMoveDir; ImGuiDir clip_dir = g.NavMoveDir;
if (g.NavMoveDir == ImGuiDir_Left && (move_flags & (ImGuiNavMoveFlags_WrapX | ImGuiNavMoveFlags_LoopX))) if (g.NavMoveDir == ImGuiDir_Left && (move_flags & (ImGuiNavMoveFlags_WrapX | ImGuiNavMoveFlags_LoopX)))
{ {
@ -10204,7 +10242,7 @@ static void ImGui::NavEndFrame()
bb_rel.TranslateY(-bb_rel.GetHeight()); bb_rel.TranslateY(-bb_rel.GetHeight());
clip_dir = ImGuiDir_Up; clip_dir = ImGuiDir_Up;
} }
NavMoveRequestForward(g.NavMoveDir, clip_dir, bb_rel, move_flags); do_forward = true;
} }
if (g.NavMoveDir == ImGuiDir_Right && (move_flags & (ImGuiNavMoveFlags_WrapX | ImGuiNavMoveFlags_LoopX))) if (g.NavMoveDir == ImGuiDir_Right && (move_flags & (ImGuiNavMoveFlags_WrapX | ImGuiNavMoveFlags_LoopX)))
{ {
@ -10214,7 +10252,7 @@ static void ImGui::NavEndFrame()
bb_rel.TranslateY(+bb_rel.GetHeight()); bb_rel.TranslateY(+bb_rel.GetHeight());
clip_dir = ImGuiDir_Down; clip_dir = ImGuiDir_Down;
} }
NavMoveRequestForward(g.NavMoveDir, clip_dir, bb_rel, move_flags); do_forward = true;
} }
if (g.NavMoveDir == ImGuiDir_Up && (move_flags & (ImGuiNavMoveFlags_WrapY | ImGuiNavMoveFlags_LoopY))) if (g.NavMoveDir == ImGuiDir_Up && (move_flags & (ImGuiNavMoveFlags_WrapY | ImGuiNavMoveFlags_LoopY)))
{ {
@ -10225,7 +10263,7 @@ static void ImGui::NavEndFrame()
bb_rel.TranslateX(-bb_rel.GetWidth()); bb_rel.TranslateX(-bb_rel.GetWidth());
clip_dir = ImGuiDir_Left; clip_dir = ImGuiDir_Left;
} }
NavMoveRequestForward(g.NavMoveDir, clip_dir, bb_rel, move_flags); do_forward = true;
} }
if (g.NavMoveDir == ImGuiDir_Down && (move_flags & (ImGuiNavMoveFlags_WrapY | ImGuiNavMoveFlags_LoopY))) if (g.NavMoveDir == ImGuiDir_Down && (move_flags & (ImGuiNavMoveFlags_WrapY | ImGuiNavMoveFlags_LoopY)))
{ {
@ -10235,7 +10273,12 @@ static void ImGui::NavEndFrame()
bb_rel.TranslateX(+bb_rel.GetWidth()); bb_rel.TranslateX(+bb_rel.GetWidth());
clip_dir = ImGuiDir_Right; clip_dir = ImGuiDir_Right;
} }
NavMoveRequestForward(g.NavMoveDir, clip_dir, bb_rel, move_flags); do_forward = true;
}
if (do_forward)
{
window->NavRectRel[g.NavLayer] = bb_rel;
NavMoveRequestForward(g.NavMoveDir, clip_dir, move_flags);
} }
} }
} }

@ -1,4 +1,4 @@
// dear imgui, v1.84 // dear imgui, v1.85 WIP
// (headers) // (headers)
// Help: // Help:
@ -15,7 +15,10 @@
// - Wiki https://github.com/ocornut/imgui/wiki (lots of good stuff there) // - Wiki https://github.com/ocornut/imgui/wiki (lots of good stuff there)
// - Glossary https://github.com/ocornut/imgui/wiki/Glossary // - Glossary https://github.com/ocornut/imgui/wiki/Glossary
// - Issues & support https://github.com/ocornut/imgui/issues // - Issues & support https://github.com/ocornut/imgui/issues
// - Discussions https://github.com/ocornut/imgui/discussions
// Getting Started?
// - For first-time users having issues compiling/linking/running or issues loading fonts:
// please post in https://github.com/ocornut/imgui/discussions if you cannot find a solution in resources above.
/* /*
@ -61,8 +64,8 @@ Index of this file:
// Version // Version
// (Integer encoded as XYYZZ for use in #if preprocessor conditionals. Work in progress versions typically starts at XYY99 then bounce up to XYY00, XYY01 etc. when release tagging happens) // (Integer encoded as XYYZZ for use in #if preprocessor conditionals. Work in progress versions typically starts at XYY99 then bounce up to XYY00, XYY01 etc. when release tagging happens)
#define IMGUI_VERSION "1.84.1" #define IMGUI_VERSION "1.85 WIP"
#define IMGUI_VERSION_NUM 18403 #define IMGUI_VERSION_NUM 18410
#define IMGUI_CHECKVERSION() ImGui::DebugCheckVersionAndDataLayout(IMGUI_VERSION, sizeof(ImGuiIO), sizeof(ImGuiStyle), sizeof(ImVec2), sizeof(ImVec4), sizeof(ImDrawVert), sizeof(ImDrawIdx)) #define IMGUI_CHECKVERSION() ImGui::DebugCheckVersionAndDataLayout(IMGUI_VERSION, sizeof(ImGuiIO), sizeof(ImGuiStyle), sizeof(ImVec2), sizeof(ImVec4), sizeof(ImDrawVert), sizeof(ImDrawIdx))
#define IMGUI_HAS_TABLE #define IMGUI_HAS_TABLE
#define IMGUI_HAS_VIEWPORT // Viewport WIP branch #define IMGUI_HAS_VIEWPORT // Viewport WIP branch
@ -166,7 +169,7 @@ struct ImGuiTextFilter; // Helper to parse and apply text filters (e
struct ImGuiViewport; // A Platform Window (always 1 unless multi-viewport are enabled. One per platform window to output to). In the future may represent Platform Monitor struct ImGuiViewport; // A Platform Window (always 1 unless multi-viewport are enabled. One per platform window to output to). In the future may represent Platform Monitor
struct ImGuiWindowClass; // Window class (rare/advanced uses: provide hints to the platform backend via altered viewport flags and parent/child info) struct ImGuiWindowClass; // Window class (rare/advanced uses: provide hints to the platform backend via altered viewport flags and parent/child info)
// Enums/Flags (declared as int for compatibility with old C++, to allow using as flags and to not pollute the top of this file) // Enums/Flags (declared as int for compatibility with old C++, to allow using as flags without overhead, and to not pollute the top of this file)
// - Tip: Use your programming IDE navigation facilities on the names in the _central column_ below to find the actual flags/enum lists! // - Tip: Use your programming IDE navigation facilities on the names in the _central column_ below to find the actual flags/enum lists!
// In Visual Studio IDE: CTRL+comma ("Edit.NavigateTo") can follow symbols in comments, whereas CTRL+F12 ("Edit.GoToImplementation") cannot. // In Visual Studio IDE: CTRL+comma ("Edit.NavigateTo") can follow symbols in comments, whereas CTRL+F12 ("Edit.GoToImplementation") cannot.
// With Visual Assist installed: ALT+G ("VAssistX.GoToImplementation") can also follow symbols in comments. // With Visual Assist installed: ALT+G ("VAssistX.GoToImplementation") can also follow symbols in comments.
@ -207,27 +210,22 @@ typedef int ImGuiTreeNodeFlags; // -> enum ImGuiTreeNodeFlags_ // Flags: f
typedef int ImGuiViewportFlags; // -> enum ImGuiViewportFlags_ // Flags: for ImGuiViewport typedef int ImGuiViewportFlags; // -> enum ImGuiViewportFlags_ // Flags: for ImGuiViewport
typedef int ImGuiWindowFlags; // -> enum ImGuiWindowFlags_ // Flags: for Begin(), BeginChild() typedef int ImGuiWindowFlags; // -> enum ImGuiWindowFlags_ // Flags: for Begin(), BeginChild()
// Other types // ImTexture: user data for renderer backend to identify a texture [Compile-time configurable type]
#ifndef ImTextureID // ImTextureID [configurable type: override in imconfig.h with '#define ImTextureID xxx'] // - To use something else than an opaque void* pointer: override with e.g. '#define ImTextureID MyTextureType*' in your imconfig.h file.
typedef void* ImTextureID; // User data for rendering backend to identify a texture. This is whatever to you want it to be! read the FAQ about ImTextureID for details. // - This can be whatever to you want it to be! read the FAQ about ImTextureID for details.
#ifndef ImTextureID
typedef void* ImTextureID; // Default: store a pointer or an integer fitting in a pointer (most renderer backends are ok with that)
#endif #endif
typedef unsigned int ImGuiID; // A unique ID used by widgets, typically hashed from a stack of string.
typedef int (*ImGuiInputTextCallback)(ImGuiInputTextCallbackData* data); // Callback function for ImGui::InputText()
typedef void (*ImGuiSizeCallback)(ImGuiSizeCallbackData* data); // Callback function for ImGui::SetNextWindowSizeConstraints()
typedef void* (*ImGuiMemAllocFunc)(size_t sz, void* user_data); // Function signature for ImGui::SetAllocatorFunctions()
typedef void (*ImGuiMemFreeFunc)(void* ptr, void* user_data); // Function signature for ImGui::SetAllocatorFunctions()
// Character types // ImDrawIdx: vertex index. [Compile-time configurable type]
// (we generally use UTF-8 encoded string in the API. This is storage specifically for a decoded character used for keyboard input and display) // - To use 16-bit indices + allow large meshes: backend need to set 'io.BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset' and handle ImDrawCmd::VtxOffset (recommended).
typedef unsigned short ImWchar16; // A single decoded U16 character/code point. We encode them as multi bytes UTF-8 when used in strings. // - To use 32-bit indices: override with '#define ImDrawIdx unsigned int' in your imconfig.h file.
typedef unsigned int ImWchar32; // A single decoded U32 character/code point. We encode them as multi bytes UTF-8 when used in strings. #ifndef ImDrawIdx
#ifdef IMGUI_USE_WCHAR32 // ImWchar [configurable type: override in imconfig.h with '#define IMGUI_USE_WCHAR32' to support Unicode planes 1-16] typedef unsigned short ImDrawIdx; // Default: 16-bit (for maximum compatibility with renderer backends)
typedef ImWchar32 ImWchar;
#else
typedef ImWchar16 ImWchar;
#endif #endif
// Basic scalar data types // Scalar data types
typedef unsigned int ImGuiID;// A unique ID used by widgets (typically the result of hashing a stack of string)
typedef signed char ImS8; // 8-bit signed integer typedef signed char ImS8; // 8-bit signed integer
typedef unsigned char ImU8; // 8-bit unsigned integer typedef unsigned char ImU8; // 8-bit unsigned integer
typedef signed short ImS16; // 16-bit signed integer typedef signed short ImS16; // 16-bit signed integer
@ -246,7 +244,24 @@ typedef signed long long ImS64; // 64-bit signed integer (post C++11)
typedef unsigned long long ImU64; // 64-bit unsigned integer (post C++11) typedef unsigned long long ImU64; // 64-bit unsigned integer (post C++11)
#endif #endif
// 2D vector (often used to store positions or sizes) // Character types
// (we generally use UTF-8 encoded string in the API. This is storage specifically for a decoded character used for keyboard input and display)
typedef unsigned short ImWchar16; // A single decoded U16 character/code point. We encode them as multi bytes UTF-8 when used in strings.
typedef unsigned int ImWchar32; // A single decoded U32 character/code point. We encode them as multi bytes UTF-8 when used in strings.
#ifdef IMGUI_USE_WCHAR32 // ImWchar [configurable type: override in imconfig.h with '#define IMGUI_USE_WCHAR32' to support Unicode planes 1-16]
typedef ImWchar32 ImWchar;
#else
typedef ImWchar16 ImWchar;
#endif
// Callback and functions types
typedef int (*ImGuiInputTextCallback)(ImGuiInputTextCallbackData* data); // Callback function for ImGui::InputText()
typedef void (*ImGuiSizeCallback)(ImGuiSizeCallbackData* data); // Callback function for ImGui::SetNextWindowSizeConstraints()
typedef void* (*ImGuiMemAllocFunc)(size_t sz, void* user_data); // Function signature for ImGui::SetAllocatorFunctions()
typedef void (*ImGuiMemFreeFunc)(void* ptr, void* user_data); // Function signature for ImGui::SetAllocatorFunctions()
// ImVec2: 2D vector used to store positions, sizes etc. [Compile-time configurable type]
// This is a frequently used type in the API. Consider using IM_VEC2_CLASS_EXTRA to create implicit cast from/to our preferred type.
IM_MSVC_RUNTIME_CHECKS_OFF IM_MSVC_RUNTIME_CHECKS_OFF
struct ImVec2 struct ImVec2
{ {
@ -260,7 +275,7 @@ struct ImVec2
#endif #endif
}; };
// 4D vector (often used to store floating-point colors) // ImVec4: 4D vector used to store clipping rectangles, colors etc. [Compile-time configurable type]
struct ImVec4 struct ImVec4
{ {
float x, y, z, w; float x, y, z, w;
@ -377,9 +392,8 @@ namespace ImGui
// - Those functions are bound to be redesigned (they are confusing, incomplete and the Min/Max return values are in local window coordinates which increases confusion) // - Those functions are bound to be redesigned (they are confusing, incomplete and the Min/Max return values are in local window coordinates which increases confusion)
IMGUI_API ImVec2 GetContentRegionAvail(); // == GetContentRegionMax() - GetCursorPos() IMGUI_API ImVec2 GetContentRegionAvail(); // == GetContentRegionMax() - GetCursorPos()
IMGUI_API ImVec2 GetContentRegionMax(); // current content boundaries (typically window boundaries including scrolling, or current column boundaries), in windows coordinates IMGUI_API ImVec2 GetContentRegionMax(); // current content boundaries (typically window boundaries including scrolling, or current column boundaries), in windows coordinates
IMGUI_API ImVec2 GetWindowContentRegionMin(); // content boundaries min (roughly (0,0)-Scroll), in window coordinates IMGUI_API ImVec2 GetWindowContentRegionMin(); // content boundaries min for the full window (roughly (0,0)-Scroll), in window coordinates
IMGUI_API ImVec2 GetWindowContentRegionMax(); // content boundaries max (roughly (0,0)+Size-Scroll) where Size can be override with SetNextWindowContentSize(), in window coordinates IMGUI_API ImVec2 GetWindowContentRegionMax(); // content boundaries max for the full window (roughly (0,0)+Size-Scroll) where Size can be override with SetNextWindowContentSize(), in window coordinates
IMGUI_API float GetWindowContentRegionWidth(); //
// Windows Scrolling // Windows Scrolling
IMGUI_API float GetScrollX(); // get scrolling amount [0 .. GetScrollMaxX()] IMGUI_API float GetScrollX(); // get scrolling amount [0 .. GetScrollMaxX()]
@ -628,7 +642,7 @@ namespace ImGui
IMGUI_API bool ListBox(const char* label, int* current_item, bool (*items_getter)(void* data, int idx, const char** out_text), void* data, int items_count, int height_in_items = -1); IMGUI_API bool ListBox(const char* label, int* current_item, bool (*items_getter)(void* data, int idx, const char** out_text), void* data, int items_count, int height_in_items = -1);
// Widgets: Data Plotting // Widgets: Data Plotting
// - Consider using ImPlot (https://github.com/epezent/implot) // - Consider using ImPlot (https://github.com/epezent/implot) which is much better!
IMGUI_API void PlotLines(const char* label, const float* values, int values_count, int values_offset = 0, const char* overlay_text = NULL, float scale_min = FLT_MAX, float scale_max = FLT_MAX, ImVec2 graph_size = ImVec2(0, 0), int stride = sizeof(float)); IMGUI_API void PlotLines(const char* label, const float* values, int values_count, int values_offset = 0, const char* overlay_text = NULL, float scale_min = FLT_MAX, float scale_max = FLT_MAX, ImVec2 graph_size = ImVec2(0, 0), int stride = sizeof(float));
IMGUI_API void PlotLines(const char* label, float(*values_getter)(void* data, int idx), void* data, int values_count, int values_offset = 0, const char* overlay_text = NULL, float scale_min = FLT_MAX, float scale_max = FLT_MAX, ImVec2 graph_size = ImVec2(0, 0)); IMGUI_API void PlotLines(const char* label, float(*values_getter)(void* data, int idx), void* data, int values_count, int values_offset = 0, const char* overlay_text = NULL, float scale_min = FLT_MAX, float scale_max = FLT_MAX, ImVec2 graph_size = ImVec2(0, 0));
IMGUI_API void PlotHistogram(const char* label, const float* values, int values_count, int values_offset = 0, const char* overlay_text = NULL, float scale_min = FLT_MAX, float scale_max = FLT_MAX, ImVec2 graph_size = ImVec2(0, 0), int stride = sizeof(float)); IMGUI_API void PlotHistogram(const char* label, const float* values, int values_count, int values_offset = 0, const char* overlay_text = NULL, float scale_min = FLT_MAX, float scale_max = FLT_MAX, ImVec2 graph_size = ImVec2(0, 0), int stride = sizeof(float));
@ -831,6 +845,7 @@ namespace ImGui
// Disabling [BETA API] // Disabling [BETA API]
// - Disable all user interactions and dim items visuals (applying style.DisabledAlpha over current colors) // - Disable all user interactions and dim items visuals (applying style.DisabledAlpha over current colors)
// - Those can be nested but it cannot be used to enable an already disabled section (a single BeginDisabled(true) in the stack is enough to keep everything disabled)
// - BeginDisabled(false) essentially does nothing useful but is provided to facilitate use of boolean expressions. If you can avoid calling BeginDisabled(False)/EndDisabled() best to avoid it. // - BeginDisabled(false) essentially does nothing useful but is provided to facilitate use of boolean expressions. If you can avoid calling BeginDisabled(False)/EndDisabled() best to avoid it.
IMGUI_API void BeginDisabled(bool disabled = true); IMGUI_API void BeginDisabled(bool disabled = true);
IMGUI_API void EndDisabled(); IMGUI_API void EndDisabled();
@ -1987,6 +2002,7 @@ struct ImGuiIO
// [Internal] Dear ImGui will maintain those fields. Forward compatibility not guaranteed! // [Internal] Dear ImGui will maintain those fields. Forward compatibility not guaranteed!
//------------------------------------------------------------------ //------------------------------------------------------------------
bool WantCaptureMouseUnlessPopupClose;// Alternative to WantCaptureMouse: (WantCaptureMouse == true && WantCaptureMouseUnlessPopupClose == false) when a click over void is expected to close a popup.
ImGuiKeyModFlags KeyMods; // Key mods flags (same as io.KeyCtrl/KeyShift/KeyAlt/KeySuper but merged into flags), updated by NewFrame() ImGuiKeyModFlags KeyMods; // Key mods flags (same as io.KeyCtrl/KeyShift/KeyAlt/KeySuper but merged into flags), updated by NewFrame()
ImGuiKeyModFlags KeyModsPrev; // Previous key mods ImGuiKeyModFlags KeyModsPrev; // Previous key mods
ImVec2 MousePosPrev; // Previous mouse position (note that MouseDelta is not necessary == MousePos-MousePosPrev, in case either position is invalid) ImVec2 MousePosPrev; // Previous mouse position (note that MouseDelta is not necessary == MousePos-MousePosPrev, in case either position is invalid)
@ -1995,7 +2011,8 @@ struct ImGuiIO
bool MouseClicked[5]; // Mouse button went from !Down to Down bool MouseClicked[5]; // Mouse button went from !Down to Down
bool MouseDoubleClicked[5]; // Has mouse button been double-clicked? bool MouseDoubleClicked[5]; // Has mouse button been double-clicked?
bool MouseReleased[5]; // Mouse button went from Down to !Down bool MouseReleased[5]; // Mouse button went from Down to !Down
bool MouseDownOwned[5]; // Track if button was clicked inside a dear imgui window. We don't request mouse capture from the application if click started outside ImGui bounds. bool MouseDownOwned[5]; // Track if button was clicked inside a dear imgui window or over void blocked by a popup. We don't request mouse capture from the application if click started outside ImGui bounds.
bool MouseDownOwnedUnlessPopupClose[5];//Track if button was clicked inside a dear imgui window.
bool MouseDownWasDoubleClick[5]; // Track if button down was a double-click bool MouseDownWasDoubleClick[5]; // Track if button down was a double-click
float MouseDownDuration[5]; // Duration the mouse button has been down (0.0f == just clicked) float MouseDownDuration[5]; // Duration the mouse button has been down (0.0f == just clicked)
float MouseDownDurationPrev[5]; // Previous time the mouse button has been down float MouseDownDurationPrev[5]; // Previous time the mouse button has been down
@ -2382,13 +2399,6 @@ struct ImDrawCmd
inline ImTextureID GetTexID() const { return TextureId; } inline ImTextureID GetTexID() const { return TextureId; }
}; };
// Vertex index, default to 16-bit
// To allow large meshes with 16-bit indices: set 'io.BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset' and handle ImDrawCmd::VtxOffset in the renderer backend (recommended).
// To use 32-bit indices: override with '#define ImDrawIdx unsigned int' in imconfig.h.
#ifndef ImDrawIdx
typedef unsigned short ImDrawIdx;
#endif
// Vertex layout // Vertex layout
#ifndef IMGUI_OVERRIDE_DRAWVERT_STRUCT_LAYOUT #ifndef IMGUI_OVERRIDE_DRAWVERT_STRUCT_LAYOUT
struct ImDrawVert struct ImDrawVert
@ -3067,6 +3077,8 @@ struct ImGuiPlatformMonitor
#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS #ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS
namespace ImGui namespace ImGui
{ {
// OBSOLETED in 1.85 (from August 2021)
static inline float GetWindowContentRegionWidth() { return GetWindowContentRegionMax().x - GetWindowContentRegionMin().x; }
// OBSOLETED in 1.81 (from February 2021) // OBSOLETED in 1.81 (from February 2021)
IMGUI_API bool ListBoxHeader(const char* label, int items_count, int height_in_items = -1); // Helper to calculate size from items_count and height_in_items IMGUI_API bool ListBoxHeader(const char* label, int items_count, int height_in_items = -1); // Helper to calculate size from items_count and height_in_items
static inline bool ListBoxHeader(const char* label, const ImVec2& size = ImVec2(0, 0)) { return BeginListBox(label, size); } static inline bool ListBoxHeader(const char* label, const ImVec2& size = ImVec2(0, 0)) { return BeginListBox(label, size); }

@ -1,4 +1,4 @@
// dear imgui, v1.84 // dear imgui, v1.85 WIP
// (demo code) // (demo code)
// Help: // Help:
@ -2427,7 +2427,7 @@ static void ShowDemoWindowLayout()
ImGuiWindowFlags window_flags = ImGuiWindowFlags_HorizontalScrollbar; ImGuiWindowFlags window_flags = ImGuiWindowFlags_HorizontalScrollbar;
if (disable_mouse_wheel) if (disable_mouse_wheel)
window_flags |= ImGuiWindowFlags_NoScrollWithMouse; window_flags |= ImGuiWindowFlags_NoScrollWithMouse;
ImGui::BeginChild("ChildL", ImVec2(ImGui::GetWindowContentRegionWidth() * 0.5f, 260), false, window_flags); ImGui::BeginChild("ChildL", ImVec2(ImGui::GetContentRegionAvail().x * 0.5f, 260), false, window_flags);
for (int i = 0; i < 100; i++) for (int i = 0; i < 100; i++)
ImGui::Text("%04d: scrollable region", i); ImGui::Text("%04d: scrollable region", i);
ImGui::EndChild(); ImGui::EndChild();
@ -5536,6 +5536,7 @@ static void ShowDemoWindowMisc()
// Display ImGuiIO output flags // Display ImGuiIO output flags
ImGui::Text("WantCaptureMouse: %d", io.WantCaptureMouse); ImGui::Text("WantCaptureMouse: %d", io.WantCaptureMouse);
ImGui::Text("WantCaptureMouseUnlessPopupClose: %d", io.WantCaptureMouseUnlessPopupClose);
ImGui::Text("WantCaptureKeyboard: %d", io.WantCaptureKeyboard); ImGui::Text("WantCaptureKeyboard: %d", io.WantCaptureKeyboard);
ImGui::Text("WantTextInput: %d", io.WantTextInput); ImGui::Text("WantTextInput: %d", io.WantTextInput);
ImGui::Text("WantSetMousePos: %d", io.WantSetMousePos); ImGui::Text("WantSetMousePos: %d", io.WantSetMousePos);

@ -1,4 +1,4 @@
// dear imgui, v1.84 // dear imgui, v1.85 WIP
// (drawing and font code) // (drawing and font code)
/* /*
@ -2004,7 +2004,7 @@ void ImFontAtlas::ClearInputData()
ConfigData.clear(); ConfigData.clear();
CustomRects.clear(); CustomRects.clear();
PackIdMouseCursors = PackIdLines = -1; PackIdMouseCursors = PackIdLines = -1;
TexReady = false; // Important: we leave TexReady untouched
} }
void ImFontAtlas::ClearTexData() void ImFontAtlas::ClearTexData()

@ -1,4 +1,4 @@
// dear imgui, v1.84 // dear imgui, v1.85 WIP
// (internal structures/api) // (internal structures/api)
// You may use this file to debug, understand or extend ImGui features but we don't provide any guarantee of forward compatibility! // You may use this file to debug, understand or extend ImGui features but we don't provide any guarantee of forward compatibility!
@ -18,6 +18,7 @@ Index of this file:
// [SECTION] Generic helpers // [SECTION] Generic helpers
// [SECTION] ImDrawList support // [SECTION] ImDrawList support
// [SECTION] Widgets support: flags, enums, data structures // [SECTION] Widgets support: flags, enums, data structures
// [SECTION] Navigation support
// [SECTION] Columns support // [SECTION] Columns support
// [SECTION] Multi-select support // [SECTION] Multi-select support
// [SECTION] Docking support // [SECTION] Docking support
@ -82,19 +83,13 @@ Index of this file:
#pragma clang diagnostic ignored "-Wzero-as-null-pointer-constant" #pragma clang diagnostic ignored "-Wzero-as-null-pointer-constant"
#pragma clang diagnostic ignored "-Wdouble-promotion" #pragma clang diagnostic ignored "-Wdouble-promotion"
#pragma clang diagnostic ignored "-Wimplicit-int-float-conversion" // warning: implicit conversion from 'xxx' to 'float' may lose precision #pragma clang diagnostic ignored "-Wimplicit-int-float-conversion" // warning: implicit conversion from 'xxx' to 'float' may lose precision
#pragma clang diagnostic ignored "-Wmissing-noreturn" // warning: function 'xxx' could be declared with attribute 'noreturn'
#elif defined(__GNUC__) #elif defined(__GNUC__)
#pragma GCC diagnostic push #pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wpragmas" // warning: unknown option after '#pragma GCC diagnostic' kind #pragma GCC diagnostic ignored "-Wpragmas" // warning: unknown option after '#pragma GCC diagnostic' kind
#pragma GCC diagnostic ignored "-Wclass-memaccess" // [__GNUC__ >= 8] warning: 'memset/memcpy' clearing/writing an object of type 'xxxx' with no trivial copy-assignment; use assignment or value-initialization instead #pragma GCC diagnostic ignored "-Wclass-memaccess" // [__GNUC__ >= 8] warning: 'memset/memcpy' clearing/writing an object of type 'xxxx' with no trivial copy-assignment; use assignment or value-initialization instead
#endif #endif
// Helper macros
#if defined(__clang__)
#define IM_NORETURN __attribute__((noreturn))
#else
#define IM_NORETURN
#endif
// Legacy defines // Legacy defines
#ifdef IMGUI_DISABLE_FORMAT_STRING_FUNCTIONS // Renamed in 1.74 #ifdef IMGUI_DISABLE_FORMAT_STRING_FUNCTIONS // Renamed in 1.74
#error Use IMGUI_DISABLE_DEFAULT_FORMAT_FUNCTIONS #error Use IMGUI_DISABLE_DEFAULT_FORMAT_FUNCTIONS
@ -933,49 +928,6 @@ enum ImGuiInputReadMode
ImGuiInputReadMode_RepeatFast ImGuiInputReadMode_RepeatFast
}; };
enum ImGuiNavHighlightFlags_
{
ImGuiNavHighlightFlags_None = 0,
ImGuiNavHighlightFlags_TypeDefault = 1 << 0,
ImGuiNavHighlightFlags_TypeThin = 1 << 1,
ImGuiNavHighlightFlags_AlwaysDraw = 1 << 2, // Draw rectangular highlight if (g.NavId == id) _even_ when using the mouse.
ImGuiNavHighlightFlags_NoRounding = 1 << 3
};
enum ImGuiNavDirSourceFlags_
{
ImGuiNavDirSourceFlags_None = 0,
ImGuiNavDirSourceFlags_Keyboard = 1 << 0,
ImGuiNavDirSourceFlags_PadDPad = 1 << 1,
ImGuiNavDirSourceFlags_PadLStick = 1 << 2
};
enum ImGuiNavMoveFlags_
{
ImGuiNavMoveFlags_None = 0,
ImGuiNavMoveFlags_LoopX = 1 << 0, // On failed request, restart from opposite side
ImGuiNavMoveFlags_LoopY = 1 << 1,
ImGuiNavMoveFlags_WrapX = 1 << 2, // On failed request, request from opposite side one line down (when NavDir==right) or one line up (when NavDir==left)
ImGuiNavMoveFlags_WrapY = 1 << 3, // This is not super useful for provided for completeness
ImGuiNavMoveFlags_AllowCurrentNavId = 1 << 4, // Allow scoring and considering the current NavId as a move target candidate. This is used when the move source is offset (e.g. pressing PageDown actually needs to send a Up move request, if we are pressing PageDown from the bottom-most item we need to stay in place)
ImGuiNavMoveFlags_AlsoScoreVisibleSet = 1 << 5, // Store alternate result in NavMoveResultLocalVisibleSet that only comprise elements that are already fully visible.
ImGuiNavMoveFlags_ScrollToEdge = 1 << 6
};
enum ImGuiNavForward
{
ImGuiNavForward_None,
ImGuiNavForward_ForwardQueued,
ImGuiNavForward_ForwardActive
};
enum ImGuiNavLayer
{
ImGuiNavLayer_Main = 0, // Main scrolling layer
ImGuiNavLayer_Menu = 1, // Menu layer (access with Alt/ImGuiNavInput_Menu)
ImGuiNavLayer_COUNT
};
enum ImGuiPopupPositionPolicy enum ImGuiPopupPositionPolicy
{ {
ImGuiPopupPositionPolicy_Default, ImGuiPopupPositionPolicy_Default,
@ -1122,20 +1074,6 @@ struct ImGuiPopupData
ImGuiPopupData() { memset(this, 0, sizeof(*this)); OpenFrameCount = -1; } ImGuiPopupData() { memset(this, 0, sizeof(*this)); OpenFrameCount = -1; }
}; };
struct ImGuiNavItemData
{
ImGuiWindow* Window; // Init,Move // Best candidate window (result->ItemWindow->RootWindowForNav == request->Window)
ImGuiID ID; // Init,Move // Best candidate item ID
ImGuiID FocusScopeId; // Init,Move // Best candidate focus scope ID
ImRect RectRel; // Init,Move // Best candidate bounding box in window relative space
float DistBox; // Move // Best candidate box distance to current NavId
float DistCenter; // Move // Best candidate center distance to current NavId
float DistAxial; // Move // Best candidate axial distance to current NavId
ImGuiNavItemData() { Clear(); }
void Clear() { Window = NULL; ID = FocusScopeId = 0; RectRel = ImRect(); DistBox = DistCenter = DistAxial = FLT_MAX; }
};
enum ImGuiNextWindowDataFlags_ enum ImGuiNextWindowDataFlags_
{ {
ImGuiNextWindowDataFlags_None = 0, ImGuiNextWindowDataFlags_None = 0,
@ -1233,6 +1171,61 @@ struct ImGuiPtrOrIndex
ImGuiPtrOrIndex(int index) { Ptr = NULL; Index = index; } ImGuiPtrOrIndex(int index) { Ptr = NULL; Index = index; }
}; };
//-----------------------------------------------------------------------------
// [SECTION] Navigation support
//-----------------------------------------------------------------------------
enum ImGuiNavHighlightFlags_
{
ImGuiNavHighlightFlags_None = 0,
ImGuiNavHighlightFlags_TypeDefault = 1 << 0,
ImGuiNavHighlightFlags_TypeThin = 1 << 1,
ImGuiNavHighlightFlags_AlwaysDraw = 1 << 2, // Draw rectangular highlight if (g.NavId == id) _even_ when using the mouse.
ImGuiNavHighlightFlags_NoRounding = 1 << 3
};
enum ImGuiNavDirSourceFlags_
{
ImGuiNavDirSourceFlags_None = 0,
ImGuiNavDirSourceFlags_Keyboard = 1 << 0,
ImGuiNavDirSourceFlags_PadDPad = 1 << 1,
ImGuiNavDirSourceFlags_PadLStick = 1 << 2
};
enum ImGuiNavMoveFlags_
{
ImGuiNavMoveFlags_None = 0,
ImGuiNavMoveFlags_LoopX = 1 << 0, // On failed request, restart from opposite side
ImGuiNavMoveFlags_LoopY = 1 << 1,
ImGuiNavMoveFlags_WrapX = 1 << 2, // On failed request, request from opposite side one line down (when NavDir==right) or one line up (when NavDir==left)
ImGuiNavMoveFlags_WrapY = 1 << 3, // This is not super useful but provided for completeness
ImGuiNavMoveFlags_AllowCurrentNavId = 1 << 4, // Allow scoring and considering the current NavId as a move target candidate. This is used when the move source is offset (e.g. pressing PageDown actually needs to send a Up move request, if we are pressing PageDown from the bottom-most item we need to stay in place)
ImGuiNavMoveFlags_AlsoScoreVisibleSet = 1 << 5, // Store alternate result in NavMoveResultLocalVisibleSet that only comprise elements that are already fully visible (used by PageUp/PageDown)
ImGuiNavMoveFlags_ScrollToEdge = 1 << 6,
ImGuiNavMoveFlags_Forwarded = 1 << 7
};
enum ImGuiNavLayer
{
ImGuiNavLayer_Main = 0, // Main scrolling layer
ImGuiNavLayer_Menu = 1, // Menu layer (access with Alt/ImGuiNavInput_Menu)
ImGuiNavLayer_COUNT
};
struct ImGuiNavItemData
{
ImGuiWindow* Window; // Init,Move // Best candidate window (result->ItemWindow->RootWindowForNav == request->Window)
ImGuiID ID; // Init,Move // Best candidate item ID
ImGuiID FocusScopeId; // Init,Move // Best candidate focus scope ID
ImRect RectRel; // Init,Move // Best candidate bounding box in window relative space
float DistBox; // Move // Best candidate box distance to current NavId
float DistCenter; // Move // Best candidate center distance to current NavId
float DistAxial; // Move // Best candidate axial distance to current NavId
ImGuiNavItemData() { Clear(); }
void Clear() { Window = NULL; ID = FocusScopeId = 0; RectRel = ImRect(); DistBox = DistCenter = DistAxial = FLT_MAX; }
};
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// [SECTION] Columns support // [SECTION] Columns support
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
@ -1708,22 +1701,20 @@ struct ImGuiContext
bool NavMousePosDirty; // When set we will update mouse position if (io.ConfigFlags & ImGuiConfigFlags_NavEnableSetMousePos) if set (NB: this not enabled by default) bool NavMousePosDirty; // When set we will update mouse position if (io.ConfigFlags & ImGuiConfigFlags_NavEnableSetMousePos) if set (NB: this not enabled by default)
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) 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)
bool NavDisableMouseHover; // When user starts using gamepad/keyboard, we hide mouse hovering highlight until mouse is touched again. bool NavDisableMouseHover; // When user starts using gamepad/keyboard, we hide mouse hovering highlight until mouse is touched again.
bool NavAnyRequest; // ~~ NavMoveRequest || NavInitRequest bool NavAnyRequest; // ~~ NavMoveRequest || NavInitRequest this is to perform early out in ItemAdd()
bool NavInitRequest; // Init request for appearing window to select first item bool NavInitRequest; // Init request for appearing window to select first item
bool NavInitRequestFromMove; bool NavInitRequestFromMove;
ImGuiID NavInitResultId; // Init request result (first item of the window, or one for which SetItemDefaultFocus() was called) ImGuiID NavInitResultId; // Init request result (first item of the window, or one for which SetItemDefaultFocus() was called)
ImRect NavInitResultRectRel; // Init request result rectangle (relative to parent window) ImRect NavInitResultRectRel; // Init request result rectangle (relative to parent window)
bool NavMoveRequest; // Move request for this frame bool NavMoveRequest; // Move request for this frame
bool NavMoveRequestForwardToNextFrame;
ImGuiNavMoveFlags NavMoveRequestFlags; ImGuiNavMoveFlags NavMoveRequestFlags;
ImGuiNavForward NavMoveRequestForward; // None / ForwardQueued / ForwardActive (this is used to navigate sibling parent menus from a child menu)
ImGuiKeyModFlags NavMoveRequestKeyMods; ImGuiKeyModFlags NavMoveRequestKeyMods;
ImGuiDir NavMoveDir, NavMoveDirLast; // Direction of the move request (left/right/up/down), direction of the previous move request ImGuiDir NavMoveDir, NavMoveDirLast; // Direction of the move request (left/right/up/down), direction of the previous move request
ImGuiDir NavMoveClipDir; // FIXME-NAV: Describe the purpose of this better. Might want to rename? ImGuiDir NavMoveClipDir; // FIXME-NAV: Describe the purpose of this better. Might want to rename?
ImGuiNavItemData NavMoveResultLocal; // Best move request candidate within NavWindow ImGuiNavItemData NavMoveResultLocal; // Best move request candidate within NavWindow
ImGuiNavItemData NavMoveResultLocalVisibleSet; // Best move request candidate within NavWindow that are mostly visible (when using ImGuiNavMoveFlags_AlsoScoreVisibleSet flag) ImGuiNavItemData NavMoveResultLocalVisibleSet; // Best move request candidate within NavWindow that are mostly visible (when using ImGuiNavMoveFlags_AlsoScoreVisibleSet flag)
ImGuiNavItemData NavMoveResultOther; // Best move request candidate within NavWindow's flattened hierarchy (when using ImGuiWindowFlags_NavFlattened flag) ImGuiNavItemData NavMoveResultOther; // Best move request candidate within NavWindow's flattened hierarchy (when using ImGuiWindowFlags_NavFlattened flag)
ImGuiWindow* NavWrapRequestWindow; // Window which requested trying nav wrap-around.
ImGuiNavMoveFlags NavWrapRequestFlags; // Wrap-around operation flags.
// Navigation: Windowing (CTRL+TAB for list, or Menu button + keys or directional pads to move/resize) // Navigation: Windowing (CTRL+TAB for list, or Menu button + keys or directional pads to move/resize)
ImGuiWindow* NavWindowingTarget; // Target window when doing CTRL+Tab (or Pad Menu + FocusPrev/Next), this window is temporarily displayed top-most! ImGuiWindow* NavWindowingTarget; // Target window when doing CTRL+Tab (or Pad Menu + FocusPrev/Next), this window is temporarily displayed top-most!
@ -1931,12 +1922,10 @@ struct ImGuiContext
NavInitRequestFromMove = false; NavInitRequestFromMove = false;
NavInitResultId = 0; NavInitResultId = 0;
NavMoveRequest = false; NavMoveRequest = false;
NavMoveRequestForwardToNextFrame = false;
NavMoveRequestFlags = ImGuiNavMoveFlags_None; NavMoveRequestFlags = ImGuiNavMoveFlags_None;
NavMoveRequestForward = ImGuiNavForward_None;
NavMoveRequestKeyMods = ImGuiKeyModFlags_None; NavMoveRequestKeyMods = ImGuiKeyModFlags_None;
NavMoveDir = NavMoveDirLast = NavMoveClipDir = ImGuiDir_None; NavMoveDir = NavMoveDirLast = NavMoveClipDir = ImGuiDir_None;
NavWrapRequestWindow = NULL;
NavWrapRequestFlags = ImGuiNavMoveFlags_None;
NavWindowingTarget = NavWindowingTargetAnim = NavWindowingListWindow = NULL; NavWindowingTarget = NavWindowingTargetAnim = NavWindowingListWindow = NULL;
NavWindowingTimer = NavWindowingHighlightAlpha = 0.0f; NavWindowingTimer = NavWindowingHighlightAlpha = 0.0f;
@ -2659,8 +2648,8 @@ namespace ImGui
// (Old) IMGUI_VERSION_NUM < 18209: using 'ItemAdd(....)' and 'bool focused = FocusableItemRegister(...)' // (Old) IMGUI_VERSION_NUM < 18209: using 'ItemAdd(....)' and 'bool focused = FocusableItemRegister(...)'
// (New) IMGUI_VERSION_NUM >= 18209: using 'ItemAdd(..., ImGuiItemAddFlags_Focusable)' and 'bool focused = (GetItemStatusFlags() & ImGuiItemStatusFlags_Focused) != 0' // (New) IMGUI_VERSION_NUM >= 18209: using 'ItemAdd(..., ImGuiItemAddFlags_Focusable)' and 'bool focused = (GetItemStatusFlags() & ImGuiItemStatusFlags_Focused) != 0'
// Widget code are simplified as there's no need to call FocusableItemUnregister() while managing the transition from regular widget to TempInputText() // Widget code are simplified as there's no need to call FocusableItemUnregister() while managing the transition from regular widget to TempInputText()
inline bool FocusableItemRegister(ImGuiWindow* window, ImGuiID id) { IM_ASSERT(0); IM_UNUSED(window); IM_UNUSED(id); return false; } // -> pass ImGuiItemAddFlags_Focusable flag to ItemAdd() inline bool FocusableItemRegister(ImGuiWindow* window, ImGuiID id) { IM_ASSERT(0); IM_UNUSED(window); IM_UNUSED(id); return false; } // -> pass ImGuiItemAddFlags_Focusable flag to ItemAdd()
inline IM_NORETURN void FocusableItemUnregister(ImGuiWindow* window) { IM_ASSERT(0); IM_UNUSED(window); } // -> unnecessary: TempInputText() uses ImGuiInputTextFlags_MergedItem inline void FocusableItemUnregister(ImGuiWindow* window) { IM_ASSERT(0); IM_UNUSED(window); } // -> unnecessary: TempInputText() uses ImGuiInputTextFlags_MergedItem
#endif #endif
// Logging/Capture // Logging/Capture
@ -2684,6 +2673,7 @@ namespace ImGui
IMGUI_API bool BeginViewportSideBar(const char* name, ImGuiViewport* viewport, ImGuiDir dir, float size, ImGuiWindowFlags window_flags); IMGUI_API bool BeginViewportSideBar(const char* name, ImGuiViewport* viewport, ImGuiDir dir, float size, ImGuiWindowFlags window_flags);
// Menus // Menus
IMGUI_API bool BeginMenuEx(const char* label, const char* icon, bool enabled = true);
IMGUI_API bool MenuItemEx(const char* label, const char* icon, const char* shortcut = NULL, bool selected = false, bool enabled = true); IMGUI_API bool MenuItemEx(const char* label, const char* icon, const char* shortcut = NULL, bool selected = false, bool enabled = true);
// Combos // Combos
@ -2693,9 +2683,10 @@ namespace ImGui
// Gamepad/Keyboard Navigation // Gamepad/Keyboard Navigation
IMGUI_API void NavInitWindow(ImGuiWindow* window, bool force_reinit); IMGUI_API void NavInitWindow(ImGuiWindow* window, bool force_reinit);
IMGUI_API bool NavMoveRequestButNoResultYet(); IMGUI_API bool NavMoveRequestButNoResultYet(); // Should be called ~NavMoveRequestIsActiveButNoResultYet()
IMGUI_API void NavMoveRequestForward(ImGuiDir move_dir, ImGuiDir clip_dir, ImGuiNavMoveFlags move_flags);
IMGUI_API void NavMoveRequestCancel(); IMGUI_API void NavMoveRequestCancel();
IMGUI_API void NavMoveRequestForward(ImGuiDir move_dir, ImGuiDir clip_dir, const ImRect& bb_rel, ImGuiNavMoveFlags move_flags); IMGUI_API void NavMoveRequestApplyResult();
IMGUI_API void NavMoveRequestTryWrapping(ImGuiWindow* window, ImGuiNavMoveFlags move_flags); IMGUI_API void NavMoveRequestTryWrapping(ImGuiWindow* window, ImGuiNavMoveFlags move_flags);
IMGUI_API float GetNavInputAmount(ImGuiNavInput n, ImGuiInputReadMode mode); IMGUI_API float GetNavInputAmount(ImGuiNavInput n, ImGuiInputReadMode mode);
IMGUI_API ImVec2 GetNavInputAmount2d(ImGuiNavDirSourceFlags dir_sources, ImGuiInputReadMode mode, float slow_factor = 0.0f, float fast_factor = 0.0f); IMGUI_API ImVec2 GetNavInputAmount2d(ImGuiNavDirSourceFlags dir_sources, ImGuiInputReadMode mode, float slow_factor = 0.0f, float fast_factor = 0.0f);

@ -1,4 +1,4 @@
// dear imgui, v1.84 // dear imgui, v1.85 WIP
// (tables and columns code) // (tables and columns code)
/* /*

@ -1,4 +1,4 @@
// dear imgui, v1.84 // dear imgui, v1.85 WIP
// (widgets code) // (widgets code)
/* /*
@ -152,9 +152,13 @@ void ImGui::TextEx(const char* text, const char* text_end, ImGuiTextFlags flags)
ImGuiWindow* window = GetCurrentWindow(); ImGuiWindow* window = GetCurrentWindow();
if (window->SkipItems) if (window->SkipItems)
return; return;
ImGuiContext& g = *GImGui; ImGuiContext& g = *GImGui;
IM_ASSERT(text != NULL);
// Accept null ranges
if (text == text_end)
text = text_end = "";
// Calculate length
const char* text_begin = text; const char* text_begin = text;
if (text_end == NULL) if (text_end == NULL)
text_end = text + strlen(text); // FIXME-OPT text_end = text + strlen(text); // FIXME-OPT
@ -3975,13 +3979,15 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_
ImGuiItemStatusFlags item_status_flags = 0; ImGuiItemStatusFlags item_status_flags = 0;
if (is_multiline) if (is_multiline)
{ {
ImVec2 backup_pos = window->DC.CursorPos;
ItemSize(total_bb, style.FramePadding.y);
if (!ItemAdd(total_bb, id, &frame_bb, ImGuiItemAddFlags_Focusable)) if (!ItemAdd(total_bb, id, &frame_bb, ImGuiItemAddFlags_Focusable))
{ {
ItemSize(total_bb, style.FramePadding.y);
EndGroup(); EndGroup();
return false; return false;
} }
item_status_flags = g.LastItemData.StatusFlags; item_status_flags = g.LastItemData.StatusFlags;
window->DC.CursorPos = backup_pos;
// We reproduce the contents of BeginChildFrame() in order to provide 'label' so our window internal data are easier to read/debug. // We reproduce the contents of BeginChildFrame() in order to provide 'label' so our window internal data are easier to read/debug.
PushStyleColor(ImGuiCol_ChildBg, style.Colors[ImGuiCol_FrameBg]); PushStyleColor(ImGuiCol_ChildBg, style.Colors[ImGuiCol_FrameBg]);
@ -5900,12 +5906,12 @@ bool ImGui::TreeNodeBehavior(ImGuiID id, ImGuiTreeNodeFlags flags, const char* l
toggled = true; toggled = true;
} }
if (g.NavId == id && g.NavMoveRequest && g.NavMoveDir == ImGuiDir_Left && is_open) if (g.NavId == id && g.NavMoveDir == ImGuiDir_Left && is_open)
{ {
toggled = true; toggled = true;
NavMoveRequestCancel(); NavMoveRequestCancel();
} }
if (g.NavId == id && g.NavMoveRequest && g.NavMoveDir == ImGuiDir_Right && !is_open) // If there's something upcoming on the line we may want to give it the priority? if (g.NavId == id && g.NavMoveDir == ImGuiDir_Right && !is_open) // If there's something upcoming on the line we may want to give it the priority?
{ {
toggled = true; toggled = true;
NavMoveRequestCancel(); NavMoveRequestCancel();
@ -6693,18 +6699,17 @@ void ImGui::EndMenuBar()
ImGuiWindow* nav_earliest_child = g.NavWindow; ImGuiWindow* nav_earliest_child = g.NavWindow;
while (nav_earliest_child->ParentWindow && (nav_earliest_child->ParentWindow->Flags & ImGuiWindowFlags_ChildMenu)) while (nav_earliest_child->ParentWindow && (nav_earliest_child->ParentWindow->Flags & ImGuiWindowFlags_ChildMenu))
nav_earliest_child = nav_earliest_child->ParentWindow; nav_earliest_child = nav_earliest_child->ParentWindow;
if (nav_earliest_child->ParentWindow == window && nav_earliest_child->DC.ParentLayoutType == ImGuiLayoutType_Horizontal && g.NavMoveRequestForward == ImGuiNavForward_None) if (nav_earliest_child->ParentWindow == window && nav_earliest_child->DC.ParentLayoutType == ImGuiLayoutType_Horizontal && (g.NavMoveRequestFlags & ImGuiNavMoveFlags_Forwarded) == 0)
{ {
// To do so we claim focus back, restore NavId and then process the movement request for yet another frame. // To do so we claim focus back, restore NavId and then process the movement request for yet another frame.
// This involve a one-frame delay which isn't very problematic in this situation. We could remove it by scoring in advance for multiple window (probably not worth the hassle/cost) // This involve a one-frame delay which isn't very problematic in this situation. We could remove it by scoring in advance for multiple window (probably not worth bothering)
const ImGuiNavLayer layer = ImGuiNavLayer_Menu; const ImGuiNavLayer layer = ImGuiNavLayer_Menu;
IM_ASSERT(window->DC.NavLayersActiveMaskNext & (1 << layer)); // Sanity check IM_ASSERT(window->DC.NavLayersActiveMaskNext & (1 << layer)); // Sanity check
FocusWindow(window); FocusWindow(window);
SetNavID(window->NavLastIds[layer], layer, 0, window->NavRectRel[layer]); SetNavID(window->NavLastIds[layer], layer, 0, window->NavRectRel[layer]);
g.NavDisableHighlight = true; // Hide highlight for the current frame so we don't see the intermediary selection. g.NavDisableHighlight = true; // Hide highlight for the current frame so we don't see the intermediary selection.
g.NavDisableMouseHover = g.NavMousePosDirty = true; g.NavDisableMouseHover = g.NavMousePosDirty = true;
g.NavMoveRequestForward = ImGuiNavForward_ForwardQueued; NavMoveRequestForward(g.NavMoveDir, g.NavMoveClipDir, g.NavMoveRequestFlags); // Repeat
NavMoveRequestCancel();
} }
} }
@ -6797,7 +6802,7 @@ void ImGui::EndMainMenuBar()
End(); End();
} }
bool ImGui::BeginMenu(const char* label, bool enabled) bool ImGui::BeginMenuEx(const char* label, const char* icon, bool enabled)
{ {
ImGuiWindow* window = GetCurrentWindow(); ImGuiWindow* window = GetCurrentWindow();
if (window->SkipItems) if (window->SkipItems)
@ -6864,13 +6869,15 @@ bool ImGui::BeginMenu(const char* label, bool enabled)
// (In a typical menu window where all items are BeginMenu() or MenuItem() calls, extra_w will always be 0.0f. // (In a typical menu window where all items are BeginMenu() or MenuItem() calls, extra_w will always be 0.0f.
// Only when they are other items sticking out we're going to add spacing, yet only register minimum width into the layout system. // Only when they are other items sticking out we're going to add spacing, yet only register minimum width into the layout system.
popup_pos = ImVec2(pos.x, pos.y - style.WindowPadding.y); popup_pos = ImVec2(pos.x, pos.y - style.WindowPadding.y);
float icon_w = 0.0f; // FIXME: This not currently exposed for BeginMenu() however you can call window->DC.MenuColumns.DeclColumns(w, 0, 0, 0) yourself float icon_w = (icon && icon[0]) ? CalcTextSize(icon, NULL).x : 0.0f;
float checkmark_w = IM_FLOOR(g.FontSize * 1.20f); float checkmark_w = IM_FLOOR(g.FontSize * 1.20f);
float min_w = window->DC.MenuColumns.DeclColumns(icon_w, label_size.x, 0.0f, checkmark_w); // Feedback to next frame float min_w = window->DC.MenuColumns.DeclColumns(icon_w, label_size.x, 0.0f, checkmark_w); // Feedback to next frame
float extra_w = ImMax(0.0f, GetContentRegionAvail().x - min_w); float extra_w = ImMax(0.0f, GetContentRegionAvail().x - min_w);
ImVec2 text_pos(window->DC.CursorPos.x + offsets->OffsetLabel, window->DC.CursorPos.y + window->DC.CurrLineTextBaseOffset); ImVec2 text_pos(window->DC.CursorPos.x + offsets->OffsetLabel, window->DC.CursorPos.y + window->DC.CurrLineTextBaseOffset);
pressed = Selectable("", menu_is_open, ImGuiSelectableFlags_NoHoldingActiveID | ImGuiSelectableFlags_SelectOnClick | ImGuiSelectableFlags_DontClosePopups | ImGuiSelectableFlags_SpanAvailWidth, ImVec2(min_w, 0.0f)); pressed = Selectable("", menu_is_open, ImGuiSelectableFlags_NoHoldingActiveID | ImGuiSelectableFlags_SelectOnClick | ImGuiSelectableFlags_DontClosePopups | ImGuiSelectableFlags_SpanAvailWidth, ImVec2(min_w, 0.0f));
RenderText(text_pos, label); RenderText(text_pos, label);
if (icon_w > 0.0f)
RenderText(pos + ImVec2(offsets->OffsetIcon, 0.0f), icon);
RenderArrow(window->DrawList, pos + ImVec2(offsets->OffsetMark + extra_w + g.FontSize * 0.30f, 0.0f), GetColorU32(ImGuiCol_Text), ImGuiDir_Right); RenderArrow(window->DrawList, pos + ImVec2(offsets->OffsetMark + extra_w + g.FontSize * 0.30f, 0.0f), GetColorU32(ImGuiCol_Text), ImGuiDir_Right);
} }
if (!enabled) if (!enabled)
@ -6918,7 +6925,7 @@ bool ImGui::BeginMenu(const char* label, bool enabled)
want_close = menu_is_open; want_close = menu_is_open;
want_open = !menu_is_open; want_open = !menu_is_open;
} }
if (g.NavId == id && g.NavMoveRequest && g.NavMoveDir == ImGuiDir_Right) // Nav-Right to open if (g.NavId == id && g.NavMoveDir == ImGuiDir_Right) // Nav-Right to open
{ {
want_open = true; want_open = true;
NavMoveRequestCancel(); NavMoveRequestCancel();
@ -6936,7 +6943,7 @@ bool ImGui::BeginMenu(const char* label, bool enabled)
{ {
want_open = true; want_open = true;
} }
else if (g.NavId == id && g.NavMoveRequest && g.NavMoveDir == ImGuiDir_Down) // Nav-Down to open else if (g.NavId == id && g.NavMoveDir == ImGuiDir_Down) // Nav-Down to open
{ {
want_open = true; want_open = true;
NavMoveRequestCancel(); NavMoveRequestCancel();
@ -6975,6 +6982,11 @@ bool ImGui::BeginMenu(const char* label, bool enabled)
return menu_is_open; return menu_is_open;
} }
bool ImGui::BeginMenu(const char* label, bool enabled)
{
return BeginMenuEx(label, NULL, enabled);
}
void ImGui::EndMenu() void ImGui::EndMenu()
{ {
// Nav: When a left move request _within our child menu_ failed, close ourselves (the _parent_ menu). // Nav: When a left move request _within our child menu_ failed, close ourselves (the _parent_ menu).

@ -6,6 +6,7 @@
// CHANGELOG // CHANGELOG
// (minor and older changes stripped away, please see git history for details) // (minor and older changes stripped away, please see git history for details)
// 2021/08/23: fixed crash when FT_Render_Glyph() fails to render a glyph and returns NULL.
// 2021/03/05: added ImGuiFreeTypeBuilderFlags_Bitmap to load bitmap glyphs. // 2021/03/05: added ImGuiFreeTypeBuilderFlags_Bitmap to load bitmap glyphs.
// 2021/03/02: set 'atlas->TexPixelsUseColors = true' to help some backends with deciding of a prefered texture format. // 2021/03/02: set 'atlas->TexPixelsUseColors = true' to help some backends with deciding of a prefered texture format.
// 2021/01/28: added support for color-layered glyphs via ImGuiFreeTypeBuilderFlags_LoadColor (require Freetype 2.10+). // 2021/01/28: added support for color-layered glyphs via ImGuiFreeTypeBuilderFlags_LoadColor (require Freetype 2.10+).
@ -539,7 +540,8 @@ bool ImFontAtlasBuildWithFreeTypeEx(FT_Library ft_library, ImFontAtlas* atlas, u
// Render glyph into a bitmap (currently held by FreeType) // Render glyph into a bitmap (currently held by FreeType)
const FT_Bitmap* ft_bitmap = src_tmp.Font.RenderGlyphAndGetInfo(&src_glyph.Info); const FT_Bitmap* ft_bitmap = src_tmp.Font.RenderGlyphAndGetInfo(&src_glyph.Info);
IM_ASSERT(ft_bitmap); if (ft_bitmap == NULL)
continue;
// Allocate new temporary chunk if needed // Allocate new temporary chunk if needed
const int bitmap_size_in_bytes = src_glyph.Info.Width * src_glyph.Info.Height * 4; const int bitmap_size_in_bytes = src_glyph.Info.Width * src_glyph.Info.Height * 4;

Loading…
Cancel
Save