From ef13d95466f27b4a955d6f95da90822001ace25f Mon Sep 17 00:00:00 2001 From: omar Date: Sat, 11 May 2019 10:33:56 +0200 Subject: [PATCH 01/11] IO: changed AddInputCharacter(unsigned short c) signature to AddInputCharacter(unsigned int c). Examples/Backends: Don't filter characters under 0x10000 before calling io.AddInputCharacter(), the filtering is done in io.AddInputCharacter() itself. This is in prevision for fuller Unicode support. (#2538, #2541) --- docs/CHANGELOG.txt | 4 ++++ examples/imgui_impl_allegro5.cpp | 4 ++-- examples/imgui_impl_glfw.cpp | 4 ++-- examples/imgui_impl_glut.cpp | 2 +- examples/imgui_impl_marmalade.cpp | 4 ++-- examples/imgui_impl_osx.mm | 5 +++-- examples/imgui_impl_win32.cpp | 4 ++-- imgui.cpp | 8 +++++--- imgui.h | 2 +- 9 files changed, 22 insertions(+), 15 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 366b695b..1e47efe2 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -33,6 +33,7 @@ HOW TO UPDATE? ----------------------------------------------------------------------- Breaking Changes: +- IO: changed AddInputCharacter(unsigned short c) signature to AddInputCharacter(unsigned int c). Other Changes: - Columns: Fixed Separator from creating an extraneous draw command. (#125) @@ -40,6 +41,9 @@ Other Changes: - Separator: Revert 1.70 "Declare its thickness (1.0f) to the layout" change. It's not incorrect but it breaks existing some layout patterns. Will return back to it when we expose Separator flags. - Scrollbar: Very minor bounding box adjustment to cope with various border size. +- Examples/Backends: Don't filter characters under 0x10000 before calling io.AddInputCharacter(), + the filtering is done in io.AddInputCharacter() itself. This is in prevision for fuller Unicode + support. (#2538, #2541) ----------------------------------------------------------------------- diff --git a/examples/imgui_impl_allegro5.cpp b/examples/imgui_impl_allegro5.cpp index b05fa2a3..46893390 100644 --- a/examples/imgui_impl_allegro5.cpp +++ b/examples/imgui_impl_allegro5.cpp @@ -15,6 +15,7 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) +// 2019-05-11: Inputs: Don't filter character value from ALLEGRO_EVENT_KEY_CHAR before calling AddInputCharacter(). // 2019-04-30: Renderer: Added support for special ImDrawCallback_ResetRenderState callback to reset render state. // 2018-11-30: Platform: Added touchscreen support. // 2018-11-30: Misc: Setting up io.BackendPlatformName/io.BackendRendererName so they can be displayed in the About Window. @@ -353,8 +354,7 @@ bool ImGui_ImplAllegro5_ProcessEvent(ALLEGRO_EVENT *ev) return true; case ALLEGRO_EVENT_KEY_CHAR: if (ev->keyboard.display == g_Display) - if (ev->keyboard.unichar > 0 && ev->keyboard.unichar < 0x10000) - io.AddInputCharacter((unsigned short)ev->keyboard.unichar); + io.AddInputCharacter((unsigned int)ev->keyboard.unichar); return true; case ALLEGRO_EVENT_KEY_DOWN: case ALLEGRO_EVENT_KEY_UP: diff --git a/examples/imgui_impl_glfw.cpp b/examples/imgui_impl_glfw.cpp index 0ed9f7d2..090b012d 100644 --- a/examples/imgui_impl_glfw.cpp +++ b/examples/imgui_impl_glfw.cpp @@ -15,6 +15,7 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) +// 2019-05-11: Inputs: Don't filter value from character callback before calling AddInputCharacter(). // 2019-03-12: Misc: Preserve DisplayFramebufferScale when main window is minimized. // 2018-11-30: Misc: Setting up io.BackendPlatformName so it can be displayed in the About Window. // 2018-11-07: Inputs: When installing our GLFW callbacks, we save user's previously installed ones - if any - and chain call them. @@ -120,8 +121,7 @@ void ImGui_ImplGlfw_CharCallback(GLFWwindow* window, unsigned int c) g_PrevUserCallbackChar(window, c); ImGuiIO& io = ImGui::GetIO(); - if (c > 0 && c < 0x10000) - io.AddInputCharacter((unsigned short)c); + io.AddInputCharacter(c); } static bool ImGui_ImplGlfw_Init(GLFWwindow* window, bool install_callbacks, GlfwClientApi client_api) diff --git a/examples/imgui_impl_glut.cpp b/examples/imgui_impl_glut.cpp index af42d4ae..78b3c54a 100644 --- a/examples/imgui_impl_glut.cpp +++ b/examples/imgui_impl_glut.cpp @@ -118,7 +118,7 @@ void ImGui_ImplGLUT_KeyboardFunc(unsigned char c, int x, int y) //printf("char_down_func %d '%c'\n", c, c); ImGuiIO& io = ImGui::GetIO(); if (c >= 32) - io.AddInputCharacter((unsigned short)c); + io.AddInputCharacter((unsigned int)c); // Store letters in KeysDown[] array as both uppercase and lowercase + Handle GLUT translating CTRL+A..CTRL+Z as 1..26. // This is a hacky mess but GLUT is unable to distinguish e.g. a TAB key from CTRL+I so this is probably the best we can do here. diff --git a/examples/imgui_impl_marmalade.cpp b/examples/imgui_impl_marmalade.cpp index 1f2307b2..a101c69a 100644 --- a/examples/imgui_impl_marmalade.cpp +++ b/examples/imgui_impl_marmalade.cpp @@ -12,6 +12,7 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) +// 2019-05-11: Inputs: Don't filter value from character callback before calling AddInputCharacter(). // 2018-11-30: Misc: Setting up io.BackendPlatformName/io.BackendRendererName so they can be displayed in the About Window. // 2018-02-16: Misc: Obsoleted the io.RenderDrawListsFn callback and exposed ImGui_Marmalade_RenderDrawData() in the .h file so you can call it yourself. // 2018-02-06: Misc: Removed call to ImGui::Shutdown() which is not available from 1.60 WIP, user needs to call CreateContext/DestroyContext themselves. @@ -166,8 +167,7 @@ int32 ImGui_Marmalade_CharCallback(void* system_data, void* user_data) { ImGuiIO& io = ImGui::GetIO(); s3eKeyboardCharEvent* e = (s3eKeyboardCharEvent*)system_data; - if ((e->m_Char > 0 && e->m_Char < 0x10000)) - io.AddInputCharacter((unsigned short)e->m_Char); + io.AddInputCharacter((unsigned int)e->m_Char); return 0; } diff --git a/examples/imgui_impl_osx.mm b/examples/imgui_impl_osx.mm index 07381caf..34a61ff5 100644 --- a/examples/imgui_impl_osx.mm +++ b/examples/imgui_impl_osx.mm @@ -12,6 +12,7 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) +// 2019-05-11: Inputs: Don't filter character values before calling AddInputCharacter() apart from 0xF700..0xFFFF range. // 2018-11-30: Misc: Setting up io.BackendPlatformName so it can be displayed in the About Window. // 2018-07-07: Initial version. @@ -189,8 +190,8 @@ bool ImGui_ImplOSX_HandleEvent(NSEvent* event, NSView* view) for (int i = 0; i < len; i++) { int c = [str characterAtIndex:i]; - if (c < 0xF700 && !io.KeyCtrl) - io.AddInputCharacter((unsigned short)c); + if (!io.KeyCtrl && !(c >= 0xF700 && c <= 0xFFFF)) + io.AddInputCharacter((unsigned int)c); // We must reset in case we're pressing a sequence of special keys while keeping the command pressed int key = mapCharacterToKey(c); diff --git a/examples/imgui_impl_win32.cpp b/examples/imgui_impl_win32.cpp index 59cf88ce..85dede4e 100644 --- a/examples/imgui_impl_win32.cpp +++ b/examples/imgui_impl_win32.cpp @@ -18,6 +18,7 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) +// 2019-05-11: Inputs: Don't filter value from WM_CHAR before calling AddInputCharacter(). // 2019-01-17: Misc: Using GetForegroundWindow()+IsChild() instead of GetActiveWindow() to be compatible with windows created in a different thread or parent. // 2019-01-17: Inputs: Added support for mouse buttons 4 and 5 via WM_XBUTTON* messages. // 2019-01-15: Inputs: Added support for XInput gamepads (if ImGuiConfigFlags_NavEnableGamepad is set by user application). @@ -305,8 +306,7 @@ IMGUI_IMPL_API LRESULT ImGui_ImplWin32_WndProcHandler(HWND hwnd, UINT msg, WPARA return 0; case WM_CHAR: // You can also use ToAscii()+GetKeyboardState() to retrieve characters. - if (wParam > 0 && wParam < 0x10000) - io.AddInputCharacter((unsigned short)wParam); + io.AddInputCharacter((unsigned int)wParam); return 0; case WM_SETCURSOR: if (LOWORD(lParam) == HTCLIENT && ImGui_ImplWin32_UpdateMouseCursor()) diff --git a/imgui.cpp b/imgui.cpp index d7a75f96..227b3ee1 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -369,6 +369,7 @@ CODE When you are not sure about a old symbol or function name, try using the Search/Find function of your IDE to look for comments or references in all imgui files. You can read releases logs https://github.com/ocornut/imgui/releases for more details. + - 2019/05/11 (1.71) - changed io.AddInputCharacter(unsigned short c) signature to io.AddInputCharacter(unsigned int c). - 2019/04/29 (1.70) - improved ImDrawList thick strokes (>1.0f) preserving correct thickness up to 90 degrees angles (e.g. rectangles). If you have custom rendering using thick lines, they will appear thicker now. - 2019/04/29 (1.70) - removed GetContentRegionAvailWidth(), use GetContentRegionAvail().x instead. Kept inline redirection function (will obsolete). - 2019/03/04 (1.69) - renamed GetOverlayDrawList() to GetForegroundDrawList(). Kept redirection function (will obsolete). @@ -1251,9 +1252,10 @@ ImGuiIO::ImGuiIO() // Pass in translated ASCII characters for text input. // - with glfw you can get those from the callback set in glfwSetCharCallback() // - on Windows you can get those using ToAscii+keyboard state, or via the WM_CHAR message -void ImGuiIO::AddInputCharacter(ImWchar c) +void ImGuiIO::AddInputCharacter(unsigned int c) { - InputQueueCharacters.push_back(c); + if (c > 0 && c < 0x10000) + InputQueueCharacters.push_back((ImWchar)c); } void ImGuiIO::AddInputCharactersUTF8(const char* utf8_chars) @@ -1262,7 +1264,7 @@ void ImGuiIO::AddInputCharactersUTF8(const char* utf8_chars) { unsigned int c = 0; utf8_chars += ImTextCharFromUtf8(&c, utf8_chars, NULL); - if (c > 0 && c <= 0xFFFF) + if (c > 0 && c < 0x10000) InputQueueCharacters.push_back((ImWchar)c); } } diff --git a/imgui.h b/imgui.h index 0d46ec5d..7c05d7c4 100644 --- a/imgui.h +++ b/imgui.h @@ -1402,7 +1402,7 @@ struct ImGuiIO float NavInputs[ImGuiNavInput_COUNT]; // Gamepad inputs. Cleared back to zero by EndFrame(). Keyboard keys will be auto-mapped and be written here by NewFrame(). // Functions - IMGUI_API void AddInputCharacter(ImWchar c); // Queue new character input + IMGUI_API void AddInputCharacter(unsigned int c); // Queue new character input IMGUI_API void AddInputCharactersUTF8(const char* str); // Queue new characters input from an UTF-8 string IMGUI_API void ClearInputCharacters(); // Clear the text input buffer manually From 87c5356d977a07abfe05dc0fcdbcebcc73eb47dd Mon Sep 17 00:00:00 2001 From: HolyBlackCat Date: Thu, 9 May 2019 22:03:27 +0300 Subject: [PATCH 02/11] FreeType: Added RasterizerFlags::Monochrome flag to disable font anti-aliasing. (#2545) Combine with RasterizerFlags::MonoHinting for best results. --- docs/CHANGELOG.txt | 2 ++ misc/freetype/README.md | 1 + misc/freetype/imgui_freetype.cpp | 53 ++++++++++++++++++++++++++------ misc/freetype/imgui_freetype.h | 3 +- 4 files changed, 48 insertions(+), 11 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 1e47efe2..d7f4ca26 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -41,6 +41,8 @@ Other Changes: - Separator: Revert 1.70 "Declare its thickness (1.0f) to the layout" change. It's not incorrect but it breaks existing some layout patterns. Will return back to it when we expose Separator flags. - Scrollbar: Very minor bounding box adjustment to cope with various border size. +- ImFontAtlas: FreeType: Added RasterizerFlags::Monochrome flag to disable font anti-aliasing. (#2545) + Combine with RasterizerFlags::MonoHinting for best results. - Examples/Backends: Don't filter characters under 0x10000 before calling io.AddInputCharacter(), the filtering is done in io.AddInputCharacter() itself. This is in prevision for fuller Unicode support. (#2538, #2541) diff --git a/misc/freetype/README.md b/misc/freetype/README.md index 397adec7..b62671ce 100644 --- a/misc/freetype/README.md +++ b/misc/freetype/README.md @@ -120,6 +120,7 @@ struct FreeTypeTest WantRebuild |= ImGui::CheckboxFlags("MonoHinting", &FontsFlags, ImGuiFreeType::MonoHinting); WantRebuild |= ImGui::CheckboxFlags("Bold", &FontsFlags, ImGuiFreeType::Bold); WantRebuild |= ImGui::CheckboxFlags("Oblique", &FontsFlags, ImGuiFreeType::Oblique); + WantRebuild |= ImGui::CheckboxFlags("Monochrome", &FontsFlags, ImGuiFreeType::Monochrome); } ImGui::End(); } diff --git a/misc/freetype/imgui_freetype.cpp b/misc/freetype/imgui_freetype.cpp index 4a579ed2..a184d78b 100644 --- a/misc/freetype/imgui_freetype.cpp +++ b/misc/freetype/imgui_freetype.cpp @@ -12,6 +12,7 @@ // - v0.56: (2018/06/08) added support for ImFontConfig::GlyphMinAdvanceX, GlyphMaxAdvanceX. // - v0.60: (2019/01/10) re-factored to match big update in STB builder. fixed texture height waste. fixed redundant glyphs when merging. support for glyph padding. // - v0.61: (2019/01/15) added support for imgui allocators + added FreeType only override function SetAllocatorFunctions(). +// - v0.62: (2019/02/09) added RasterizerFlags::Monochrome flag to disable font anti-aliasing (combine with ::MonoHinting for best results!) // Gamma Correct Blending: // FreeType assumes blending in linear space rather than gamma space. @@ -109,6 +110,7 @@ namespace FT_Face Face; unsigned int UserFlags; // = ImFontConfig::RasterizerFlags FT_Int32 LoadFlags; + FT_Render_Mode RenderMode; }; // From SDL_ttf: Handy routines for converting from fixed point @@ -142,6 +144,11 @@ namespace else LoadFlags |= FT_LOAD_TARGET_NORMAL; + if (UserFlags & ImGuiFreeType::Monochrome) + RenderMode = FT_RENDER_MODE_MONO; + else + RenderMode = FT_RENDER_MODE_NORMAL; + return true; } @@ -208,7 +215,7 @@ namespace const FT_Bitmap* FreeTypeFont::RenderGlyphAndGetInfo(GlyphInfo* out_glyph_info) { FT_GlyphSlot slot = Face->glyph; - FT_Error error = FT_Render_Glyph(slot, FT_RENDER_MODE_NORMAL); + FT_Error error = FT_Render_Glyph(slot, RenderMode); if (error != 0) return NULL; @@ -230,16 +237,42 @@ namespace const uint8_t* src = ft_bitmap->buffer; const uint32_t src_pitch = ft_bitmap->pitch; - if (multiply_table == NULL) + switch (ft_bitmap->pixel_mode) { - for (uint32_t y = 0; y < h; y++, src += src_pitch, dst += dst_pitch) - memcpy(dst, src, w); - } - else - { - for (uint32_t y = 0; y < h; y++, src += src_pitch, dst += dst_pitch) - for (uint32_t x = 0; x < w; x++) - dst[x] = multiply_table[src[x]]; + case FT_PIXEL_MODE_GRAY: // Grayscale image, 1 byte per pixel. + { + if (multiply_table == NULL) + { + for (uint32_t y = 0; y < h; y++, src += src_pitch, dst += dst_pitch) + memcpy(dst, src, w); + } + else + { + for (uint32_t y = 0; y < h; y++, src += src_pitch, dst += dst_pitch) + for (uint32_t x = 0; x < w; x++) + dst[x] = multiply_table[src[x]]; + } + break; + } + case FT_PIXEL_MODE_MONO: // Monochrome image, 1 bit per pixel. The bits in each byte are ordered from MSB to LSB. + { + uint8_t color0 = multiply_table ? multiply_table[0] : 0; + uint8_t color1 = multiply_table ? multiply_table[255] : 255; + for (uint32_t y = 0; y < h; y++, src += src_pitch, dst += dst_pitch) + { + uint8_t bits = 0; + const uint8_t* bits_ptr = src; + for (uint32_t x = 0; x < w; x++, bits <<= 1) + { + if ((x & 7) == 0) + bits = *bits_ptr++; + dst[x] = (bits & 0x80) ? color1 : color0; + } + } + break; + } + default: + IM_ASSERT(0 && "FreeTypeFont::BlitGlyph(): Unknown bitmap pixel mode!"); } } } diff --git a/misc/freetype/imgui_freetype.h b/misc/freetype/imgui_freetype.h index b4b0fd66..d65c7724 100644 --- a/misc/freetype/imgui_freetype.h +++ b/misc/freetype/imgui_freetype.h @@ -24,7 +24,8 @@ namespace ImGuiFreeType LightHinting = 1 << 3, // A lighter hinting algorithm for gray-level modes. Many generated glyphs are fuzzier but better resemble their original shape. This is achieved by snapping glyphs to the pixel grid only vertically (Y-axis), as is done by Microsoft's ClearType and Adobe's proprietary font renderer. This preserves inter-glyph spacing in horizontal text. MonoHinting = 1 << 4, // Strong hinting algorithm that should only be used for monochrome output. Bold = 1 << 5, // Styling: Should we artificially embolden the font? - Oblique = 1 << 6 // Styling: Should we slant the font, emulating italic style? + Oblique = 1 << 6, // Styling: Should we slant the font, emulating italic style? + Monochrome = 1 << 7 // Disable anti-aliasing. Combine this with MonoHinting for best results! }; IMGUI_API bool BuildFontAtlas(ImFontAtlas* atlas, unsigned int extra_flags = 0); From aca6ee1a912fd6bf022cce15a5c25a2eb2c0f6df Mon Sep 17 00:00:00 2001 From: omar Date: Sat, 11 May 2019 11:25:49 +0200 Subject: [PATCH 03/11] Cast ImTextureId to void* before printing in Metrics window. (#2548) --- imgui.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/imgui.cpp b/imgui.cpp index 227b3ee1..b9cce1f9 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -9670,7 +9670,9 @@ void ImGui::ShowMetricsWindow(bool* p_open) continue; } ImDrawIdx* idx_buffer = (draw_list->IdxBuffer.Size > 0) ? draw_list->IdxBuffer.Data : NULL; - bool pcmd_node_open = ImGui::TreeNode((void*)(pcmd - draw_list->CmdBuffer.begin()), "Draw %4d %s vtx, tex 0x%p, clip_rect (%4.0f,%4.0f)-(%4.0f,%4.0f)", pcmd->ElemCount, draw_list->IdxBuffer.Size > 0 ? "indexed" : "non-indexed", pcmd->TextureId, pcmd->ClipRect.x, pcmd->ClipRect.y, pcmd->ClipRect.z, pcmd->ClipRect.w); + bool pcmd_node_open = ImGui::TreeNode((void*)(pcmd - draw_list->CmdBuffer.begin()), + "Draw %4d %s vtx, tex 0x%p, clip_rect (%4.0f,%4.0f)-(%4.0f,%4.0f)", + pcmd->ElemCount, draw_list->IdxBuffer.Size > 0 ? "indexed" : "non-indexed", (void*)(intptr_t)pcmd->TextureId, pcmd->ClipRect.x, pcmd->ClipRect.y, pcmd->ClipRect.z, pcmd->ClipRect.w); if (show_drawcmd_clip_rects && fg_draw_list && ImGui::IsItemHovered()) { ImRect clip_rect = pcmd->ClipRect; From 7355c847016ec01f0c5b2186f56d7783e75ceb4c Mon Sep 17 00:00:00 2001 From: omar Date: Sun, 12 May 2019 21:35:05 +0200 Subject: [PATCH 04/11] Tweak EndGroup() to facilitate fixing #2550 later (currently should have no side-effect0. Demo: Add extra widget to status query test. --- imgui.cpp | 9 ++++++--- imgui_demo.cpp | 21 +++++++++++++-------- 2 files changed, 19 insertions(+), 11 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index b9cce1f9..9087752a 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -6825,10 +6825,13 @@ void ImGui::EndGroup() // If the current ActiveId was declared within the boundary of our group, we copy it to LastItemId so IsItemActive(), IsItemDeactivated() etc. will be functional on the entire group. // It would be be neater if we replaced window.DC.LastItemId by e.g. 'bool LastItemIsActive', but would put a little more burden on individual widgets. - // (and if you grep for LastItemId you'll notice it is only used in that context. - if ((group_data.BackupActiveIdIsAlive != g.ActiveId) && (g.ActiveIdIsAlive == g.ActiveId) && g.ActiveId) // && g.ActiveIdWindow->RootWindow == window->RootWindow) + // Also if you grep for LastItemId you'll notice it is only used in that context. + // (The tests not symmetrical because ActiveIdIsAlive is an ID itself, in order to be able to handle ActiveId being overwritten during the frame.) + const bool group_contains_curr_active_id = (group_data.BackupActiveIdIsAlive != g.ActiveId) && (g.ActiveIdIsAlive == g.ActiveId) && g.ActiveId; + const bool group_contains_prev_active_id = !group_data.BackupActiveIdPreviousFrameIsAlive && g.ActiveIdPreviousFrameIsAlive; + if (group_contains_curr_active_id) window->DC.LastItemId = g.ActiveId; - else if (!group_data.BackupActiveIdPreviousFrameIsAlive && g.ActiveIdPreviousFrameIsAlive) // && g.ActiveIdPreviousFrameWindow->RootWindow == window->RootWindow) + else if (group_contains_prev_active_id) window->DC.LastItemId = g.ActiveIdPreviousFrame; window->DC.LastItemRect = group_bb; diff --git a/imgui_demo.cpp b/imgui_demo.cpp index e0d9c761..f9cb7c6b 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -1533,10 +1533,11 @@ static void ShowDemoWindowWidgets() ImGui::RadioButton("Checkbox", &item_type, 2); ImGui::RadioButton("SliderFloat", &item_type, 3); ImGui::RadioButton("InputText", &item_type, 4); - ImGui::RadioButton("ColorEdit4", &item_type, 5); - ImGui::RadioButton("MenuItem", &item_type, 6); - ImGui::RadioButton("TreeNode (w/ double-click)", &item_type, 7); - ImGui::RadioButton("ListBox", &item_type, 8); + ImGui::RadioButton("InputFloat3", &item_type, 5); + ImGui::RadioButton("ColorEdit4", &item_type, 6); + ImGui::RadioButton("MenuItem", &item_type, 7); + ImGui::RadioButton("TreeNode (w/ double-click)", &item_type, 8); + ImGui::RadioButton("ListBox", &item_type, 9); ImGui::Separator(); bool ret = false; if (item_type == 0) { ImGui::Text("ITEM: Text"); } // Testing text items with no identifier/interaction @@ -1544,10 +1545,11 @@ static void ShowDemoWindowWidgets() if (item_type == 2) { ret = ImGui::Checkbox("ITEM: Checkbox", &b); } // Testing checkbox if (item_type == 3) { ret = ImGui::SliderFloat("ITEM: SliderFloat", &col4f[0], 0.0f, 1.0f); } // Testing basic item if (item_type == 4) { ret = ImGui::InputText("ITEM: InputText", &str[0], IM_ARRAYSIZE(str)); } // Testing input text (which handles tabbing) - if (item_type == 5) { ret = ImGui::ColorEdit4("ITEM: ColorEdit4", col4f); } // Testing multi-component items (IsItemXXX flags are reported merged) - if (item_type == 6) { ret = ImGui::MenuItem("ITEM: MenuItem"); } // Testing menu item (they use ImGuiButtonFlags_PressedOnRelease button policy) - if (item_type == 7) { ret = ImGui::TreeNodeEx("ITEM: TreeNode w/ ImGuiTreeNodeFlags_OpenOnDoubleClick", ImGuiTreeNodeFlags_OpenOnDoubleClick | ImGuiTreeNodeFlags_NoTreePushOnOpen); } // Testing tree node with ImGuiButtonFlags_PressedOnDoubleClick button policy. - if (item_type == 8) { const char* items[] = { "Apple", "Banana", "Cherry", "Kiwi" }; static int current = 1; ret = ImGui::ListBox("ITEM: ListBox", ¤t, items, IM_ARRAYSIZE(items), IM_ARRAYSIZE(items)); } + if (item_type == 5) { ret = ImGui::InputFloat3("ITEM: InputFloat3", col4f); } // Testing multi-component items (IsItemXXX flags are reported merged) + if (item_type == 6) { ret = ImGui::ColorEdit4("ITEM: ColorEdit4", col4f); } // Testing multi-component items (IsItemXXX flags are reported merged) + if (item_type == 7) { ret = ImGui::MenuItem("ITEM: MenuItem"); } // Testing menu item (they use ImGuiButtonFlags_PressedOnRelease button policy) + if (item_type == 8) { ret = ImGui::TreeNodeEx("ITEM: TreeNode w/ ImGuiTreeNodeFlags_OpenOnDoubleClick", ImGuiTreeNodeFlags_OpenOnDoubleClick | ImGuiTreeNodeFlags_NoTreePushOnOpen); } // Testing tree node with ImGuiButtonFlags_PressedOnDoubleClick button policy. + if (item_type == 9) { const char* items[] = { "Apple", "Banana", "Cherry", "Kiwi" }; static int current = 1; ret = ImGui::ListBox("ITEM: ListBox", ¤t, items, IM_ARRAYSIZE(items), IM_ARRAYSIZE(items)); } ImGui::BulletText( "Return value = %d\n" "IsItemFocused() = %d\n" @@ -1628,6 +1630,9 @@ static void ShowDemoWindowWidgets() if (embed_all_inside_a_child_window) ImGui::EndChild(); + static char dummy_str[] = "This is a dummy field to be able to tab-out of the widgets above."; + ImGui::InputText("dummy", dummy_str, IM_ARRAYSIZE(dummy_str), ImGuiInputTextFlags_ReadOnly); + // Calling IsItemHovered() after begin returns the hovered status of the title bar. // This is useful in particular if you want to create a context menu (with BeginPopupContextItem) associated to the title bar of a window. static bool test_window = false; From 0b485f12d7b420a12a53a9a2d685e0cb75532a87 Mon Sep 17 00:00:00 2001 From: omar Date: Mon, 13 May 2019 11:25:38 +0200 Subject: [PATCH 05/11] Internal: Minor tidying/reordering of sections within ImGuiContext / window DC. --- imgui.cpp | 16 +++++++++------- imgui_internal.h | 49 ++++++++++++++++++++++++++++++----------------- imgui_widgets.cpp | 2 +- 3 files changed, 41 insertions(+), 26 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 9087752a..808594bc 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -6786,7 +6786,7 @@ void ImGui::BeginGroup() group_data.BackupCurrentLineTextBaseOffset = window->DC.CurrentLineTextBaseOffset; group_data.BackupActiveIdIsAlive = g.ActiveIdIsAlive; group_data.BackupActiveIdPreviousFrameIsAlive = g.ActiveIdPreviousFrameIsAlive; - group_data.AdvanceCursor = true; + group_data.EmitItem = true; window->DC.GroupOffset.x = window->DC.CursorPos.x - window->Pos.x - window->DC.ColumnsOffset.x; window->DC.Indent = window->DC.GroupOffset; @@ -6804,8 +6804,7 @@ void ImGui::EndGroup() ImGuiGroupData& group_data = window->DC.GroupStack.back(); - ImRect group_bb(group_data.BackupCursorPos, window->DC.CursorMaxPos); - group_bb.Max = ImMax(group_bb.Min, group_bb.Max); + ImRect group_bb(group_data.BackupCursorPos, ImMax(window->DC.CursorMaxPos, group_data.BackupCursorPos)); window->DC.CursorPos = group_data.BackupCursorPos; window->DC.CursorMaxPos = ImMax(group_data.BackupCursorMaxPos, window->DC.CursorMaxPos); @@ -6816,13 +6815,16 @@ void ImGui::EndGroup() if (g.LogEnabled) g.LogLinePosY = -FLT_MAX; // To enforce Log carriage return - if (group_data.AdvanceCursor) + if (!group_data.EmitItem) { - window->DC.CurrentLineTextBaseOffset = ImMax(window->DC.PrevLineTextBaseOffset, group_data.BackupCurrentLineTextBaseOffset); // FIXME: Incorrect, we should grab the base offset from the *first line* of the group but it is hard to obtain now. - ItemSize(group_bb.GetSize(), 0.0f); - ItemAdd(group_bb, 0); + window->DC.GroupStack.pop_back(); + return; } + window->DC.CurrentLineTextBaseOffset = ImMax(window->DC.PrevLineTextBaseOffset, group_data.BackupCurrentLineTextBaseOffset); // FIXME: Incorrect, we should grab the base offset from the *first line* of the group but it is hard to obtain now. + ItemSize(group_bb.GetSize(), 0.0f); + ItemAdd(group_bb, 0); + // If the current ActiveId was declared within the boundary of our group, we copy it to LastItemId so IsItemActive(), IsItemDeactivated() etc. will be functional on the entire group. // It would be be neater if we replaced window.DC.LastItemId by e.g. 'bool LastItemIsActive', but would put a little more burden on individual widgets. // Also if you grep for LastItemId you'll notice it is only used in that context. diff --git a/imgui_internal.h b/imgui_internal.h index fd579a37..868a3e98 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -575,7 +575,7 @@ struct ImGuiGroupData float BackupCurrentLineTextBaseOffset; ImGuiID BackupActiveIdIsAlive; bool BackupActiveIdPreviousFrameIsAlive; - bool AdvanceCursor; + bool EmitItem; }; // Simple column measurement, currently used for MenuItem() only.. This is very short-sighted/throw-away code and NOT a generic helper. @@ -818,11 +818,12 @@ struct ImGuiContext float FontSize; // (Shortcut) == FontBaseSize * g.CurrentWindow->FontWindowScale == window->FontSize(). Text height for current window. float FontBaseSize; // (Shortcut) == IO.FontGlobalScale * Font->Scale * Font->FontSize. Base text height. ImDrawListSharedData DrawListSharedData; - double Time; int FrameCount; int FrameCountEnded; int FrameCountRendered; + + // Windows state ImVector Windows; // Windows, sorted in display order, back to front ImVector WindowsFocusOrder; // Windows, sorted in focus order, back to front ImVector WindowsSortBuffer; @@ -832,39 +833,45 @@ struct ImGuiContext ImGuiWindow* CurrentWindow; // Being drawn into ImGuiWindow* HoveredWindow; // Will catch mouse inputs ImGuiWindow* HoveredRootWindow; // Will catch mouse inputs (for focus/move only) + ImGuiWindow* MovingWindow; // Track the window we clicked on (in order to preserve focus). The actually window that is moved is generally MovingWindow->RootWindow. + + // Item/widgets state and tracking information ImGuiID HoveredId; // Hovered widget bool HoveredIdAllowOverlap; ImGuiID HoveredIdPreviousFrame; float HoveredIdTimer; // Measure contiguous hovering time float HoveredIdNotActiveTimer; // Measure contiguous hovering time where the item has not been active ImGuiID ActiveId; // Active widget - ImGuiID ActiveIdPreviousFrame; ImGuiID ActiveIdIsAlive; // Active widget has been seen this frame (we can't use a bool as the ActiveId may change within the frame) float ActiveIdTimer; bool ActiveIdIsJustActivated; // Set at the time of activation for one frame bool ActiveIdAllowOverlap; // Active widget allows another widget to steal active id (generally for overlapping widgets, but not always) bool ActiveIdHasBeenPressed; // Track whether the active id led to a press (this is to allow changing between PressOnClick and PressOnRelease without pressing twice). Used by range_select branch. bool ActiveIdHasBeenEdited; // Was the value associated to the widget Edited over the course of the Active state. - bool ActiveIdPreviousFrameIsAlive; - bool ActiveIdPreviousFrameHasBeenEdited; int ActiveIdAllowNavDirFlags; // Active widget allows using directional navigation (e.g. can activate a button and move away from it) int ActiveIdBlockNavInputFlags; ImVec2 ActiveIdClickOffset; // Clicked offset from upper-left corner, if applicable (currently only set by ButtonBehavior) ImGuiWindow* ActiveIdWindow; - ImGuiWindow* ActiveIdPreviousFrameWindow; ImGuiInputSource ActiveIdSource; // Activating with mouse or nav (gamepad/keyboard) + ImGuiID ActiveIdPreviousFrame; + bool ActiveIdPreviousFrameIsAlive; + bool ActiveIdPreviousFrameHasBeenEdited; + ImGuiWindow* ActiveIdPreviousFrameWindow; + ImGuiID LastActiveId; // Store the last non-zero ActiveId, useful for animation. float LastActiveIdTimer; // Store the last non-zero ActiveId timer since the beginning of activation, useful for animation. - ImVec2 LastValidMousePos; - ImGuiWindow* MovingWindow; // Track the window we clicked on (in order to preserve focus). The actually window that is moved is generally MovingWindow->RootWindow. + + // Next window/item data + ImGuiNextWindowData NextWindowData; // Storage for SetNextWindow** functions + bool NextTreeNodeOpenVal; // Storage for SetNextTreeNode** functions + ImGuiCond NextTreeNodeOpenCond; + + // Shared stacks ImVector ColorModifiers; // Stack for PushStyleColor()/PopStyleColor() ImVector StyleModifiers; // Stack for PushStyleVar()/PopStyleVar() ImVector FontStack; // Stack for PushFont()/PopFont() ImVectorOpenPopupStack; // Which popups are open (persistent) ImVectorBeginPopupStack; // Which level of BeginPopup() we are in (reset every frame) - ImGuiNextWindowData NextWindowData; // Storage for SetNextWindow** functions - bool NextTreeNodeOpenVal; // Storage for SetNextTreeNode** functions - ImGuiCond NextTreeNodeOpenCond; // Navigation data (for gamepad/keyboard) ImGuiWindow* NavWindow; // Focused window for navigation. Could be called 'FocusWindow' @@ -948,6 +955,7 @@ struct ImGuiContext ImVector TabSortByWidthBuffer; // Widget state + ImVec2 LastValidMousePos; ImGuiInputTextState InputTextState; ImFont InputTextPasswordFont; ImGuiID TempInputTextId; // Temporary text input when CTRL+clicking on a slider, etc. @@ -1003,37 +1011,41 @@ struct ImGuiContext FontSize = FontBaseSize = 0.0f; FontAtlasOwnedByContext = shared_font_atlas ? false : true; IO.Fonts = shared_font_atlas ? shared_font_atlas : IM_NEW(ImFontAtlas)(); - Time = 0.0f; FrameCount = 0; FrameCountEnded = FrameCountRendered = -1; + WindowsActiveCount = 0; CurrentWindow = NULL; HoveredWindow = NULL; HoveredRootWindow = NULL; + MovingWindow = NULL; + HoveredId = 0; HoveredIdAllowOverlap = false; HoveredIdPreviousFrame = 0; HoveredIdTimer = HoveredIdNotActiveTimer = 0.0f; ActiveId = 0; - ActiveIdPreviousFrame = 0; ActiveIdIsAlive = 0; ActiveIdTimer = 0.0f; ActiveIdIsJustActivated = false; ActiveIdAllowOverlap = false; ActiveIdHasBeenPressed = false; ActiveIdHasBeenEdited = false; - ActiveIdPreviousFrameIsAlive = false; - ActiveIdPreviousFrameHasBeenEdited = false; ActiveIdAllowNavDirFlags = 0x00; ActiveIdBlockNavInputFlags = 0x00; ActiveIdClickOffset = ImVec2(-1,-1); - ActiveIdWindow = ActiveIdPreviousFrameWindow = NULL; + ActiveIdWindow = NULL; ActiveIdSource = ImGuiInputSource_None; + + ActiveIdPreviousFrame = 0; + ActiveIdPreviousFrameIsAlive = false; + ActiveIdPreviousFrameHasBeenEdited = false; + ActiveIdPreviousFrameWindow = NULL; + LastActiveId = 0; LastActiveIdTimer = 0.0f; - LastValidMousePos = ImVec2(0.0f, 0.0f); - MovingWindow = NULL; + NextTreeNodeOpenVal = false; NextTreeNodeOpenCond = 0; @@ -1087,6 +1099,7 @@ struct ImGuiContext CurrentTabBar = NULL; + LastValidMousePos = ImVec2(0.0f, 0.0f); TempInputTextId = 0; ColorEditOptions = ImGuiColorEditFlags__OptionsDefault; DragCurrentAccumDirty = false; diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index e0ebdbc2..f09e80be 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -5903,7 +5903,7 @@ void ImGui::EndMenuBar() PopClipRect(); PopID(); window->DC.MenuBarOffset.x = window->DC.CursorPos.x - window->MenuBarRect().Min.x; // Save horizontal position so next append can reuse it. This is kinda equivalent to a per-layer CursorPos. - window->DC.GroupStack.back().AdvanceCursor = false; + window->DC.GroupStack.back().EmitItem = false; EndGroup(); // Restore position on layer 0 window->DC.LayoutType = ImGuiLayoutType_Vertical; window->DC.NavLayerCurrent = ImGuiNavLayer_Main; From 36e714a4590db3299cd72c695ff66c1fe62a47da Mon Sep 17 00:00:00 2001 From: omar Date: Mon, 13 May 2019 14:45:41 +0200 Subject: [PATCH 06/11] Internal: Storing flags for NextWindowData so that we can clear everything with a single write and remove dummy condition fields. --- imgui.cpp | 38 ++++++++++---------- imgui_internal.h | 89 ++++++++++++++++++++++------------------------- imgui_widgets.cpp | 10 +++--- 3 files changed, 67 insertions(+), 70 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 808594bc..781614d2 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -4636,7 +4636,7 @@ static ImGuiWindow* CreateNewWindow(const char* name, ImVec2 size, ImGuiWindowFl static ImVec2 CalcSizeAfterConstraint(ImGuiWindow* window, ImVec2 new_size) { ImGuiContext& g = *GImGui; - if (g.NextWindowData.SizeConstraintCond != 0) + if (g.NextWindowData.Flags & ImGuiNextWindowDataFlags_HasSizeConstraint) { // Using -1,-1 on either X/Y axis to preserve the current size. ImRect cr = g.NextWindowData.SizeConstraintRect; @@ -4993,13 +4993,12 @@ void ImGui::RenderWindowDecorations(ImGuiWindow* window, const ImRect& title_bar { ImU32 bg_col = GetColorU32(GetWindowBgColorIdxFromFlags(flags)); float alpha = 1.0f; - if (g.NextWindowData.BgAlphaCond != 0) + if (g.NextWindowData.Flags & ImGuiNextWindowDataFlags_HasBgAlpha) alpha = g.NextWindowData.BgAlphaVal; if (alpha != 1.0f) bg_col = (bg_col & ~IM_COL32_A_MASK) | (IM_F32_TO_INT8_SAT(alpha) << IM_COL32_A_SHIFT); window->DrawList->AddRectFilled(window->Pos + ImVec2(0, window->TitleBarHeight()), window->Pos + window->Size, bg_col, window_rounding, (flags & ImGuiWindowFlags_NoTitleBar) ? ImDrawCornerFlags_All : ImDrawCornerFlags_Bot); } - g.NextWindowData.BgAlphaCond = 0; // Title bar if (!(flags & ImGuiWindowFlags_NoTitleBar)) @@ -5130,7 +5129,7 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) const bool window_just_created = (window == NULL); if (window_just_created) { - ImVec2 size_on_first_use = (g.NextWindowData.SizeCond != 0) ? g.NextWindowData.SizeVal : ImVec2(0.0f, 0.0f); // Any condition flag will do since we are creating a new window here. + ImVec2 size_on_first_use = (g.NextWindowData.Flags & ImGuiNextWindowDataFlags_HasSize) ? g.NextWindowData.SizeVal : ImVec2(0.0f, 0.0f); // Any condition flag will do since we are creating a new window here. window = CreateNewWindow(name, size_on_first_use, flags); } @@ -5194,7 +5193,7 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) // Process SetNextWindow***() calls bool window_pos_set_by_api = false; bool window_size_x_set_by_api = false, window_size_y_set_by_api = false; - if (g.NextWindowData.PosCond) + if (g.NextWindowData.Flags & ImGuiNextWindowDataFlags_HasPos) { window_pos_set_by_api = (window->SetWindowPosAllowFlags & g.NextWindowData.PosCond) != 0; if (window_pos_set_by_api && ImLengthSqr(g.NextWindowData.PosPivotVal) > 0.00001f) @@ -5210,13 +5209,13 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) SetWindowPos(window, g.NextWindowData.PosVal, g.NextWindowData.PosCond); } } - if (g.NextWindowData.SizeCond) + if (g.NextWindowData.Flags & ImGuiNextWindowDataFlags_HasSize) { window_size_x_set_by_api = (window->SetWindowSizeAllowFlags & g.NextWindowData.SizeCond) != 0 && (g.NextWindowData.SizeVal.x > 0.0f); window_size_y_set_by_api = (window->SetWindowSizeAllowFlags & g.NextWindowData.SizeCond) != 0 && (g.NextWindowData.SizeVal.y > 0.0f); SetWindowSize(window, g.NextWindowData.SizeVal, g.NextWindowData.SizeCond); } - if (g.NextWindowData.ContentSizeCond) + if (g.NextWindowData.Flags & ImGuiNextWindowDataFlags_HasContentSize) { // Adjust passed "client size" to become a "window size" window->SizeContentsExplicit = g.NextWindowData.ContentSizeVal; @@ -5227,9 +5226,9 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) { window->SizeContentsExplicit = ImVec2(0.0f, 0.0f); } - if (g.NextWindowData.CollapsedCond) + if (g.NextWindowData.Flags & ImGuiNextWindowDataFlags_HasCollapsed) SetWindowCollapsed(window, g.NextWindowData.CollapsedVal, g.NextWindowData.CollapsedCond); - if (g.NextWindowData.FocusCond) + if (g.NextWindowData.Flags & ImGuiNextWindowDataFlags_HasFocus) FocusWindow(window); if (window->Appearing) SetWindowConditionAllowFlags(window, ImGuiCond_Appearing, false); @@ -5607,7 +5606,7 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) window->WriteAccessed = false; window->BeginCount++; - g.NextWindowData.Clear(); + g.NextWindowData.ClearFlags(); if (flags & ImGuiWindowFlags_ChildWindow) { @@ -6397,6 +6396,7 @@ void ImGui::SetNextWindowPos(const ImVec2& pos, ImGuiCond cond, const ImVec2& pi { ImGuiContext& g = *GImGui; IM_ASSERT(cond == 0 || ImIsPowerOfTwo(cond)); // Make sure the user doesn't attempt to combine multiple condition flags. + g.NextWindowData.Flags |= ImGuiNextWindowDataFlags_HasPos; g.NextWindowData.PosVal = pos; g.NextWindowData.PosPivotVal = pivot; g.NextWindowData.PosCond = cond ? cond : ImGuiCond_Always; @@ -6406,6 +6406,7 @@ void ImGui::SetNextWindowSize(const ImVec2& size, ImGuiCond cond) { ImGuiContext& g = *GImGui; IM_ASSERT(cond == 0 || ImIsPowerOfTwo(cond)); // Make sure the user doesn't attempt to combine multiple condition flags. + g.NextWindowData.Flags |= ImGuiNextWindowDataFlags_HasSize; g.NextWindowData.SizeVal = size; g.NextWindowData.SizeCond = cond ? cond : ImGuiCond_Always; } @@ -6413,7 +6414,7 @@ void ImGui::SetNextWindowSize(const ImVec2& size, ImGuiCond cond) void ImGui::SetNextWindowSizeConstraints(const ImVec2& size_min, const ImVec2& size_max, ImGuiSizeCallback custom_callback, void* custom_callback_user_data) { ImGuiContext& g = *GImGui; - g.NextWindowData.SizeConstraintCond = ImGuiCond_Always; + g.NextWindowData.Flags |= ImGuiNextWindowDataFlags_HasSizeConstraint; g.NextWindowData.SizeConstraintRect = ImRect(size_min, size_max); g.NextWindowData.SizeCallback = custom_callback; g.NextWindowData.SizeCallbackUserData = custom_callback_user_data; @@ -6422,14 +6423,15 @@ void ImGui::SetNextWindowSizeConstraints(const ImVec2& size_min, const ImVec2& s void ImGui::SetNextWindowContentSize(const ImVec2& size) { ImGuiContext& g = *GImGui; + g.NextWindowData.Flags |= ImGuiNextWindowDataFlags_HasContentSize; g.NextWindowData.ContentSizeVal = size; // In Begin() we will add the size of window decorations (title bar, menu etc.) to that to form a SizeContents value. - g.NextWindowData.ContentSizeCond = ImGuiCond_Always; } void ImGui::SetNextWindowCollapsed(bool collapsed, ImGuiCond cond) { ImGuiContext& g = *GImGui; IM_ASSERT(cond == 0 || ImIsPowerOfTwo(cond)); // Make sure the user doesn't attempt to combine multiple condition flags. + g.NextWindowData.Flags |= ImGuiNextWindowDataFlags_HasCollapsed; g.NextWindowData.CollapsedVal = collapsed; g.NextWindowData.CollapsedCond = cond ? cond : ImGuiCond_Always; } @@ -6437,14 +6439,14 @@ void ImGui::SetNextWindowCollapsed(bool collapsed, ImGuiCond cond) void ImGui::SetNextWindowFocus() { ImGuiContext& g = *GImGui; - g.NextWindowData.FocusCond = ImGuiCond_Always; // Using a Cond member for consistency (may transition all of them to single flag set for fast Clear() op) + g.NextWindowData.Flags |= ImGuiNextWindowDataFlags_HasFocus; } void ImGui::SetNextWindowBgAlpha(float alpha) { ImGuiContext& g = *GImGui; + g.NextWindowData.Flags |= ImGuiNextWindowDataFlags_HasBgAlpha; g.NextWindowData.BgAlphaVal = alpha; - g.NextWindowData.BgAlphaCond = ImGuiCond_Always; // Using a Cond member for consistency (may transition all of them to single flag set for fast Clear() op) } // FIXME: This is in window space (not screen space!). We should try to obsolete all those functions. @@ -7144,7 +7146,7 @@ bool ImGui::BeginPopupEx(ImGuiID id, ImGuiWindowFlags extra_flags) ImGuiContext& g = *GImGui; if (!IsPopupOpen(id)) { - g.NextWindowData.Clear(); // We behave like Begin() and need to consume those values + g.NextWindowData.ClearFlags(); // We behave like Begin() and need to consume those values return false; } @@ -7166,7 +7168,7 @@ bool ImGui::BeginPopup(const char* str_id, ImGuiWindowFlags flags) ImGuiContext& g = *GImGui; if (g.OpenPopupStack.Size <= g.BeginPopupStack.Size) // Early out for performance { - g.NextWindowData.Clear(); // We behave like Begin() and need to consume those values + g.NextWindowData.ClearFlags(); // We behave like Begin() and need to consume those values return false; } flags |= ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoSavedSettings; @@ -7182,13 +7184,13 @@ bool ImGui::BeginPopupModal(const char* name, bool* p_open, ImGuiWindowFlags fla const ImGuiID id = window->GetID(name); if (!IsPopupOpen(id)) { - g.NextWindowData.Clear(); // We behave like Begin() and need to consume those values + g.NextWindowData.ClearFlags(); // We behave like Begin() and need to consume those values return false; } // Center modal windows by default // FIXME: Should test for (PosCond & window->SetWindowPosAllowFlags) with the upcoming window. - if (g.NextWindowData.PosCond == 0) + if ((g.NextWindowData.Flags & ImGuiNextWindowDataFlags_HasPos) == 0) SetNextWindowPos(g.IO.DisplaySize * 0.5f, ImGuiCond_Appearing, ImVec2(0.5f, 0.5f)); flags |= ImGuiWindowFlags_Popup | ImGuiWindowFlags_Modal | ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoSavedSettings; diff --git a/imgui_internal.h b/imgui_internal.h index 868a3e98..494d5481 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -71,7 +71,7 @@ struct ImGuiInputTextState; // Internal state of the currently focused/e struct ImGuiItemHoveredDataBackup; // Backup and restore IsItemHovered() internal data struct ImGuiMenuColumns; // Simple column measurement, currently used for MenuItem() only struct ImGuiNavMoveResult; // Result of a directional navigation move query result -struct ImGuiNextWindowData; // Storage for SetNexWindow** functions +struct ImGuiNextWindowData; // Storage for SetNextWindow** functions struct ImGuiPopupData; // Storage for current popup stack struct ImGuiSettingsHandler; // Storage for one type registered in the .ini file struct ImGuiStyleMod; // Stacked style modifier, backup of modified data so we can restore it @@ -82,17 +82,18 @@ struct ImGuiWindowTempData; // Temporary storage for one window (that's struct ImGuiWindowSettings; // Storage for window settings stored in .ini file (we keep one of those even if the actual window wasn't instanced during this session) // Use your programming IDE "Go to definition" facility on the names of the center columns to find the actual flags/enum lists. -typedef int ImGuiLayoutType; // -> enum ImGuiLayoutType_ // Enum: Horizontal or vertical -typedef int ImGuiButtonFlags; // -> enum ImGuiButtonFlags_ // Flags: for ButtonEx(), ButtonBehavior() -typedef int ImGuiDragFlags; // -> enum ImGuiDragFlags_ // Flags: for DragBehavior() -typedef int ImGuiItemFlags; // -> enum ImGuiItemFlags_ // Flags: for PushItemFlag() -typedef int ImGuiItemStatusFlags; // -> enum ImGuiItemStatusFlags_ // Flags: for DC.LastItemStatusFlags -typedef int ImGuiNavHighlightFlags; // -> enum ImGuiNavHighlightFlags_ // Flags: for RenderNavHighlight() -typedef int ImGuiNavDirSourceFlags; // -> enum ImGuiNavDirSourceFlags_ // Flags: for GetNavInputAmount2d() -typedef int ImGuiNavMoveFlags; // -> enum ImGuiNavMoveFlags_ // Flags: for navigation requests -typedef int ImGuiSeparatorFlags; // -> enum ImGuiSeparatorFlags_ // Flags: for Separator() - internal -typedef int ImGuiSliderFlags; // -> enum ImGuiSliderFlags_ // Flags: for SliderBehavior() -typedef int ImGuiTextFlags; // -> enum ImGuiTextFlags_ // Flags: for TextEx() +typedef int ImGuiLayoutType; // -> enum ImGuiLayoutType_ // Enum: Horizontal or vertical +typedef int ImGuiButtonFlags; // -> enum ImGuiButtonFlags_ // Flags: for ButtonEx(), ButtonBehavior() +typedef int ImGuiDragFlags; // -> enum ImGuiDragFlags_ // Flags: for DragBehavior() +typedef int ImGuiItemFlags; // -> enum ImGuiItemFlags_ // Flags: for PushItemFlag() +typedef int ImGuiItemStatusFlags; // -> enum ImGuiItemStatusFlags_ // Flags: for DC.LastItemStatusFlags +typedef int ImGuiNavHighlightFlags; // -> enum ImGuiNavHighlightFlags_ // Flags: for RenderNavHighlight() +typedef int ImGuiNavDirSourceFlags; // -> enum ImGuiNavDirSourceFlags_ // Flags: for GetNavInputAmount2d() +typedef int ImGuiNavMoveFlags; // -> enum ImGuiNavMoveFlags_ // Flags: for navigation requests +typedef int ImGuiNextWindowDataFlags; // -> enum ImGuiNextWindowDataFlags_// Flags: for SetNextWindowXXX() functions +typedef int ImGuiSeparatorFlags; // -> enum ImGuiSeparatorFlags_ // Flags: for SeparatorEx() +typedef int ImGuiSliderFlags; // -> enum ImGuiSliderFlags_ // Flags: for SliderBehavior() +typedef int ImGuiTextFlags; // -> enum ImGuiTextFlags_ // Flags: for TextEx() //------------------------------------------------------------------------- // STB libraries includes @@ -743,44 +744,38 @@ struct ImGuiNavMoveResult void Clear() { ID = SelectScopeId = 0; Window = NULL; DistBox = DistCenter = DistAxial = FLT_MAX; RectRel = ImRect(); } }; +enum ImGuiNextWindowDataFlags_ +{ + ImGuiNextWindowDataFlags_None = 0, + ImGuiNextWindowDataFlags_HasPos = 1 << 0, + ImGuiNextWindowDataFlags_HasSize = 1 << 1, + ImGuiNextWindowDataFlags_HasContentSize = 1 << 2, + ImGuiNextWindowDataFlags_HasCollapsed = 1 << 3, + ImGuiNextWindowDataFlags_HasSizeConstraint = 1 << 4, + ImGuiNextWindowDataFlags_HasFocus = 1 << 5, + ImGuiNextWindowDataFlags_HasBgAlpha = 1 << 6 +}; + // Storage for SetNexWindow** functions struct ImGuiNextWindowData { - ImGuiCond PosCond; - ImGuiCond SizeCond; - ImGuiCond ContentSizeCond; - ImGuiCond CollapsedCond; - ImGuiCond SizeConstraintCond; - ImGuiCond FocusCond; - ImGuiCond BgAlphaCond; - ImVec2 PosVal; - ImVec2 PosPivotVal; - ImVec2 SizeVal; - ImVec2 ContentSizeVal; - bool CollapsedVal; - ImRect SizeConstraintRect; - ImGuiSizeCallback SizeCallback; - void* SizeCallbackUserData; - float BgAlphaVal; - ImVec2 MenuBarOffsetMinVal; // This is not exposed publicly, so we don't clear it. - - ImGuiNextWindowData() - { - PosCond = SizeCond = ContentSizeCond = CollapsedCond = SizeConstraintCond = FocusCond = BgAlphaCond = 0; - PosVal = PosPivotVal = SizeVal = ImVec2(0.0f, 0.0f); - ContentSizeVal = ImVec2(0.0f, 0.0f); - CollapsedVal = false; - SizeConstraintRect = ImRect(); - SizeCallback = NULL; - SizeCallbackUserData = NULL; - BgAlphaVal = FLT_MAX; - MenuBarOffsetMinVal = ImVec2(0.0f, 0.0f); - } - - void Clear() - { - PosCond = SizeCond = ContentSizeCond = CollapsedCond = SizeConstraintCond = FocusCond = BgAlphaCond = 0; - } + ImGuiNextWindowDataFlags Flags; + ImGuiCond PosCond; + ImGuiCond SizeCond; + ImGuiCond CollapsedCond; + ImVec2 PosVal; + ImVec2 PosPivotVal; + ImVec2 SizeVal; + ImVec2 ContentSizeVal; + bool CollapsedVal; + ImRect SizeConstraintRect; + ImGuiSizeCallback SizeCallback; + void* SizeCallbackUserData; + float BgAlphaVal; + ImVec2 MenuBarOffsetMinVal; // This is not exposed publicly, so we don't clear it. + + ImGuiNextWindowData() { memset(this, 0, sizeof(*this)); } + inline void ClearFlags() { Flags = ImGuiNextWindowDataFlags_None; } }; //----------------------------------------------------------------------------- diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index f09e80be..490b672d 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -1350,8 +1350,8 @@ bool ImGui::BeginCombo(const char* label, const char* preview_value, ImGuiComboF { // Always consume the SetNextWindowSizeConstraint() call in our early return paths ImGuiContext& g = *GImGui; - ImGuiCond backup_next_window_size_constraint = g.NextWindowData.SizeConstraintCond; - g.NextWindowData.SizeConstraintCond = 0; + bool has_window_size_constraint = (g.NextWindowData.Flags & ImGuiNextWindowDataFlags_HasSizeConstraint) != 0; + g.NextWindowData.Flags &= ~ImGuiNextWindowDataFlags_HasSizeConstraint; ImGuiWindow* window = GetCurrentWindow(); if (window->SkipItems) @@ -1403,9 +1403,9 @@ bool ImGui::BeginCombo(const char* label, const char* preview_value, ImGuiComboF if (!popup_open) return false; - if (backup_next_window_size_constraint) + if (has_window_size_constraint) { - g.NextWindowData.SizeConstraintCond = backup_next_window_size_constraint; + g.NextWindowData.Flags |= ImGuiNextWindowDataFlags_HasSizeConstraint; g.NextWindowData.SizeConstraintRect.Min.x = ImMax(g.NextWindowData.SizeConstraintRect.Min.x, w); } else @@ -1495,7 +1495,7 @@ bool ImGui::Combo(const char* label, int* current_item, bool (*items_getter)(voi items_getter(data, *current_item, &preview_value); // The old Combo() API exposed "popup_max_height_in_items". The new more general BeginCombo() API doesn't have/need it, but we emulate it here. - if (popup_max_height_in_items != -1 && !g.NextWindowData.SizeConstraintCond) + if (popup_max_height_in_items != -1 && !(g.NextWindowData.Flags & ImGuiNextWindowDataFlags_HasSizeConstraint)) SetNextWindowSizeConstraints(ImVec2(0,0), ImVec2(FLT_MAX, CalcMaxPopupHeightFromItemCount(popup_max_height_in_items))); if (!BeginCombo(label, preview_value, ImGuiComboFlags_None)) From 632469d2e5533f2a3ffda2ccd5c96551b479a2b7 Mon Sep 17 00:00:00 2001 From: omar Date: Mon, 13 May 2019 15:11:25 +0200 Subject: [PATCH 07/11] Renamed SetNextTreeNodeOpen() to SetNextItemOpen(). Refactored SetNextItemXXX stuff to match SetNextWindowXXX code closely. --- docs/CHANGELOG.txt | 1 + imgui.cpp | 24 ++++++++++++++---------- imgui.h | 7 +++++-- imgui_demo.cpp | 9 ++++++++- imgui_internal.h | 30 ++++++++++++++++++++++-------- imgui_widgets.cpp | 20 ++++++++++---------- 6 files changed, 60 insertions(+), 31 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index d7f4ca26..641e11c1 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -34,6 +34,7 @@ HOW TO UPDATE? Breaking Changes: - IO: changed AddInputCharacter(unsigned short c) signature to AddInputCharacter(unsigned int c). +- Renamed SetNextTreeNodeOpen() to SetNextItemOpen(). Kept inline redirection function (will obsolete). Other Changes: - Columns: Fixed Separator from creating an extraneous draw command. (#125) diff --git a/imgui.cpp b/imgui.cpp index 781614d2..3baeed9d 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -369,6 +369,7 @@ CODE When you are not sure about a old symbol or function name, try using the Search/Find function of your IDE to look for comments or references in all imgui files. You can read releases logs https://github.com/ocornut/imgui/releases for more details. + - 2019/05/13 (1.71) - renamed SetNextTreeNodeOpen() to SetNextItemOpen(). Kept inline redirection function (will obsolete). - 2019/05/11 (1.71) - changed io.AddInputCharacter(unsigned short c) signature to io.AddInputCharacter(unsigned int c). - 2019/04/29 (1.70) - improved ImDrawList thick strokes (>1.0f) preserving correct thickness up to 90 degrees angles (e.g. rectangles). If you have custom rendering using thick lines, they will appear thicker now. - 2019/04/29 (1.70) - removed GetContentRegionAvailWidth(), use GetContentRegionAvail().x instead. Kept inline redirection function (will obsolete). @@ -2840,6 +2841,7 @@ bool ImGui::ItemAdd(const ImRect& bb, ImGuiID id, const ImRect* nav_bb_arg) window->DC.LastItemId = id; window->DC.LastItemRect = bb; window->DC.LastItemStatusFlags = ImGuiItemStatusFlags_None; + g.NextItemData.Flags = ImGuiNextItemDataFlags_None; #ifdef IMGUI_ENABLE_TEST_ENGINE if (id != 0) @@ -5794,8 +5796,9 @@ void ImGui::FocusTopMostWindowUnderOne(ImGuiWindow* under_this_window, ImGuiWind void ImGui::SetNextItemWidth(float item_width) { - ImGuiWindow* window = GetCurrentWindow(); - window->DC.NextItemWidth = item_width; + ImGuiContext& g = *GImGui; + g.NextItemData.Flags |= ImGuiNextItemDataFlags_HasWidth; + g.NextItemData.Width = item_width; } void ImGui::PushItemWidth(float item_width) @@ -5825,15 +5828,16 @@ void ImGui::PopItemWidth() } // Calculate default item width given value passed to PushItemWidth() or SetNextItemWidth(), -// Then consume the +// Then _consume_ the SetNextItemWidth() data. float ImGui::GetNextItemWidth() { - ImGuiWindow* window = GImGui->CurrentWindow; + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; float w; - if (window->DC.NextItemWidth != FLT_MAX) + if (g.NextItemData.Flags & ImGuiNextItemDataFlags_HasWidth) { - w = window->DC.NextItemWidth; - window->DC.NextItemWidth = FLT_MAX; + w = g.NextItemData.Width; + g.NextItemData.Flags &= ~ImGuiNextItemDataFlags_HasWidth; } else { @@ -5852,10 +5856,10 @@ float ImGui::GetNextItemWidth() // (rarely used, which is why we avoid calling this from GetNextItemWidth() and instead do a backup/restore here) float ImGui::CalcItemWidth() { - ImGuiWindow* window = GImGui->CurrentWindow; - float backup_next_item_width = window->DC.NextItemWidth; + ImGuiContext& g = *GImGui; + ImGuiNextItemDataFlags backup_flags = g.NextItemData.Flags; float w = GetNextItemWidth(); - window->DC.NextItemWidth = backup_next_item_width; + g.NextItemData.Flags = backup_flags; return w; } diff --git a/imgui.h b/imgui.h index 7c05d7c4..0bcea46b 100644 --- a/imgui.h +++ b/imgui.h @@ -494,9 +494,9 @@ namespace ImGui IMGUI_API void TreePop(); // ~ Unindent()+PopId() IMGUI_API void TreeAdvanceToLabelPos(); // advance cursor x position by GetTreeNodeToLabelSpacing() IMGUI_API float GetTreeNodeToLabelSpacing(); // horizontal distance preceding label when using TreeNode*() or Bullet() == (g.FontSize + style.FramePadding.x*2) for a regular unframed TreeNode - IMGUI_API void SetNextTreeNodeOpen(bool is_open, ImGuiCond cond = 0); // set next TreeNode/CollapsingHeader open state. IMGUI_API bool CollapsingHeader(const char* label, ImGuiTreeNodeFlags flags = 0); // if returning 'true' the header is open. doesn't indent nor push on ID stack. user doesn't have to call TreePop(). IMGUI_API bool CollapsingHeader(const char* label, bool* p_open, ImGuiTreeNodeFlags flags = 0); // when 'p_open' isn't NULL, display an additional small close button on upper right of the header + IMGUI_API void SetNextItemOpen(bool is_open, ImGuiCond cond = 0); // set next TreeNode/CollapsingHeader open state. // Widgets: Selectables // - A selectable highlights when hovered, and can display another color when selected. @@ -1173,7 +1173,7 @@ enum ImGuiMouseCursor_ #endif }; -// Enumateration for ImGui::SetWindow***(), SetNextWindow***(), SetNextTreeNode***() functions +// Enumateration for ImGui::SetWindow***(), SetNextWindow***(), SetNextItem***() functions // Represent a condition. // Important: Treat as a regular enum! Do NOT combine multiple values using binary operators! All the functions above treat 0 as a shortcut to ImGuiCond_Always. enum ImGuiCond_ @@ -1529,6 +1529,9 @@ struct ImGuiPayload #ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS namespace ImGui { + // OBSOLETED in 1.71 (from May 2019) + static inline void SetNextTreeNodeOpen(bool open, ImGuiCond cond = 0) { SetNextItemOpen(open, cond); } + // OBSOLETED in 1.70 (from May 2019) static inline float GetContentRegionAvailWidth() { return GetContentRegionAvail().x; } // OBSOLETED in 1.69 (from Mar 2019) diff --git a/imgui_demo.cpp b/imgui_demo.cpp index f9cb7c6b..7ce699d1 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -568,13 +568,20 @@ static void ShowDemoWindowWidgets() if (ImGui::TreeNode("Basic trees")) { for (int i = 0; i < 5; i++) + { + // Use SetNextItemOpen() so set the default state of a node to be open. + // We could also use TreeNodeEx() with the ImGuiTreeNodeFlags_DefaultOpen flag to achieve the same thing! + if (i == 0) + ImGui::SetNextItemOpen(true, ImGuiCond_Once); + if (ImGui::TreeNode((void*)(intptr_t)i, "Child %d", i)) { ImGui::Text("blah blah"); ImGui::SameLine(); - if (ImGui::SmallButton("button")) { }; + if (ImGui::SmallButton("button")) {}; ImGui::TreePop(); } + } ImGui::TreePop(); } diff --git a/imgui_internal.h b/imgui_internal.h index 494d5481..d4508657 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -72,6 +72,7 @@ struct ImGuiItemHoveredDataBackup; // Backup and restore IsItemHovered() intern struct ImGuiMenuColumns; // Simple column measurement, currently used for MenuItem() only struct ImGuiNavMoveResult; // Result of a directional navigation move query result struct ImGuiNextWindowData; // Storage for SetNextWindow** functions +struct ImGuiNextItemData; // Storage for SetNextItem** functions struct ImGuiPopupData; // Storage for current popup stack struct ImGuiSettingsHandler; // Storage for one type registered in the .ini file struct ImGuiStyleMod; // Stacked style modifier, backup of modified data so we can restore it @@ -90,6 +91,7 @@ typedef int ImGuiItemStatusFlags; // -> enum ImGuiItemStatusFlags_ // F typedef int ImGuiNavHighlightFlags; // -> enum ImGuiNavHighlightFlags_ // Flags: for RenderNavHighlight() typedef int ImGuiNavDirSourceFlags; // -> enum ImGuiNavDirSourceFlags_ // Flags: for GetNavInputAmount2d() typedef int ImGuiNavMoveFlags; // -> enum ImGuiNavMoveFlags_ // Flags: for navigation requests +typedef int ImGuiNextItemDataFlags; // -> enum ImGuiNextItemDataFlags_ // Flags: for SetNextItemXXX() functions typedef int ImGuiNextWindowDataFlags; // -> enum ImGuiNextWindowDataFlags_// Flags: for SetNextWindowXXX() functions typedef int ImGuiSeparatorFlags; // -> enum ImGuiSeparatorFlags_ // Flags: for SeparatorEx() typedef int ImGuiSliderFlags; // -> enum ImGuiSliderFlags_ // Flags: for SliderBehavior() @@ -778,6 +780,24 @@ struct ImGuiNextWindowData inline void ClearFlags() { Flags = ImGuiNextWindowDataFlags_None; } }; +enum ImGuiNextItemDataFlags_ +{ + ImGuiNextItemDataFlags_None = 0, + ImGuiNextItemDataFlags_HasWidth = 1 << 0, + ImGuiNextItemDataFlags_HasOpen = 1 << 1 +}; + +struct ImGuiNextItemData +{ + ImGuiNextItemDataFlags Flags; + float Width; // Set by SetNextItemWidth(). + bool OpenVal; // Set by SetNextItemOpen() function. + ImGuiCond OpenCond; + + ImGuiNextItemData() { memset(this, 0, sizeof(*this)); } + inline void ClearFlags() { Flags = ImGuiNextItemDataFlags_None; } +}; + //----------------------------------------------------------------------------- // Tabs //----------------------------------------------------------------------------- @@ -858,8 +878,7 @@ struct ImGuiContext // Next window/item data ImGuiNextWindowData NextWindowData; // Storage for SetNextWindow** functions - bool NextTreeNodeOpenVal; // Storage for SetNextTreeNode** functions - ImGuiCond NextTreeNodeOpenCond; + ImGuiNextItemData NextItemData; // Storage for SetNextItem** functions // Shared stacks ImVector ColorModifiers; // Stack for PushStyleColor()/PopStyleColor() @@ -1041,9 +1060,6 @@ struct ImGuiContext LastActiveId = 0; LastActiveIdTimer = 0.0f; - NextTreeNodeOpenVal = false; - NextTreeNodeOpenCond = 0; - NavWindow = NULL; NavId = NavActivateId = NavActivateDownId = NavActivatePressedId = NavInputId = 0; NavJustTabbedId = NavJustMovedToId = NavJustMovedToMultiSelectScopeId = NavNextActivateId = 0; @@ -1166,7 +1182,6 @@ struct IMGUI_API ImGuiWindowTempData // We store the current settings outside of the vectors to increase memory locality (reduce cache misses). The vectors are rarely modified. Also it allows us to not heap allocate for short-lived windows which are not using those settings. ImGuiItemFlags ItemFlags; // == ItemFlagsStack.back() [empty == ImGuiItemFlags_Default] float ItemWidth; // == ItemWidthStack.back(). 0.0: default, >0.0: width in pixels, <0.0: align xx pixels to the right of window - float NextItemWidth; float TextWrapPos; // == TextWrapPosStack.back() [empty == -1.0f] ImVectorItemFlagsStack; ImVector ItemWidthStack; @@ -1202,7 +1217,6 @@ struct IMGUI_API ImGuiWindowTempData ItemFlags = ImGuiItemFlags_Default_; ItemWidth = 0.0f; - NextItemWidth = +FLT_MAX; TextWrapPos = -1.0f; memset(StackSizesBackup, 0, sizeof(StackSizesBackup)); @@ -1569,7 +1583,7 @@ namespace ImGui IMGUI_API bool SliderBehavior(const ImRect& bb, ImGuiID id, ImGuiDataType data_type, void* v, const void* v_min, const void* v_max, const char* format, float power, ImGuiSliderFlags flags, ImRect* out_grab_bb); IMGUI_API bool SplitterBehavior(const ImRect& bb, ImGuiID id, ImGuiAxis axis, float* size1, float* size2, float min_size1, float min_size2, float hover_extend = 0.0f, float hover_visibility_delay = 0.0f); IMGUI_API bool TreeNodeBehavior(ImGuiID id, ImGuiTreeNodeFlags flags, const char* label, const char* label_end = NULL); - IMGUI_API bool TreeNodeBehaviorIsOpen(ImGuiID id, ImGuiTreeNodeFlags flags = 0); // Consume previous SetNextTreeNodeOpened() data, if any. May return true when logging + IMGUI_API bool TreeNodeBehaviorIsOpen(ImGuiID id, ImGuiTreeNodeFlags flags = 0); // Consume previous SetNextItemOpen() data, if any. May return true when logging IMGUI_API void TreePushOverrideID(ImGuiID id); // Template functions are instantiated in imgui_widgets.cpp for a finite number of types. diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index 490b672d..301634c9 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -4906,7 +4906,7 @@ void ImGui::ColorPickerOptionsPopup(const float* ref_col, ImGuiColorEditFlags fl // - TreePop() // - TreeAdvanceToLabelPos() // - GetTreeNodeToLabelSpacing() -// - SetNextTreeNodeOpen() +// - SetNextItemOpen() // - CollapsingHeader() //------------------------------------------------------------------------- @@ -5000,17 +5000,17 @@ bool ImGui::TreeNodeBehaviorIsOpen(ImGuiID id, ImGuiTreeNodeFlags flags) if (flags & ImGuiTreeNodeFlags_Leaf) return true; - // We only write to the tree storage if the user clicks (or explicitly use SetNextTreeNode*** functions) + // We only write to the tree storage if the user clicks (or explicitly use the SetNextItemOpen function) ImGuiContext& g = *GImGui; ImGuiWindow* window = g.CurrentWindow; ImGuiStorage* storage = window->DC.StateStorage; bool is_open; - if (g.NextTreeNodeOpenCond != 0) + if (g.NextItemData.Flags & ImGuiNextItemDataFlags_HasOpen) { - if (g.NextTreeNodeOpenCond & ImGuiCond_Always) + if (g.NextItemData.OpenCond & ImGuiCond_Always) { - is_open = g.NextTreeNodeOpenVal; + is_open = g.NextItemData.OpenVal; storage->SetInt(id, is_open); } else @@ -5019,7 +5019,7 @@ bool ImGui::TreeNodeBehaviorIsOpen(ImGuiID id, ImGuiTreeNodeFlags flags) const int stored_value = storage->GetInt(id, -1); if (stored_value == -1) { - is_open = g.NextTreeNodeOpenVal; + is_open = g.NextItemData.OpenVal; storage->SetInt(id, is_open); } else @@ -5027,7 +5027,6 @@ bool ImGui::TreeNodeBehaviorIsOpen(ImGuiID id, ImGuiTreeNodeFlags flags) is_open = stored_value != 0; } } - g.NextTreeNodeOpenCond = 0; } else { @@ -5256,13 +5255,14 @@ float ImGui::GetTreeNodeToLabelSpacing() return g.FontSize + (g.Style.FramePadding.x * 2.0f); } -void ImGui::SetNextTreeNodeOpen(bool is_open, ImGuiCond cond) +void ImGui::SetNextItemOpen(bool is_open, ImGuiCond cond) { ImGuiContext& g = *GImGui; if (g.CurrentWindow->SkipItems) return; - g.NextTreeNodeOpenVal = is_open; - g.NextTreeNodeOpenCond = cond ? cond : ImGuiCond_Always; + g.NextItemData.Flags |= ImGuiNextItemDataFlags_HasOpen; + g.NextItemData.OpenVal = is_open; + g.NextItemData.OpenCond = cond ? cond : ImGuiCond_Always; } // CollapsingHeader returns true when opened but do not indent nor push into the ID stack (because of the ImGuiTreeNodeFlags_NoTreePushOnOpen flag). From 64dbd932d2b8056a7ad7c85d68f76f2f7738e889 Mon Sep 17 00:00:00 2001 From: omar Date: Mon, 13 May 2019 15:29:00 +0200 Subject: [PATCH 08/11] Internal: Removed GetNextItemWidth(), relying on ItemAdd or NextItemData.ClearFlags() to clear the width data. Amend 5078fa20 and undo some of its effects of imgui_widgets.cpp --- imgui.cpp | 34 +++++++++++----------------------- imgui_internal.h | 1 - imgui_widgets.cpp | 42 ++++++++++++++++++++++++------------------ 3 files changed, 35 insertions(+), 42 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 3baeed9d..e5b2da50 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -5803,14 +5803,17 @@ void ImGui::SetNextItemWidth(float item_width) void ImGui::PushItemWidth(float item_width) { - ImGuiWindow* window = GetCurrentWindow(); + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; window->DC.ItemWidth = (item_width == 0.0f ? window->ItemWidthDefault : item_width); window->DC.ItemWidthStack.push_back(window->DC.ItemWidth); + g.NextItemData.Flags &= ~ImGuiNextItemDataFlags_HasWidth; } void ImGui::PushMultiItemsWidths(int components, float w_full) { - ImGuiWindow* window = GetCurrentWindow(); + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; const ImGuiStyle& style = GImGui->Style; const float w_item_one = ImMax(1.0f, (float)(int)((w_full - (style.ItemInnerSpacing.x) * (components-1)) / (float)components)); const float w_item_last = ImMax(1.0f, (float)(int)(w_full - (w_item_one + style.ItemInnerSpacing.x) * (components-1))); @@ -5818,6 +5821,7 @@ void ImGui::PushMultiItemsWidths(int components, float w_full) for (int i = 0; i < components-1; i++) window->DC.ItemWidthStack.push_back(w_item_one); window->DC.ItemWidth = window->DC.ItemWidthStack.back(); + g.NextItemData.Flags &= ~ImGuiNextItemDataFlags_HasWidth; } void ImGui::PopItemWidth() @@ -5827,22 +5831,17 @@ void ImGui::PopItemWidth() window->DC.ItemWidth = window->DC.ItemWidthStack.empty() ? window->ItemWidthDefault : window->DC.ItemWidthStack.back(); } -// Calculate default item width given value passed to PushItemWidth() or SetNextItemWidth(), -// Then _consume_ the SetNextItemWidth() data. -float ImGui::GetNextItemWidth() +// Calculate default item width given value passed to PushItemWidth() or SetNextItemWidth(). +// The SetNextItemWidth() data is generally cleared/consumed by ItemAdd() or NextItemData.ClearFlags() +float ImGui::CalcItemWidth() { ImGuiContext& g = *GImGui; ImGuiWindow* window = g.CurrentWindow; float w; if (g.NextItemData.Flags & ImGuiNextItemDataFlags_HasWidth) - { w = g.NextItemData.Width; - g.NextItemData.Flags &= ~ImGuiNextItemDataFlags_HasWidth; - } else - { w = window->DC.ItemWidth; - } if (w < 0.0f) { float region_max_x = GetWorkRectMax().x; @@ -5852,21 +5851,10 @@ float ImGui::GetNextItemWidth() return w; } -// Calculate item width *without* popping/consuming NextItemWidth if it was set. -// (rarely used, which is why we avoid calling this from GetNextItemWidth() and instead do a backup/restore here) -float ImGui::CalcItemWidth() -{ - ImGuiContext& g = *GImGui; - ImGuiNextItemDataFlags backup_flags = g.NextItemData.Flags; - float w = GetNextItemWidth(); - g.NextItemData.Flags = backup_flags; - return w; -} - -// [Internal] Calculate full item size given user provided 'size' parameter and default width/height. Default width is often == GetNextItemWidth(). +// [Internal] Calculate full item size given user provided 'size' parameter and default width/height. Default width is often == CalcItemWidth(). // Those two functions CalcItemWidth vs CalcItemSize are awkwardly named because they are not fully symmetrical. // Note that only CalcItemWidth() is publicly exposed. -// The 4.0f here may be changed to match GetNextItemWidth() and/or BeginChild() (right now we have a mismatch which is harmless but undesirable) +// The 4.0f here may be changed to match CalcItemWidth() and/or BeginChild() (right now we have a mismatch which is harmless but undesirable) ImVec2 ImGui::CalcItemSize(ImVec2 size, float default_w, float default_h) { ImGuiWindow* window = GImGui->CurrentWindow; diff --git a/imgui_internal.h b/imgui_internal.h index d4508657..71628f59 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -1475,7 +1475,6 @@ namespace ImGui IMGUI_API bool IsClippedEx(const ImRect& bb, ImGuiID id, bool clip_even_when_logged); IMGUI_API bool FocusableItemRegister(ImGuiWindow* window, ImGuiID id); // Return true if focus is requested IMGUI_API void FocusableItemUnregister(ImGuiWindow* window); - IMGUI_API float GetNextItemWidth(); IMGUI_API ImVec2 CalcItemSize(ImVec2 size, float default_w, float default_h); IMGUI_API float CalcWrapWidthForPos(const ImVec2& pos, float wrap_pos_x); IMGUI_API void PushMultiItemsWidths(int components, float width_full); diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index 301634c9..c59558e4 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -320,7 +320,7 @@ void ImGui::LabelTextV(const char* label, const char* fmt, va_list args) ImGuiContext& g = *GImGui; const ImGuiStyle& style = g.Style; - const float w = GetNextItemWidth(); + const float w = CalcItemWidth(); const ImVec2 label_size = CalcTextSize(label, NULL, true); const ImRect value_bb(window->DC.CursorPos, window->DC.CursorPos + ImVec2(w, label_size.y + style.FramePadding.y*2)); @@ -1091,7 +1091,7 @@ void ImGui::ProgressBar(float fraction, const ImVec2& size_arg, const char* over const ImGuiStyle& style = g.Style; ImVec2 pos = window->DC.CursorPos; - ImVec2 size = CalcItemSize(size_arg, GetNextItemWidth(), g.FontSize + style.FramePadding.y*2.0f); + ImVec2 size = CalcItemSize(size_arg, CalcItemWidth(), g.FontSize + style.FramePadding.y*2.0f); ImRect bb(pos, pos + size); ItemSize(size, style.FramePadding.y); if (!ItemAdd(bb, 0)) @@ -1364,7 +1364,7 @@ bool ImGui::BeginCombo(const char* label, const char* preview_value, ImGuiComboF const float arrow_size = (flags & ImGuiComboFlags_NoArrowButton) ? 0.0f : GetFrameHeight(); const ImVec2 label_size = CalcTextSize(label, NULL, true); - const float expected_w = GetNextItemWidth(); + const float expected_w = CalcItemWidth(); const float w = (flags & ImGuiComboFlags_NoPreview) ? arrow_size : expected_w; const ImRect frame_bb(window->DC.CursorPos, window->DC.CursorPos + ImVec2(w, label_size.y + style.FramePadding.y*2.0f)); const ImRect total_bb(frame_bb.Min, frame_bb.Max + ImVec2(label_size.x > 0.0f ? style.ItemInnerSpacing.x + label_size.x : 0.0f, 0.0f)); @@ -1991,8 +1991,7 @@ bool ImGui::DragScalar(const char* label, ImGuiDataType data_type, void* v, floa ImGuiContext& g = *GImGui; const ImGuiStyle& style = g.Style; const ImGuiID id = window->GetID(label); - const float w = GetNextItemWidth(); - + const float w = CalcItemWidth(); const ImVec2 label_size = CalcTextSize(label, NULL, true); const ImRect frame_bb(window->DC.CursorPos, window->DC.CursorPos + ImVec2(w, label_size.y + style.FramePadding.y*2.0f)); const ImRect total_bb(frame_bb.Min, frame_bb.Max + ImVec2(label_size.x > 0.0f ? style.ItemInnerSpacing.x + label_size.x : 0.0f, 0.0f)); @@ -2064,7 +2063,7 @@ bool ImGui::DragScalarN(const char* label, ImGuiDataType data_type, void* v, int bool value_changed = false; BeginGroup(); PushID(label); - PushMultiItemsWidths(components, GetNextItemWidth()); + PushMultiItemsWidths(components, CalcItemWidth()); size_t type_size = GDataTypeInfo[data_type].Size; for (int i = 0; i < components; i++) { @@ -2111,7 +2110,7 @@ bool ImGui::DragFloatRange2(const char* label, float* v_current_min, float* v_cu ImGuiContext& g = *GImGui; PushID(label); BeginGroup(); - PushMultiItemsWidths(2, GetNextItemWidth()); + PushMultiItemsWidths(2, CalcItemWidth()); bool value_changed = DragFloat("##min", v_current_min, v_speed, (v_min >= v_max) ? -FLT_MAX : v_min, (v_min >= v_max) ? *v_current_max : ImMin(v_max, *v_current_max), format, power); PopItemWidth(); @@ -2156,7 +2155,7 @@ bool ImGui::DragIntRange2(const char* label, int* v_current_min, int* v_current_ ImGuiContext& g = *GImGui; PushID(label); BeginGroup(); - PushMultiItemsWidths(2, GetNextItemWidth()); + PushMultiItemsWidths(2, CalcItemWidth()); bool value_changed = DragInt("##min", v_current_min, v_speed, (v_min >= v_max) ? INT_MIN : v_min, (v_min >= v_max) ? *v_current_max : ImMin(v_max, *v_current_max), format); PopItemWidth(); @@ -2434,7 +2433,7 @@ bool ImGui::SliderScalar(const char* label, ImGuiDataType data_type, void* v, co ImGuiContext& g = *GImGui; const ImGuiStyle& style = g.Style; const ImGuiID id = window->GetID(label); - const float w = GetNextItemWidth(); + const float w = CalcItemWidth(); const ImVec2 label_size = CalcTextSize(label, NULL, true); const ImRect frame_bb(window->DC.CursorPos, window->DC.CursorPos + ImVec2(w, label_size.y + style.FramePadding.y*2.0f)); @@ -2512,7 +2511,7 @@ bool ImGui::SliderScalarN(const char* label, ImGuiDataType data_type, void* v, i bool value_changed = false; BeginGroup(); PushID(label); - PushMultiItemsWidths(components, GetNextItemWidth()); + PushMultiItemsWidths(components, CalcItemWidth()); size_t type_size = GDataTypeInfo[data_type].Size; for (int i = 0; i < components; i++) { @@ -2800,7 +2799,7 @@ bool ImGui::InputScalar(const char* label, ImGuiDataType data_type, void* data_p BeginGroup(); // The only purpose of the group here is to allow the caller to query item data e.g. IsItemActive() PushID(label); - SetNextItemWidth(ImMax(1.0f, GetNextItemWidth() - (button_size + style.ItemInnerSpacing.x) * 2)); + SetNextItemWidth(ImMax(1.0f, CalcItemWidth() - (button_size + style.ItemInnerSpacing.x) * 2)); if (InputText("", buf, IM_ARRAYSIZE(buf), flags)) // PushId(label) + "" gives us the expected ID from outside point of view value_changed = DataTypeApplyOpFromText(buf, g.InputTextState.InitialTextA.Data, data_type, data_ptr, format); @@ -2848,7 +2847,7 @@ bool ImGui::InputScalarN(const char* label, ImGuiDataType data_type, void* v, in bool value_changed = false; BeginGroup(); PushID(label); - PushMultiItemsWidths(components, GetNextItemWidth()); + PushMultiItemsWidths(components, CalcItemWidth()); size_t type_size = GDataTypeInfo[data_type].Size; for (int i = 0; i < components; i++) { @@ -3298,7 +3297,7 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ BeginGroup(); const ImGuiID id = window->GetID(label); const ImVec2 label_size = CalcTextSize(label, NULL, true); - ImVec2 size = CalcItemSize(size_arg, GetNextItemWidth(), (is_multiline ? GetTextLineHeight() * 8.0f : label_size.y) + style.FramePadding.y*2.0f); // Arbitrary default of 8 lines high for multi-line + ImVec2 size = CalcItemSize(size_arg, CalcItemWidth(), (is_multiline ? GetTextLineHeight() * 8.0f : label_size.y) + style.FramePadding.y*2.0f); // Arbitrary default of 8 lines high for multi-line const ImRect frame_bb(window->DC.CursorPos, window->DC.CursorPos + size); const ImRect total_bb(frame_bb.Min, frame_bb.Max + ImVec2(label_size.x > 0.0f ? (style.ItemInnerSpacing.x + label_size.x) : 0.0f, 0.0f)); @@ -4056,8 +4055,9 @@ bool ImGui::ColorEdit4(const char* label, float col[4], ImGuiColorEditFlags flag const ImGuiStyle& style = g.Style; const float square_sz = GetFrameHeight(); const float w_extra = (flags & ImGuiColorEditFlags_NoSmallPreview) ? 0.0f : (square_sz + style.ItemInnerSpacing.x); - const float w_items_all = GetNextItemWidth() - w_extra; + const float w_items_all = CalcItemWidth() - w_extra; const char* label_display_end = FindRenderedTextEnd(label); + g.NextItemData.ClearFlags(); BeginGroup(); PushID(label); @@ -4337,6 +4337,9 @@ bool ImGui::ColorPicker4(const char* label, float col[4], ImGuiColorEditFlags fl ImGuiStyle& style = g.Style; ImGuiIO& io = g.IO; + const float width = CalcItemWidth(); + g.NextItemData.ClearFlags(); + PushID(label); BeginGroup(); @@ -4363,7 +4366,7 @@ bool ImGui::ColorPicker4(const char* label, float col[4], ImGuiColorEditFlags fl ImVec2 picker_pos = window->DC.CursorPos; float square_sz = GetFrameHeight(); float bars_width = square_sz; // Arbitrary smallish width of Hue/Alpha picking bars - float sv_picker_size = ImMax(bars_width * 1, GetNextItemWidth() - (alpha_bar ? 2 : 1) * (bars_width + style.ItemInnerSpacing.x)); // Saturation/Value picking box + float sv_picker_size = ImMax(bars_width * 1, width - (alpha_bar ? 2 : 1) * (bars_width + style.ItemInnerSpacing.x)); // Saturation/Value picking box float bar0_pos_x = picker_pos.x + sv_picker_size + style.ItemInnerSpacing.x; float bar1_pos_x = bar0_pos_x + bars_width + style.ItemInnerSpacing.x; float bars_triangles_half_sz = (float)(int)(bars_width * 0.20f); @@ -5255,6 +5258,7 @@ float ImGui::GetTreeNodeToLabelSpacing() return g.FontSize + (g.Style.FramePadding.x * 2.0f); } +// Set next TreeNode/CollapsingHeader open state. void ImGui::SetNextItemOpen(bool is_open, ImGuiCond cond) { ImGuiContext& g = *GImGui; @@ -5452,20 +5456,22 @@ bool ImGui::Selectable(const char* label, bool* p_selected, ImGuiSelectableFlags // Tip: To have a list filling the entire window width, PushItemWidth(-1) and pass an non-visible label e.g. "##empty" bool ImGui::ListBoxHeader(const char* label, const ImVec2& size_arg) { + ImGuiContext& g = *GImGui; ImGuiWindow* window = GetCurrentWindow(); if (window->SkipItems) return false; - const ImGuiStyle& style = GetStyle(); + const ImGuiStyle& style = g.Style; const ImGuiID id = GetID(label); const ImVec2 label_size = CalcTextSize(label, NULL, true); // Size default to hold ~7 items. Fractional number of items helps seeing that we can scroll down/up without looking at scrollbar. - ImVec2 size = CalcItemSize(size_arg, GetNextItemWidth(), GetTextLineHeightWithSpacing() * 7.4f + style.ItemSpacing.y); + ImVec2 size = CalcItemSize(size_arg, CalcItemWidth(), GetTextLineHeightWithSpacing() * 7.4f + style.ItemSpacing.y); ImVec2 frame_size = ImVec2(size.x, ImMax(size.y, label_size.y)); ImRect frame_bb(window->DC.CursorPos, window->DC.CursorPos + frame_size); ImRect bb(frame_bb.Min, frame_bb.Max + ImVec2(label_size.x > 0.0f ? style.ItemInnerSpacing.x + label_size.x : 0.0f, 0.0f)); window->DC.LastItemRect = bb; // Forward storage for ListBoxFooter.. dodgy. + g.NextItemData.ClearFlags(); if (!IsRectVisible(bb.Min, bb.Max)) { @@ -5578,7 +5584,7 @@ void ImGui::PlotEx(ImGuiPlotType plot_type, const char* label, float (*values_ge const ImVec2 label_size = CalcTextSize(label, NULL, true); if (frame_size.x == 0.0f) - frame_size.x = GetNextItemWidth(); + frame_size.x = CalcItemWidth(); if (frame_size.y == 0.0f) frame_size.y = label_size.y + (style.FramePadding.y * 2); From 99a845053a815e7767b0d2c785a640b1cded871d Mon Sep 17 00:00:00 2001 From: omar Date: Mon, 13 May 2019 18:15:39 +0200 Subject: [PATCH 09/11] Internal: Renamed fields + minor tweaks (probably shallow break stack-layout pr, sorry!) --- docs/TODO.txt | 1 + imgui.cpp | 44 ++++++++++++++++++++++---------------------- imgui_internal.h | 26 +++++++++++++------------- imgui_widgets.cpp | 28 ++++++++++++++-------------- 4 files changed, 50 insertions(+), 49 deletions(-) diff --git a/docs/TODO.txt b/docs/TODO.txt index 97594ba4..79b170ad 100644 --- a/docs/TODO.txt +++ b/docs/TODO.txt @@ -67,6 +67,7 @@ It's mostly a bunch of personal notes, probably incomplete. Feel free to query i - widgets: selectable: generic BeginSelectable()/EndSelectable() mechanism. - widgets: selectable: a way to visualize partial/mixed selection (e.g. parent tree node has children with mixed selection) - widgets: checkbox with custom glyph inside frame. + - widgets: IsItemEdited() on InputScalar keeps returning true because InputText vs formatted output are mismatched. - input text: clean up the mess caused by converting UTF-8 <> wchar. the code is rather inefficient right now and super fragile. - input text: reorganize event handling, allow CharFilter to modify buffers, allow multiple events? (#541) diff --git a/imgui.cpp b/imgui.cpp index e5b2da50..7cf0ba6b 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -2679,8 +2679,8 @@ void ImGui::SetActiveID(ImGuiID id, ImGuiWindow* window) if (g.ActiveIdIsJustActivated) { g.ActiveIdTimer = 0.0f; - g.ActiveIdHasBeenPressed = false; - g.ActiveIdHasBeenEdited = false; + g.ActiveIdHasBeenPressedBefore = false; + g.ActiveIdHasBeenEditedBefore = false; if (id != 0) { g.LastActiveId = id; @@ -2759,7 +2759,7 @@ void ImGui::MarkItemEdited(ImGuiID id) IM_ASSERT(g.ActiveId == id || g.ActiveId == 0 || g.DragDropActive); IM_UNUSED(id); // Avoid unused variable warnings when asserts are compiled out. //IM_ASSERT(g.CurrentWindow->DC.LastItemId == id); - g.ActiveIdHasBeenEdited = true; + g.ActiveIdHasBeenEditedBefore = true; g.CurrentWindow->DC.LastItemStatusFlags |= ImGuiItemStatusFlags_Edited; } @@ -2792,10 +2792,11 @@ void ImGui::ItemSize(const ImVec2& size, float text_offset_y) return; // Always align ourselves on pixel boundaries - const float line_height = ImMax(window->DC.CurrentLineSize.y, size.y); - const float text_base_offset = ImMax(window->DC.CurrentLineTextBaseOffset, text_offset_y); + const float line_height = ImMax(window->DC.CurrLineSize.y, size.y); + const float text_base_offset = ImMax(window->DC.CurrLineTextBaseOffset, text_offset_y); //if (g.IO.KeyAlt) window->DrawList->AddRect(window->DC.CursorPos, window->DC.CursorPos + ImVec2(size.x, line_height), IM_COL32(255,0,0,200)); // [DEBUG] - window->DC.CursorPosPrevLine = ImVec2(window->DC.CursorPos.x + size.x, window->DC.CursorPos.y); + window->DC.CursorPosPrevLine.x = window->DC.CursorPos.x + size.x; + window->DC.CursorPosPrevLine.y = window->DC.CursorPos.y; window->DC.CursorPos.x = (float)(int)(window->Pos.x + window->DC.Indent.x + window->DC.ColumnsOffset.x); window->DC.CursorPos.y = (float)(int)(window->DC.CursorPos.y + line_height + g.Style.ItemSpacing.y); window->DC.CursorMaxPos.x = ImMax(window->DC.CursorMaxPos.x, window->DC.CursorPosPrevLine.x); @@ -2804,7 +2805,7 @@ void ImGui::ItemSize(const ImVec2& size, float text_offset_y) window->DC.PrevLineSize.y = line_height; window->DC.PrevLineTextBaseOffset = text_base_offset; - window->DC.CurrentLineSize.y = window->DC.CurrentLineTextBaseOffset = 0.0f; + window->DC.CurrLineSize.y = window->DC.CurrLineTextBaseOffset = 0.0f; // Horizontal layout mode if (window->DC.LayoutType == ImGuiLayoutType_Horizontal) @@ -3529,7 +3530,7 @@ void ImGui::NewFrame() g.LastActiveIdTimer += g.IO.DeltaTime; g.ActiveIdPreviousFrame = g.ActiveId; g.ActiveIdPreviousFrameWindow = g.ActiveIdWindow; - g.ActiveIdPreviousFrameHasBeenEdited = g.ActiveIdHasBeenEdited; + g.ActiveIdPreviousFrameHasBeenEditedBefore = g.ActiveIdHasBeenEditedBefore; g.ActiveIdIsAlive = 0; g.ActiveIdPreviousFrameIsAlive = false; g.ActiveIdIsJustActivated = false; @@ -4341,7 +4342,7 @@ bool ImGui::IsItemDeactivated() bool ImGui::IsItemDeactivatedAfterEdit() { ImGuiContext& g = *GImGui; - return IsItemDeactivated() && (g.ActiveIdPreviousFrameHasBeenEdited || (g.ActiveId == 0 && g.ActiveIdHasBeenEdited)); + return IsItemDeactivated() && (g.ActiveIdPreviousFrameHasBeenEditedBefore || (g.ActiveId == 0 && g.ActiveIdHasBeenEditedBefore)); } bool ImGui::IsItemFocused() @@ -5530,8 +5531,8 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) window->DC.CursorPos = window->DC.CursorStartPos; window->DC.CursorPosPrevLine = window->DC.CursorPos; window->DC.CursorMaxPos = window->DC.CursorStartPos; - window->DC.CurrentLineSize = window->DC.PrevLineSize = ImVec2(0.0f, 0.0f); - window->DC.CurrentLineTextBaseOffset = window->DC.PrevLineTextBaseOffset = 0.0f; + window->DC.CurrLineSize = window->DC.PrevLineSize = ImVec2(0.0f, 0.0f); + window->DC.CurrLineTextBaseOffset = window->DC.PrevLineTextBaseOffset = 0.0f; window->DC.NavHideHighlightOneFrame = false; window->DC.NavHasScroll = (GetWindowScrollMaxY(window) > 0.0f); window->DC.NavLayerActiveMask = window->DC.NavLayerActiveMaskNext; @@ -6776,8 +6777,8 @@ void ImGui::BeginGroup() group_data.BackupCursorMaxPos = window->DC.CursorMaxPos; group_data.BackupIndent = window->DC.Indent; group_data.BackupGroupOffset = window->DC.GroupOffset; - group_data.BackupCurrentLineSize = window->DC.CurrentLineSize; - group_data.BackupCurrentLineTextBaseOffset = window->DC.CurrentLineTextBaseOffset; + group_data.BackupCurrLineSize = window->DC.CurrLineSize; + group_data.BackupCurrLineTextBaseOffset = window->DC.CurrLineTextBaseOffset; group_data.BackupActiveIdIsAlive = g.ActiveIdIsAlive; group_data.BackupActiveIdPreviousFrameIsAlive = g.ActiveIdPreviousFrameIsAlive; group_data.EmitItem = true; @@ -6785,7 +6786,7 @@ void ImGui::BeginGroup() window->DC.GroupOffset.x = window->DC.CursorPos.x - window->Pos.x - window->DC.ColumnsOffset.x; window->DC.Indent = window->DC.GroupOffset; window->DC.CursorMaxPos = window->DC.CursorPos; - window->DC.CurrentLineSize = ImVec2(0.0f, 0.0f); + window->DC.CurrLineSize = ImVec2(0.0f, 0.0f); if (g.LogEnabled) g.LogLinePosY = -FLT_MAX; // To enforce Log carriage return } @@ -6804,8 +6805,8 @@ void ImGui::EndGroup() window->DC.CursorMaxPos = ImMax(group_data.BackupCursorMaxPos, window->DC.CursorMaxPos); window->DC.Indent = group_data.BackupIndent; window->DC.GroupOffset = group_data.BackupGroupOffset; - window->DC.CurrentLineSize = group_data.BackupCurrentLineSize; - window->DC.CurrentLineTextBaseOffset = group_data.BackupCurrentLineTextBaseOffset; + window->DC.CurrLineSize = group_data.BackupCurrLineSize; + window->DC.CurrLineTextBaseOffset = group_data.BackupCurrLineTextBaseOffset; if (g.LogEnabled) g.LogLinePosY = -FLT_MAX; // To enforce Log carriage return @@ -6815,7 +6816,7 @@ void ImGui::EndGroup() return; } - window->DC.CurrentLineTextBaseOffset = ImMax(window->DC.PrevLineTextBaseOffset, group_data.BackupCurrentLineTextBaseOffset); // FIXME: Incorrect, we should grab the base offset from the *first line* of the group but it is hard to obtain now. + window->DC.CurrLineTextBaseOffset = ImMax(window->DC.PrevLineTextBaseOffset, group_data.BackupCurrLineTextBaseOffset); // FIXME: Incorrect, we should grab the base offset from the *first line* of the group but it is hard to obtain now. ItemSize(group_bb.GetSize(), 0.0f); ItemAdd(group_bb, 0); @@ -6832,7 +6833,6 @@ void ImGui::EndGroup() window->DC.LastItemRect = group_bb; window->DC.GroupStack.pop_back(); - //window->DrawList->AddRect(group_bb.Min, group_bb.Max, IM_COL32(255,0,255,255)); // [Debug] } @@ -6860,8 +6860,8 @@ void ImGui::SameLine(float offset_from_start_x, float spacing_w) window->DC.CursorPos.x = window->DC.CursorPosPrevLine.x + spacing_w; window->DC.CursorPos.y = window->DC.CursorPosPrevLine.y; } - window->DC.CurrentLineSize = window->DC.PrevLineSize; - window->DC.CurrentLineTextBaseOffset = window->DC.PrevLineTextBaseOffset; + window->DC.CurrLineSize = window->DC.PrevLineSize; + window->DC.CurrLineTextBaseOffset = window->DC.PrevLineTextBaseOffset; } void ImGui::Indent(float indent_w) @@ -8435,8 +8435,8 @@ void ImGui::NextColumn() } window->DC.CursorPos.x = (float)(int)(window->Pos.x + window->DC.Indent.x + window->DC.ColumnsOffset.x); window->DC.CursorPos.y = columns->LineMinY; - window->DC.CurrentLineSize = ImVec2(0.0f, 0.0f); - window->DC.CurrentLineTextBaseOffset = 0.0f; + window->DC.CurrLineSize = ImVec2(0.0f, 0.0f); + window->DC.CurrLineTextBaseOffset = 0.0f; PushColumnClipRect(columns->Current); PushItemWidth(GetColumnWidth() * 0.65f); // FIXME-COLUMNS: Move on columns setup diff --git a/imgui_internal.h b/imgui_internal.h index 71628f59..048ee49d 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -574,8 +574,8 @@ struct ImGuiGroupData ImVec2 BackupCursorMaxPos; ImVec1 BackupIndent; ImVec1 BackupGroupOffset; - ImVec2 BackupCurrentLineSize; - float BackupCurrentLineTextBaseOffset; + ImVec2 BackupCurrLineSize; + float BackupCurrLineTextBaseOffset; ImGuiID BackupActiveIdIsAlive; bool BackupActiveIdPreviousFrameIsAlive; bool EmitItem; @@ -774,7 +774,7 @@ struct ImGuiNextWindowData ImGuiSizeCallback SizeCallback; void* SizeCallbackUserData; float BgAlphaVal; - ImVec2 MenuBarOffsetMinVal; // This is not exposed publicly, so we don't clear it. + ImVec2 MenuBarOffsetMinVal; // *Always on* This is not exposed publicly, so we don't clear it. ImGuiNextWindowData() { memset(this, 0, sizeof(*this)); } inline void ClearFlags() { Flags = ImGuiNextWindowDataFlags_None; } @@ -861,8 +861,8 @@ struct ImGuiContext float ActiveIdTimer; bool ActiveIdIsJustActivated; // Set at the time of activation for one frame bool ActiveIdAllowOverlap; // Active widget allows another widget to steal active id (generally for overlapping widgets, but not always) - bool ActiveIdHasBeenPressed; // Track whether the active id led to a press (this is to allow changing between PressOnClick and PressOnRelease without pressing twice). Used by range_select branch. - bool ActiveIdHasBeenEdited; // Was the value associated to the widget Edited over the course of the Active state. + bool ActiveIdHasBeenPressedBefore; // Track whether the active id led to a press (this is to allow changing between PressOnClick and PressOnRelease without pressing twice). Used by range_select branch. + bool ActiveIdHasBeenEditedBefore; // Was the value associated to the widget Edited over the course of the Active state. int ActiveIdAllowNavDirFlags; // Active widget allows using directional navigation (e.g. can activate a button and move away from it) int ActiveIdBlockNavInputFlags; ImVec2 ActiveIdClickOffset; // Clicked offset from upper-left corner, if applicable (currently only set by ButtonBehavior) @@ -870,7 +870,7 @@ struct ImGuiContext ImGuiInputSource ActiveIdSource; // Activating with mouse or nav (gamepad/keyboard) ImGuiID ActiveIdPreviousFrame; bool ActiveIdPreviousFrameIsAlive; - bool ActiveIdPreviousFrameHasBeenEdited; + bool ActiveIdPreviousFrameHasBeenEditedBefore; ImGuiWindow* ActiveIdPreviousFrameWindow; ImGuiID LastActiveId; // Store the last non-zero ActiveId, useful for animation. @@ -1044,8 +1044,8 @@ struct ImGuiContext ActiveIdTimer = 0.0f; ActiveIdIsJustActivated = false; ActiveIdAllowOverlap = false; - ActiveIdHasBeenPressed = false; - ActiveIdHasBeenEdited = false; + ActiveIdHasBeenPressedBefore = false; + ActiveIdHasBeenEditedBefore = false; ActiveIdAllowNavDirFlags = 0x00; ActiveIdBlockNavInputFlags = 0x00; ActiveIdClickOffset = ImVec2(-1,-1); @@ -1054,7 +1054,7 @@ struct ImGuiContext ActiveIdPreviousFrame = 0; ActiveIdPreviousFrameIsAlive = false; - ActiveIdPreviousFrameHasBeenEdited = false; + ActiveIdPreviousFrameHasBeenEditedBefore = false; ActiveIdPreviousFrameWindow = NULL; LastActiveId = 0; @@ -1154,9 +1154,9 @@ struct IMGUI_API ImGuiWindowTempData ImVec2 CursorPosPrevLine; ImVec2 CursorStartPos; // Initial position in client area with padding ImVec2 CursorMaxPos; // Used to implicitly calculate the size of our contents, always growing during the frame. Turned into window->SizeContents at the beginning of next frame - ImVec2 CurrentLineSize; - float CurrentLineTextBaseOffset; + ImVec2 CurrLineSize; ImVec2 PrevLineSize; + float CurrLineTextBaseOffset; float PrevLineTextBaseOffset; int TreeDepth; ImU32 TreeStoreMayJumpToParentOnPop; // Store a copy of !g.NavIdIsAlive for TreeDepth 0..31.. Could be turned into a ImU64 if necessary. @@ -1197,8 +1197,8 @@ struct IMGUI_API ImGuiWindowTempData ImGuiWindowTempData() { CursorPos = CursorPosPrevLine = CursorStartPos = CursorMaxPos = ImVec2(0.0f, 0.0f); - CurrentLineSize = PrevLineSize = ImVec2(0.0f, 0.0f); - CurrentLineTextBaseOffset = PrevLineTextBaseOffset = 0.0f; + CurrLineSize = PrevLineSize = ImVec2(0.0f, 0.0f); + CurrLineTextBaseOffset = PrevLineTextBaseOffset = 0.0f; TreeDepth = 0; TreeStoreMayJumpToParentOnPop = 0x00; LastItemId = 0; diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index c59558e4..117a047d 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -139,7 +139,7 @@ void ImGui::TextEx(const char* text, const char* text_end, ImGuiTextFlags flags) if (text_end == NULL) text_end = text + strlen(text); // FIXME-OPT - const ImVec2 text_pos(window->DC.CursorPos.x, window->DC.CursorPos.y + window->DC.CurrentLineTextBaseOffset); + const ImVec2 text_pos(window->DC.CursorPos.x, window->DC.CursorPos.y + window->DC.CurrLineTextBaseOffset); const float wrap_pos_x = window->DC.TextWrapPos; const bool wrap_enabled = (wrap_pos_x >= 0.0f); if (text_end - text > 2000 && !wrap_enabled) @@ -358,8 +358,8 @@ void ImGui::BulletTextV(const char* fmt, va_list args) const char* text_begin = g.TempBuffer; const char* text_end = text_begin + ImFormatStringV(g.TempBuffer, IM_ARRAYSIZE(g.TempBuffer), fmt, args); const ImVec2 label_size = CalcTextSize(text_begin, text_end, false); - const float text_base_offset_y = ImMax(0.0f, window->DC.CurrentLineTextBaseOffset); // Latch before ItemSize changes it - const float line_height = ImMax(ImMin(window->DC.CurrentLineSize.y, g.FontSize + g.Style.FramePadding.y*2), g.FontSize); + const float text_base_offset_y = ImMax(0.0f, window->DC.CurrLineTextBaseOffset); // Latch before ItemSize changes it + const float line_height = ImMax(ImMin(window->DC.CurrLineSize.y, g.FontSize + g.Style.FramePadding.y*2), g.FontSize); const ImRect bb(window->DC.CursorPos, window->DC.CursorPos + ImVec2(g.FontSize + (label_size.x > 0.0f ? (label_size.x + style.FramePadding.x*2) : 0.0f), ImMax(line_height, label_size.y))); // Empty text doesn't add padding ItemSize(bb); if (!ItemAdd(bb, 0)) @@ -563,7 +563,7 @@ bool ImGui::ButtonBehavior(const ImRect& bb, ImGuiID id, bool* out_hovered, bool if (g.ActiveId == id) { if (pressed) - g.ActiveIdHasBeenPressed = true; + g.ActiveIdHasBeenPressedBefore = true; if (g.ActiveIdSource == ImGuiInputSource_Mouse) { if (g.ActiveIdIsJustActivated) @@ -611,8 +611,8 @@ bool ImGui::ButtonEx(const char* label, const ImVec2& size_arg, ImGuiButtonFlags const ImVec2 label_size = CalcTextSize(label, NULL, true); ImVec2 pos = window->DC.CursorPos; - if ((flags & ImGuiButtonFlags_AlignTextBaseLine) && style.FramePadding.y < window->DC.CurrentLineTextBaseOffset) // Try to vertically align buttons that are smaller/have no padding so that text baseline matches (bit hacky, since it shouldn't be a flag) - pos.y += window->DC.CurrentLineTextBaseOffset - style.FramePadding.y; + if ((flags & ImGuiButtonFlags_AlignTextBaseLine) && style.FramePadding.y < window->DC.CurrLineTextBaseOffset) // Try to vertically align buttons that are smaller/have no padding so that text baseline matches (bit hacky, since it shouldn't be a flag) + pos.y += window->DC.CurrLineTextBaseOffset - style.FramePadding.y; ImVec2 size = CalcItemSize(size_arg, label_size.x + style.FramePadding.x * 2.0f, label_size.y + style.FramePadding.y * 2.0f); const ImRect bb(pos, pos + size); @@ -1125,7 +1125,7 @@ void ImGui::Bullet() ImGuiContext& g = *GImGui; const ImGuiStyle& style = g.Style; - const float line_height = ImMax(ImMin(window->DC.CurrentLineSize.y, g.FontSize + g.Style.FramePadding.y*2), g.FontSize); + const float line_height = ImMax(ImMin(window->DC.CurrLineSize.y, g.FontSize + g.Style.FramePadding.y*2), g.FontSize); const ImRect bb(window->DC.CursorPos, window->DC.CursorPos + ImVec2(g.FontSize, line_height)); ItemSize(bb); if (!ItemAdd(bb, 0)) @@ -1179,7 +1179,7 @@ void ImGui::NewLine() ImGuiContext& g = *GImGui; const ImGuiLayoutType backup_layout_type = window->DC.LayoutType; window->DC.LayoutType = ImGuiLayoutType_Vertical; - if (window->DC.CurrentLineSize.y > 0.0f) // In the event that we are on a line with items that is smaller that FontSize high, we will preserve its height. + if (window->DC.CurrLineSize.y > 0.0f) // In the event that we are on a line with items that is smaller that FontSize high, we will preserve its height. ItemSize(ImVec2(0,0)); else ItemSize(ImVec2(0.0f, g.FontSize)); @@ -1193,8 +1193,8 @@ void ImGui::AlignTextToFramePadding() return; ImGuiContext& g = *GImGui; - window->DC.CurrentLineSize.y = ImMax(window->DC.CurrentLineSize.y, g.FontSize + g.Style.FramePadding.y * 2); - window->DC.CurrentLineTextBaseOffset = ImMax(window->DC.CurrentLineTextBaseOffset, g.Style.FramePadding.y); + window->DC.CurrLineSize.y = ImMax(window->DC.CurrLineSize.y, g.FontSize + g.Style.FramePadding.y * 2); + window->DC.CurrLineTextBaseOffset = ImMax(window->DC.CurrLineTextBaseOffset, g.Style.FramePadding.y); } // Horizontal/vertical separating line @@ -1213,7 +1213,7 @@ void ImGui::SeparatorEx(ImGuiSeparatorFlags flags) { // Vertical separator, for menu bars (use current line height). Not exposed because it is misleading and it doesn't have an effect on regular layout. float y1 = window->DC.CursorPos.y; - float y2 = window->DC.CursorPos.y + window->DC.CurrentLineSize.y; + float y2 = window->DC.CursorPos.y + window->DC.CurrLineSize.y; const ImRect bb(ImVec2(window->DC.CursorPos.x, y1), ImVec2(window->DC.CursorPos.x + thickness_draw, y2)); ItemSize(ImVec2(thickness_layout, 0.0f)); if (!ItemAdd(bb, 0)) @@ -5060,8 +5060,8 @@ bool ImGui::TreeNodeBehavior(ImGuiID id, ImGuiTreeNodeFlags flags, const char* l const ImVec2 label_size = CalcTextSize(label, label_end, false); // We vertically grow up to current line height up the typical widget height. - const float text_base_offset_y = ImMax(padding.y, window->DC.CurrentLineTextBaseOffset); // Latch before ItemSize changes it - const float frame_height = ImMax(ImMin(window->DC.CurrentLineSize.y, g.FontSize + style.FramePadding.y*2), label_size.y + padding.y*2); + const float text_base_offset_y = ImMax(padding.y, window->DC.CurrLineTextBaseOffset); // Latch before ItemSize changes it + const float frame_height = ImMax(ImMin(window->DC.CurrLineSize.y, g.FontSize + style.FramePadding.y*2), label_size.y + padding.y*2); ImRect frame_bb = ImRect(window->DC.CursorPos, ImVec2(GetWorkRectMax().x, window->DC.CursorPos.y + frame_height)); if (display_frame) { @@ -5330,7 +5330,7 @@ bool ImGui::Selectable(const char* label, bool selected, ImGuiSelectableFlags fl ImVec2 label_size = CalcTextSize(label, NULL, true); ImVec2 size(size_arg.x != 0.0f ? size_arg.x : label_size.x, size_arg.y != 0.0f ? size_arg.y : label_size.y); ImVec2 pos = window->DC.CursorPos; - pos.y += window->DC.CurrentLineTextBaseOffset; + pos.y += window->DC.CurrLineTextBaseOffset; ImRect bb_inner(pos, pos + size); ItemSize(size); From d3a387cc1865b7d147a73f728b7823fb965a00f9 Mon Sep 17 00:00:00 2001 From: omar Date: Mon, 13 May 2019 19:04:57 +0200 Subject: [PATCH 10/11] Fixed InputFloatX, SliderFloatX, DragFloatX functions erroneously reporting IsItemEdited() multiple times when the text input doesn't match the formatted output value (e.g. input "1" shows "1.000"). It wasn't much of a problem because we typically use the return value instead of IsItemEdited() here. (#1875, #2034) --- docs/CHANGELOG.txt | 3 +++ docs/TODO.txt | 1 - imgui.h | 3 ++- imgui_widgets.cpp | 14 +++++++++++--- 4 files changed, 16 insertions(+), 5 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 641e11c1..31c8ed8d 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -41,6 +41,9 @@ Other Changes: - Columns: Fixed Selectable with SpanAllColumns flag from creating an extraneous draw command. (#125) - Separator: Revert 1.70 "Declare its thickness (1.0f) to the layout" change. It's not incorrect but it breaks existing some layout patterns. Will return back to it when we expose Separator flags. +- Fixed InputFloatX, SliderFloatX, DragFloatX functions erroneously reporting IsItemEdited() multiple + times when the text input doesn't match the formatted output value (e.g. input "1" shows "1.000"). + It wasn't much of a problem because we typically use the return value instead of IsItemEdited() here. - Scrollbar: Very minor bounding box adjustment to cope with various border size. - ImFontAtlas: FreeType: Added RasterizerFlags::Monochrome flag to disable font anti-aliasing. (#2545) Combine with RasterizerFlags::MonoHinting for best results. diff --git a/docs/TODO.txt b/docs/TODO.txt index 79b170ad..97594ba4 100644 --- a/docs/TODO.txt +++ b/docs/TODO.txt @@ -67,7 +67,6 @@ It's mostly a bunch of personal notes, probably incomplete. Feel free to query i - widgets: selectable: generic BeginSelectable()/EndSelectable() mechanism. - widgets: selectable: a way to visualize partial/mixed selection (e.g. parent tree node has children with mixed selection) - widgets: checkbox with custom glyph inside frame. - - widgets: IsItemEdited() on InputScalar keeps returning true because InputText vs formatted output are mismatched. - input text: clean up the mess caused by converting UTF-8 <> wchar. the code is rather inefficient right now and super fragile. - input text: reorganize event handling, allow CharFilter to modify buffers, allow multiple events? (#541) diff --git a/imgui.h b/imgui.h index 0bcea46b..75a2ae7f 100644 --- a/imgui.h +++ b/imgui.h @@ -763,7 +763,8 @@ enum ImGuiInputTextFlags_ ImGuiInputTextFlags_CharsScientific = 1 << 17, // Allow 0123456789.+-*/eE (Scientific notation input) ImGuiInputTextFlags_CallbackResize = 1 << 18, // Callback on buffer capacity changes request (beyond 'buf_size' parameter value), allowing the string to grow. Notify when the string wants to be resized (for string types which hold a cache of their Size). You will be provided a new BufSize in the callback and NEED to honor it. (see misc/cpp/imgui_stdlib.h for an example of using this) // [Internal] - ImGuiInputTextFlags_Multiline = 1 << 20 // For internal use by InputTextMultiline() + ImGuiInputTextFlags_Multiline = 1 << 20, // For internal use by InputTextMultiline() + ImGuiInputTextFlags_NoMarkEdited = 1 << 21 // For internal use by functions using InputText() before reformatting data }; // Flags for ImGui::TreeNodeEx(), ImGui::CollapsingHeader*() diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index 117a047d..bcd5d3b9 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -2760,7 +2760,8 @@ bool ImGui::TempInputTextScalar(const ImRect& bb, ImGuiID id, const char* label, ImStrTrimBlanks(data_buf); g.CurrentWindow->DC.CursorPos = bb.Min; - ImGuiInputTextFlags flags = ImGuiInputTextFlags_AutoSelectAll | ((data_type == ImGuiDataType_Float || data_type == ImGuiDataType_Double) ? ImGuiInputTextFlags_CharsScientific : ImGuiInputTextFlags_CharsDecimal); + ImGuiInputTextFlags flags = ImGuiInputTextFlags_AutoSelectAll | ImGuiInputTextFlags_NoMarkEdited; + flags |= ((data_type == ImGuiDataType_Float || data_type == ImGuiDataType_Double) ? ImGuiInputTextFlags_CharsScientific : ImGuiInputTextFlags_CharsDecimal); bool value_changed = InputTextEx(label, NULL, data_buf, IM_ARRAYSIZE(data_buf), bb.GetSize(), flags); if (init) { @@ -2769,7 +2770,11 @@ bool ImGui::TempInputTextScalar(const ImRect& bb, ImGuiID id, const char* label, g.TempInputTextId = g.ActiveId; } if (value_changed) - return DataTypeApplyOpFromText(data_buf, g.InputTextState.InitialTextA.Data, data_type, data_ptr, NULL); + { + value_changed = DataTypeApplyOpFromText(data_buf, g.InputTextState.InitialTextA.Data, data_type, data_ptr, NULL); + if (value_changed) + MarkItemEdited(id); + } return false; } @@ -2792,6 +2797,7 @@ bool ImGui::InputScalar(const char* label, ImGuiDataType data_type, void* data_p if ((flags & (ImGuiInputTextFlags_CharsHexadecimal | ImGuiInputTextFlags_CharsScientific)) == 0) flags |= ImGuiInputTextFlags_CharsDecimal; flags |= ImGuiInputTextFlags_AutoSelectAll; + flags |= ImGuiInputTextFlags_NoMarkEdited; // We call MarkItemEdited() ourselve by comparing the actual data rather than the string. if (step != NULL) { @@ -2833,6 +2839,8 @@ bool ImGui::InputScalar(const char* label, ImGuiDataType data_type, void* data_p if (InputText(label, buf, IM_ARRAYSIZE(buf), flags)) value_changed = DataTypeApplyOpFromText(buf, g.InputTextState.InitialTextA.Data, data_type, data_ptr, format); } + if (value_changed) + MarkItemEdited(window->DC.LastItemId); return value_changed; } @@ -4012,7 +4020,7 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ if (label_size.x > 0) RenderText(ImVec2(frame_bb.Max.x + style.ItemInnerSpacing.x, frame_bb.Min.y + style.FramePadding.y), label); - if (value_changed) + if (value_changed && !(flags & ImGuiInputTextFlags_NoMarkEdited)) MarkItemEdited(id); IMGUI_TEST_ENGINE_ITEM_INFO(id, label, window->DC.ItemFlags); From fc3c3de551cbc5c13443f6e25977078006275713 Mon Sep 17 00:00:00 2001 From: omar Date: Mon, 13 May 2019 19:05:41 +0200 Subject: [PATCH 11/11] Fixed uses of IsItemDeactivated(), IsItemDeactivatedAfterEdit() on multi-components widgets and after EndGroup(). (#2550, #1875) --- docs/CHANGELOG.txt | 2 ++ imgui.cpp | 14 ++++++++++++++ imgui_internal.h | 6 +++++- 3 files changed, 21 insertions(+), 1 deletion(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 31c8ed8d..8a2d53c2 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -44,6 +44,8 @@ Other Changes: - Fixed InputFloatX, SliderFloatX, DragFloatX functions erroneously reporting IsItemEdited() multiple times when the text input doesn't match the formatted output value (e.g. input "1" shows "1.000"). It wasn't much of a problem because we typically use the return value instead of IsItemEdited() here. +- Fixed uses of IsItemDeactivated(), IsItemDeactivatedAfterEdit() on multi-components widgets and + after EndGroup(). (#2550, #1875) - Scrollbar: Very minor bounding box adjustment to cope with various border size. - ImFontAtlas: FreeType: Added RasterizerFlags::Monochrome flag to disable font anti-aliasing. (#2545) Combine with RasterizerFlags::MonoHinting for best results. diff --git a/imgui.cpp b/imgui.cpp index 7cf0ba6b..20840931 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -2692,6 +2692,7 @@ void ImGui::SetActiveID(ImGuiID id, ImGuiWindow* window) g.ActiveIdBlockNavInputFlags = 0; g.ActiveIdAllowOverlap = false; g.ActiveIdWindow = window; + g.ActiveIdHasBeenEditedThisFrame = false; if (id) { g.ActiveIdIsAlive = id; @@ -2759,6 +2760,7 @@ void ImGui::MarkItemEdited(ImGuiID id) IM_ASSERT(g.ActiveId == id || g.ActiveId == 0 || g.DragDropActive); IM_UNUSED(id); // Avoid unused variable warnings when asserts are compiled out. //IM_ASSERT(g.CurrentWindow->DC.LastItemId == id); + g.ActiveIdHasBeenEditedThisFrame = true; g.ActiveIdHasBeenEditedBefore = true; g.CurrentWindow->DC.LastItemStatusFlags |= ImGuiItemStatusFlags_Edited; } @@ -3532,6 +3534,7 @@ void ImGui::NewFrame() g.ActiveIdPreviousFrameWindow = g.ActiveIdWindow; g.ActiveIdPreviousFrameHasBeenEditedBefore = g.ActiveIdHasBeenEditedBefore; g.ActiveIdIsAlive = 0; + g.ActiveIdHasBeenEditedThisFrame = false; g.ActiveIdPreviousFrameIsAlive = false; g.ActiveIdIsJustActivated = false; if (g.TempInputTextId != 0 && g.ActiveId != g.TempInputTextId) @@ -4336,6 +4339,8 @@ bool ImGui::IsItemDeactivated() { ImGuiContext& g = *GImGui; ImGuiWindow* window = g.CurrentWindow; + if (window->DC.LastItemStatusFlags & ImGuiItemStatusFlags_HasDeactivated) + return (window->DC.LastItemStatusFlags & ImGuiItemStatusFlags_Deactivated) != 0; return (g.ActiveIdPreviousFrame == window->DC.LastItemId && g.ActiveIdPreviousFrame != 0 && g.ActiveId != window->DC.LastItemId); } @@ -6832,6 +6837,15 @@ void ImGui::EndGroup() window->DC.LastItemId = g.ActiveIdPreviousFrame; window->DC.LastItemRect = group_bb; + // Forward Edited flag + if (group_contains_curr_active_id && g.ActiveIdHasBeenEditedThisFrame) + window->DC.LastItemStatusFlags |= ImGuiItemStatusFlags_Edited; + + // Forward Deactivated flag + window->DC.LastItemStatusFlags |= ImGuiItemStatusFlags_HasDeactivated; + if (group_contains_prev_active_id && g.ActiveId != g.ActiveIdPreviousFrame) + window->DC.LastItemStatusFlags |= ImGuiItemStatusFlags_Deactivated; + window->DC.GroupStack.pop_back(); //window->DrawList->AddRect(group_bb.Min, group_bb.Max, IM_COL32(255,0,255,255)); // [Debug] } diff --git a/imgui_internal.h b/imgui_internal.h index 048ee49d..a44e5667 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -381,7 +381,9 @@ enum ImGuiItemStatusFlags_ ImGuiItemStatusFlags_HoveredRect = 1 << 0, ImGuiItemStatusFlags_HasDisplayRect = 1 << 1, ImGuiItemStatusFlags_Edited = 1 << 2, // Value exposed by item was edited in the current frame (should match the bool return value of most widgets) - ImGuiItemStatusFlags_ToggledSelection = 1 << 3 // Set when Selectable(), TreeNode() reports toggling a selection. We can't report "Selected" because reporting the change allows us to handle clipping with less issues. + ImGuiItemStatusFlags_ToggledSelection = 1 << 3, // Set when Selectable(), TreeNode() reports toggling a selection. We can't report "Selected" because reporting the change allows us to handle clipping with less issues. + ImGuiItemStatusFlags_HasDeactivated = 1 << 4, // Set if the widget/group is able to provide data for the ImGuiItemStatusFlags_Deactivated flag. + ImGuiItemStatusFlags_Deactivated = 1 << 5 // Only valid if ImGuiItemStatusFlags_HasDeactivated is set. #ifdef IMGUI_ENABLE_TEST_ENGINE , // [imgui-test only] @@ -863,6 +865,7 @@ struct ImGuiContext bool ActiveIdAllowOverlap; // Active widget allows another widget to steal active id (generally for overlapping widgets, but not always) bool ActiveIdHasBeenPressedBefore; // Track whether the active id led to a press (this is to allow changing between PressOnClick and PressOnRelease without pressing twice). Used by range_select branch. bool ActiveIdHasBeenEditedBefore; // Was the value associated to the widget Edited over the course of the Active state. + bool ActiveIdHasBeenEditedThisFrame; int ActiveIdAllowNavDirFlags; // Active widget allows using directional navigation (e.g. can activate a button and move away from it) int ActiveIdBlockNavInputFlags; ImVec2 ActiveIdClickOffset; // Clicked offset from upper-left corner, if applicable (currently only set by ButtonBehavior) @@ -1046,6 +1049,7 @@ struct ImGuiContext ActiveIdAllowOverlap = false; ActiveIdHasBeenPressedBefore = false; ActiveIdHasBeenEditedBefore = false; + ActiveIdHasBeenEditedThisFrame = false; ActiveIdAllowNavDirFlags = 0x00; ActiveIdBlockNavInputFlags = 0x00; ActiveIdClickOffset = ImVec2(-1,-1);