From 3777fbbd81514695fb540e3b0c12330d1525b0bd Mon Sep 17 00:00:00 2001 From: ocornut Date: Tue, 3 Nov 2020 14:28:41 +0100 Subject: [PATCH 01/10] Renamed io.ConfigWindowsMemoryCompactTimer to io.ConfigMemoryCompactTimer as the feature will apply to other data structures. --- docs/CHANGELOG.txt | 2 ++ imgui.cpp | 5 +++-- imgui.h | 4 ++-- imgui_demo.cpp | 2 +- 4 files changed, 8 insertions(+), 5 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 5118fece..cc8d2f52 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -50,6 +50,8 @@ Breaking Changes: - If you were still using the old names, while you are cleaning up, considering enabling IMGUI_DISABLE_OBSOLETE_FUNCTIONS in imconfig.h even temporarily to have a pass at finding and removing up old API calls, if any remaining. +- Renamed io.ConfigWindowsMemoryCompactTimer to io.ConfigMemoryCompactTimer as the feature will apply + to other data structures. (#2636) Other Changes: diff --git a/imgui.cpp b/imgui.cpp index 0effb3b4..d347c531 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -371,6 +371,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. + - 2020/11/03 (1.80) - renamed io.ConfigWindowsMemoryCompactTimer to io.ConfigMemoryCompactTimer as the feature will apply to other data structures - 2020/10/14 (1.80) - backends: moved all backends files (imgui_impl_XXXX.cpp, imgui_impl_XXXX.h) from examples/ to backends/. - 2020/10/12 (1.80) - removed redirecting functions/enums that were marked obsolete in 1.60 (April 2018): - io.RenderDrawListsFn pointer -> use ImGui::GetDrawData() value and call the render function of your backend @@ -1037,7 +1038,7 @@ ImGuiIO::ImGuiIO() ConfigInputTextCursorBlink = true; ConfigWindowsResizeFromEdges = true; ConfigWindowsMoveFromTitleBarOnly = false; - ConfigWindowsMemoryCompactTimer = 60.0f; + ConfigMemoryCompactTimer = 60.0f; // Platform Functions BackendPlatformName = BackendRendererName = NULL; @@ -3894,7 +3895,7 @@ void ImGui::NewFrame() // Mark all windows as not visible and compact unused memory. IM_ASSERT(g.WindowsFocusOrder.Size == g.Windows.Size); - const float memory_compact_start_time = (g.IO.ConfigWindowsMemoryCompactTimer >= 0.0f) ? (float)g.Time - g.IO.ConfigWindowsMemoryCompactTimer : FLT_MAX; + const float memory_compact_start_time = (g.IO.ConfigMemoryCompactTimer >= 0.0f) ? (float)g.Time - g.IO.ConfigMemoryCompactTimer : FLT_MAX; for (int i = 0; i != g.Windows.Size; i++) { ImGuiWindow* window = g.Windows[i]; diff --git a/imgui.h b/imgui.h index a54e3f9e..a1b3e162 100644 --- a/imgui.h +++ b/imgui.h @@ -60,7 +60,7 @@ Index of this file: // Version // (Integer encoded as XYYZZ for use in #if preprocessor conditionals. Work in progress versions typically starts at XYY99 then bounce up to XYY00, XYY01 etc. when release tagging happens) #define IMGUI_VERSION "1.80 WIP" -#define IMGUI_VERSION_NUM 17905 +#define IMGUI_VERSION_NUM 17906 #define IMGUI_CHECKVERSION() ImGui::DebugCheckVersionAndDataLayout(IMGUI_VERSION, sizeof(ImGuiIO), sizeof(ImGuiStyle), sizeof(ImVec2), sizeof(ImVec4), sizeof(ImDrawVert), sizeof(ImDrawIdx)) // Define attributes of all API symbols declarations (e.g. for DLL under Windows) @@ -1524,7 +1524,7 @@ struct ImGuiIO bool ConfigInputTextCursorBlink; // = true // Set to false to disable blinking cursor, for users who consider it distracting. (was called: io.OptCursorBlink prior to 1.63) bool ConfigWindowsResizeFromEdges; // = true // Enable resizing of windows from their edges and from the lower-left corner. This requires (io.BackendFlags & ImGuiBackendFlags_HasMouseCursors) because it needs mouse cursor feedback. (This used to be a per-window ImGuiWindowFlags_ResizeFromAnySide flag) bool ConfigWindowsMoveFromTitleBarOnly; // = false // [BETA] Set to true to only allow moving windows when clicked+dragged from the title bar. Windows without a title bar are not affected. - float ConfigWindowsMemoryCompactTimer;// = 60.0f // [BETA] Compact window memory usage when unused. Set to -1.0f to disable. + float ConfigMemoryCompactTimer; // = 60.0f // [BETA] Free transient windows/tables memory buffers when unused for given amount of time. Set to -1.0f to disable. //------------------------------------------------------------------ // Platform Functions diff --git a/imgui_demo.cpp b/imgui_demo.cpp index 2ce3ddac..dd897236 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -3686,7 +3686,7 @@ void ImGui::ShowAboutWindow(bool* p_open) if (io.ConfigInputTextCursorBlink) ImGui::Text("io.ConfigInputTextCursorBlink"); if (io.ConfigWindowsResizeFromEdges) ImGui::Text("io.ConfigWindowsResizeFromEdges"); if (io.ConfigWindowsMoveFromTitleBarOnly) ImGui::Text("io.ConfigWindowsMoveFromTitleBarOnly"); - if (io.ConfigWindowsMemoryCompactTimer >= 0.0f) ImGui::Text("io.ConfigWindowsMemoryCompactTimer = %.1ff", io.ConfigWindowsMemoryCompactTimer); + if (io.ConfigMemoryCompactTimer >= 0.0f) ImGui::Text("io.ConfigMemoryCompactTimer = %.1f", io.ConfigMemoryCompactTimer); ImGui::Text("io.BackendFlags: 0x%08X", io.BackendFlags); if (io.BackendFlags & ImGuiBackendFlags_HasGamepad) ImGui::Text(" HasGamepad"); if (io.BackendFlags & ImGuiBackendFlags_HasMouseCursors) ImGui::Text(" HasMouseCursors"); From 9cca1b2e9795bcebb3054621788d5eb414080273 Mon Sep 17 00:00:00 2001 From: Rokas Kupstys Date: Tue, 3 Nov 2020 14:32:44 +0100 Subject: [PATCH 02/10] Replace UTF-8 decoder with one based on branchless version by Christopher Wellons. (not branchless anymore tho) Decoding performance increase ~30% --- docs/CHANGELOG.txt | 3 ++ imgui.cpp | 102 +++++++++++++++++++++------------------------ 2 files changed, 50 insertions(+), 55 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index cc8d2f52..6d21f86a 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -64,6 +64,9 @@ Other Changes: - Drag and Drop: Fix drag and drop to tie same-size drop targets by choosen the later one. Fixes dragging into a full-window-sized dockspace inside a zero-padded window. (#3519, #2717) [@Black-Cat] - Metrics: Fixed mishandling of ImDrawCmd::VtxOffset in wireframe mesh renderer. +- Misc: Replaced UTF-8 decoder by branchless one by Christopher Wellons (30~40% faster). [@rokups] + Super minor fix handling incomplete UTF-8 contents: if input does not contain enough bytes, decoder + returns IM_UNICODE_CODEPOINT_INVALID and consume remaining bytes (vs old decoded consumed only 1 byte). - Backends: OpenGL3: Use glGetString(GL_VERSION) query instead of glGetIntegerv(GL_MAJOR_VERSION, ...) when the later returns zero (e.g. Desktop GL 2.x). (#3530) [@xndcn] - Backends: OpenGL3: Backup and restore GL_PRIMITIVE_RESTART state. (#3544) [@Xipiryon] diff --git a/imgui.cpp b/imgui.cpp index d347c531..3aeb948c 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -1554,66 +1554,58 @@ void* ImFileLoadToMemory(const char* filename, const char* mode, size_t* out_f //----------------------------------------------------------------------------- // Convert UTF-8 to 32-bit character, process single character input. -// Based on stb_from_utf8() from github.com/nothings/stb/ +// A nearly-branchless UTF-8 decoder, based on work of Christopher Wellons (https://github.com/skeeto/branchless-utf8). // We handle UTF-8 decoding error by skipping forward. int ImTextCharFromUtf8(unsigned int* out_char, const char* in_text, const char* in_text_end) { - unsigned int c = (unsigned int)-1; - const unsigned char* str = (const unsigned char*)in_text; - if (!(*str & 0x80)) + static const char lengths[32] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 3, 3, 4, 0 }; + static const int masks[] = { 0x00, 0x7f, 0x1f, 0x0f, 0x07 }; + static const uint32_t mins[] = { 0x400000, 0, 0x80, 0x800, 0x10000 }; + static const int shiftc[] = { 0, 18, 12, 6, 0 }; + static const int shifte[] = { 0, 6, 4, 2, 0 }; + int len = lengths[*(const unsigned char*)in_text >> 3]; + int wanted = len + !len; + + if (in_text_end == NULL) + in_text_end = in_text + wanted; // Max length, nulls will be taken into account. + + // Copy at most 'len' bytes, stop copying at 0 or past in_text_end. Branch predictor does a good job here, + // so it is fast even with excessive branching. + unsigned char s[4]; + s[0] = in_text + 0 < in_text_end ? in_text[0] : 0; + s[1] = in_text + 1 < in_text_end ? in_text[1] : 0; + s[2] = in_text + 2 < in_text_end ? in_text[2] : 0; + s[3] = in_text + 3 < in_text_end ? in_text[3] : 0; + + // Assume a four-byte character and load four bytes. Unused bits are shifted out. + *out_char = (uint32_t)(s[0] & masks[len]) << 18; + *out_char |= (uint32_t)(s[1] & 0x3f) << 12; + *out_char |= (uint32_t)(s[2] & 0x3f) << 6; + *out_char |= (uint32_t)(s[3] & 0x3f) << 0; + *out_char >>= shiftc[len]; + + // Accumulate the various error conditions. + int e = 0; + e = (*out_char < mins[len]) << 6; // non-canonical encoding + e |= ((*out_char >> 11) == 0x1b) << 7; // surrogate half? + e |= (*out_char > IM_UNICODE_CODEPOINT_MAX) << 8; // out of range? + e |= (s[1] & 0xc0) >> 2; + e |= (s[2] & 0xc0) >> 4; + e |= (s[3] ) >> 6; + e ^= 0x2a; // top two bits of each tail byte correct? + e >>= shifte[len]; + + if (e) { - c = (unsigned int)(*str++); - *out_char = c; - return 1; + // No bytes are consumed when *in_text == 0 || in_text == in_text_end. + // One byte is consumed in case of invalid first byte of in_text. + // All available bytes (at most `len` bytes) are consumed on incomplete/invalid second to last bytes. + // Invalid or incomplete input may consume less bytes than wanted, therefore every byte has to be inspected in s. + wanted = ImMin(wanted, !!s[0] + !!s[1] + !!s[2] + !!s[3]); + *out_char = IM_UNICODE_CODEPOINT_INVALID; } - if ((*str & 0xe0) == 0xc0) - { - *out_char = IM_UNICODE_CODEPOINT_INVALID; // will be invalid but not end of string - if (in_text_end && in_text_end - (const char*)str < 2) return 1; - if (*str < 0xc2) return 2; - c = (unsigned int)((*str++ & 0x1f) << 6); - if ((*str & 0xc0) != 0x80) return 2; - c += (*str++ & 0x3f); - *out_char = c; - return 2; - } - if ((*str & 0xf0) == 0xe0) - { - *out_char = IM_UNICODE_CODEPOINT_INVALID; // will be invalid but not end of string - if (in_text_end && in_text_end - (const char*)str < 3) return 1; - if (*str == 0xe0 && (str[1] < 0xa0 || str[1] > 0xbf)) return 3; - if (*str == 0xed && str[1] > 0x9f) return 3; // str[1] < 0x80 is checked below - c = (unsigned int)((*str++ & 0x0f) << 12); - if ((*str & 0xc0) != 0x80) return 3; - c += (unsigned int)((*str++ & 0x3f) << 6); - if ((*str & 0xc0) != 0x80) return 3; - c += (*str++ & 0x3f); - *out_char = c; - return 3; - } - if ((*str & 0xf8) == 0xf0) - { - *out_char = IM_UNICODE_CODEPOINT_INVALID; // will be invalid but not end of string - if (in_text_end && in_text_end - (const char*)str < 4) return 1; - if (*str > 0xf4) return 4; - if (*str == 0xf0 && (str[1] < 0x90 || str[1] > 0xbf)) return 4; - if (*str == 0xf4 && str[1] > 0x8f) return 4; // str[1] < 0x80 is checked below - c = (unsigned int)((*str++ & 0x07) << 18); - if ((*str & 0xc0) != 0x80) return 4; - c += (unsigned int)((*str++ & 0x3f) << 12); - if ((*str & 0xc0) != 0x80) return 4; - c += (unsigned int)((*str++ & 0x3f) << 6); - if ((*str & 0xc0) != 0x80) return 4; - c += (*str++ & 0x3f); - // utf-8 encodings of values used in surrogate pairs are invalid - if ((c & 0xFFFFF800) == 0xD800) return 4; - // If codepoint does not fit in ImWchar, use replacement character U+FFFD instead - if (c > IM_UNICODE_CODEPOINT_MAX) c = IM_UNICODE_CODEPOINT_INVALID; - *out_char = c; - return 4; - } - *out_char = 0; - return 0; + + return wanted; } int ImTextStrFromUtf8(ImWchar* buf, int buf_size, const char* in_text, const char* in_text_end, const char** in_text_remaining) From b934b9bb8695c745c0e0b1b19994f4f5eb6a4da9 Mon Sep 17 00:00:00 2001 From: Albin Odervall Date: Fri, 23 Oct 2020 18:57:35 +0200 Subject: [PATCH 03/10] Backends: OSX, Metal: Fix -Wshadow, -Wimplicit-float-conversion, and -Wsign-conversion warnings. (#3555) --- backends/imgui_impl_metal.mm | 22 +++++++++++----------- backends/imgui_impl_osx.mm | 19 +++++++++---------- 2 files changed, 20 insertions(+), 21 deletions(-) diff --git a/backends/imgui_impl_metal.mm b/backends/imgui_impl_metal.mm index 3b0d34c6..8a6f7e7d 100644 --- a/backends/imgui_impl_metal.mm +++ b/backends/imgui_impl_metal.mm @@ -234,8 +234,8 @@ void ImGui_ImplMetal_DestroyDeviceObjects() int width, height; io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height); MTLTextureDescriptor *textureDescriptor = [MTLTextureDescriptor texture2DDescriptorWithPixelFormat:MTLPixelFormatRGBA8Unorm - width:width - height:height + width:(NSUInteger)width + height:(NSUInteger)height mipmapped:NO]; textureDescriptor.usage = MTLTextureUsageShaderRead; #if TARGET_OS_OSX @@ -244,7 +244,7 @@ void ImGui_ImplMetal_DestroyDeviceObjects() textureDescriptor.storageMode = MTLStorageModeShared; #endif id texture = [device newTextureWithDescriptor:textureDescriptor]; - [texture replaceRegion:MTLRegionMake2D(0, 0, width, height) mipmapLevel:0 withBytes:pixels bytesPerRow:width * 4]; + [texture replaceRegion:MTLRegionMake2D(0, 0, (NSUInteger)width, (NSUInteger)height) mipmapLevel:0 withBytes:pixels bytesPerRow:(NSUInteger)width * 4]; self.fontTexture = texture; } @@ -435,8 +435,8 @@ void ImGui_ImplMetal_DestroyDeviceObjects() float R = drawData->DisplayPos.x + drawData->DisplaySize.x; float T = drawData->DisplayPos.y; float B = drawData->DisplayPos.y + drawData->DisplaySize.y; - float N = viewport.znear; - float F = viewport.zfar; + float N = (float)viewport.znear; + float F = (float)viewport.zfar; const float ortho_projection[4][4] = { { 2.0f/(R-L), 0.0f, 0.0f, 0.0f }, @@ -464,8 +464,8 @@ void ImGui_ImplMetal_DestroyDeviceObjects() id renderPipelineState = [self renderPipelineStateForFrameAndDevice:commandBuffer.device]; - size_t vertexBufferLength = drawData->TotalVtxCount * sizeof(ImDrawVert); - size_t indexBufferLength = drawData->TotalIdxCount * sizeof(ImDrawIdx); + size_t vertexBufferLength = (size_t)drawData->TotalVtxCount * sizeof(ImDrawVert); + size_t indexBufferLength = (size_t)drawData->TotalIdxCount * sizeof(ImDrawIdx); MetalBuffer* vertexBuffer = [self dequeueReusableBufferOfLength:vertexBufferLength device:commandBuffer.device]; MetalBuffer* indexBuffer = [self dequeueReusableBufferOfLength:indexBufferLength device:commandBuffer.device]; @@ -482,8 +482,8 @@ void ImGui_ImplMetal_DestroyDeviceObjects() { const ImDrawList* cmd_list = drawData->CmdLists[n]; - memcpy((char *)vertexBuffer.buffer.contents + vertexBufferOffset, cmd_list->VtxBuffer.Data, cmd_list->VtxBuffer.Size * sizeof(ImDrawVert)); - memcpy((char *)indexBuffer.buffer.contents + indexBufferOffset, cmd_list->IdxBuffer.Data, cmd_list->IdxBuffer.Size * sizeof(ImDrawIdx)); + memcpy((char *)vertexBuffer.buffer.contents + vertexBufferOffset, cmd_list->VtxBuffer.Data, (size_t)cmd_list->VtxBuffer.Size * sizeof(ImDrawVert)); + memcpy((char *)indexBuffer.buffer.contents + indexBufferOffset, cmd_list->IdxBuffer.Data, (size_t)cmd_list->IdxBuffer.Size * sizeof(ImDrawIdx)); for (int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.Size; cmd_i++) { @@ -533,8 +533,8 @@ void ImGui_ImplMetal_DestroyDeviceObjects() } } - vertexBufferOffset += cmd_list->VtxBuffer.Size * sizeof(ImDrawVert); - indexBufferOffset += cmd_list->IdxBuffer.Size * sizeof(ImDrawIdx); + vertexBufferOffset += (size_t)cmd_list->VtxBuffer.Size * sizeof(ImDrawVert); + indexBufferOffset += (size_t)cmd_list->IdxBuffer.Size * sizeof(ImDrawIdx); } __weak id weakSelf = self; diff --git a/backends/imgui_impl_osx.mm b/backends/imgui_impl_osx.mm index fc347a40..4c137f6c 100644 --- a/backends/imgui_impl_osx.mm +++ b/backends/imgui_impl_osx.mm @@ -171,7 +171,7 @@ void ImGui_ImplOSX_NewFrame(NSView* view) ImGuiIO& io = ImGui::GetIO(); if (view) { - const float dpi = [view.window backingScaleFactor]; + const float dpi = (float)[view.window backingScaleFactor]; io.DisplaySize = ImVec2((float)view.bounds.size.width, (float)view.bounds.size.height); io.DisplayFramebufferScale = ImVec2(dpi, dpi); } @@ -180,7 +180,7 @@ void ImGui_ImplOSX_NewFrame(NSView* view) if (g_Time == 0.0) g_Time = CFAbsoluteTimeGetCurrent(); CFAbsoluteTime current_time = CFAbsoluteTimeGetCurrent(); - io.DeltaTime = current_time - g_Time; + io.DeltaTime = (float)(current_time - g_Time); g_Time = current_time; ImGui_ImplOSX_UpdateMouseCursorAndButtons(); @@ -231,7 +231,7 @@ bool ImGui_ImplOSX_HandleEvent(NSEvent* event, NSView* view) NSPoint mousePoint = event.locationInWindow; mousePoint = [view convertPoint:mousePoint fromView:nil]; mousePoint = NSMakePoint(mousePoint.x, view.bounds.size.height - mousePoint.y); - io.MousePos = ImVec2(mousePoint.x, mousePoint.y); + io.MousePos = ImVec2((float)mousePoint.x, (float)mousePoint.y); } if (event.type == NSEventTypeScrollWheel) @@ -258,9 +258,9 @@ bool ImGui_ImplOSX_HandleEvent(NSEvent* event, NSView* view) } if (fabs(wheel_dx) > 0.0) - io.MouseWheelH += wheel_dx * 0.1f; + io.MouseWheelH += (float)wheel_dx * 0.1f; if (fabs(wheel_dy) > 0.0) - io.MouseWheel += wheel_dy * 0.1f; + io.MouseWheel += (float)wheel_dy * 0.1f; return io.WantCaptureMouse; } @@ -268,8 +268,8 @@ bool ImGui_ImplOSX_HandleEvent(NSEvent* event, NSView* view) if (event.type == NSEventTypeKeyDown) { NSString* str = [event characters]; - int len = (int)[str length]; - for (int i = 0; i < len; i++) + NSUInteger len = [str length]; + for (NSUInteger i = 0; i < len; i++) { int c = [str characterAtIndex:i]; if (!io.KeyCtrl && !(c >= 0xF700 && c <= 0xFFFF) && c != 127) @@ -288,8 +288,8 @@ bool ImGui_ImplOSX_HandleEvent(NSEvent* event, NSView* view) if (event.type == NSEventTypeKeyUp) { NSString* str = [event characters]; - int len = (int)[str length]; - for (int i = 0; i < len; i++) + NSUInteger len = [str length]; + for (NSUInteger i = 0; i < len; i++) { int c = [str characterAtIndex:i]; int key = mapCharacterToKey(c); @@ -301,7 +301,6 @@ bool ImGui_ImplOSX_HandleEvent(NSEvent* event, NSView* view) if (event.type == NSEventTypeFlagsChanged) { - ImGuiIO& io = ImGui::GetIO(); unsigned int flags = [event modifierFlags] & NSEventModifierFlagDeviceIndependentFlagsMask; bool oldKeyCtrl = io.KeyCtrl; From 2fa00656a40fca5c1d5b3c19c51f13632d41c35e Mon Sep 17 00:00:00 2001 From: ocornut Date: Tue, 3 Nov 2020 15:46:29 +0100 Subject: [PATCH 04/10] Fix for IMGUI_DISABLE_METRICS_WINDOW --- imgui.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/imgui.cpp b/imgui.cpp index 3aeb948c..7f2bd0ae 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -10867,7 +10867,7 @@ void ImGui::DebugNodeWindowsList(ImVector* windows, const char* la void ImGui::ShowMetricsWindow(bool*) {} void ImGui::DebugNodeColumns(ImGuiColumns*) {} -void ImGui::DebugNodeDrawList(ImGuiWindow*, ImDrawList*, const char*) {} +void ImGui::DebugNodeDrawList(ImGuiWindow*, const ImDrawList*, const char*) {} void ImGui::DebugNodeDrawCmdShowMeshAndBoundingBox(ImGuiWindow*, const ImDrawList*, const ImDrawCmd*, bool, bool) {} void ImGui::DebugNodeStorage(ImGuiStorage*, const char*) {} void ImGui::DebugNodeTabBar(ImGuiTabBar*, const char*) {} From d6a2f7e95e98b93973a23005bc0b31d5c7953ee5 Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 4 Nov 2020 13:49:16 +0100 Subject: [PATCH 05/10] Reduced padding + unused storage in ImDrawList (224->192 bytes) + zero-init ImDrawListSplitter and ImDrawList + Readme tweak --- docs/README.md | 2 +- imgui.h | 18 +++++++++++++----- imgui_internal.h | 2 +- 3 files changed, 15 insertions(+), 7 deletions(-) diff --git a/docs/README.md b/docs/README.md index 35b08f9c..30151a91 100644 --- a/docs/README.md +++ b/docs/README.md @@ -196,7 +196,7 @@ Ongoing Dear ImGui development is financially supported by users and private spo - [Blizzard](https://careers.blizzard.com/en-us/openings/engineering/all/all/all/1), [Google](https://github.com/google/filament), [Nvidia](https://developer.nvidia.com/nvidia-omniverse), [Ubisoft](https://montreal.ubisoft.com/en/ubisoft-sponsors-user-interface-library-for-c-dear-imgui/) *Double-chocolate and Salty caramel sponsors* -- [Activision](https://careers.activision.com/c/programmingsoftware-engineering-jobs), [Arkane Studios](https://www.arkane-studios.com), [Dotemu](http://www.dotemu.com), [Framefield](http://framefield.com), [Hexagon](https://hexagonxalt.com/the-technology/xalt-visualization), [Kylotonn](https://www.kylotonn.com), [Media Molecule](http://www.mediamolecule.com), [Mesh Consultants](https://www.meshconsultants.ca), [Mobigame](http://www.mobigame.net), [Nadeo](https://www.nadeo.com), [Next Level Games](https://www.nextlevelgames.com), [RAD Game Tools](http://www.radgametools.com/), [Supercell](http://www.supercell.com), [Remedy Entertainment](https://www.remedygames.com/), [Unit 2 Games](https://unit2games.com/) +- [Activision](https://careers.activision.com/c/programmingsoftware-engineering-jobs), [Arkane Studios](https://www.arkane-studios.com), [Dotemu](http://www.dotemu.com), [Framefield](http://framefield.com), [Grinding Gear Games](https://www.grindinggear.com), [Hexagon](https://hexagonxalt.com/the-technology/xalt-visualization), [Kylotonn](https://www.kylotonn.com), [Media Molecule](http://www.mediamolecule.com), [Mesh Consultants](https://www.meshconsultants.ca), [Mobigame](http://www.mobigame.net), [Nadeo](https://www.nadeo.com), [Next Level Games](https://www.nextlevelgames.com), [RAD Game Tools](http://www.radgametools.com/), [Supercell](http://www.supercell.com), [Remedy Entertainment](https://www.remedygames.com/), [Unit 2 Games](https://unit2games.com/) From November 2014 to December 2019, ongoing development has also been financially supported by its users on Patreon and through individual donations. Please see [detailed list of Dear ImGui supporters](https://github.com/ocornut/imgui/wiki/Sponsors). diff --git a/imgui.h b/imgui.h index a1b3e162..bbedcfc8 100644 --- a/imgui.h +++ b/imgui.h @@ -2006,7 +2006,15 @@ struct ImDrawVert IMGUI_OVERRIDE_DRAWVERT_STRUCT_LAYOUT; #endif -// For use by ImDrawListSplitter. +// [Internal] For use by ImDrawList +struct ImDrawCmdHeader +{ + ImVec4 ClipRect; + ImTextureID TextureId; + unsigned int VtxOffset; +}; + +// [Internal] For use by ImDrawListSplitter struct ImDrawChannel { ImVector _CmdBuffer; @@ -2021,7 +2029,7 @@ struct ImDrawListSplitter int _Count; // Number of active channels (1+) ImVector _Channels; // Draw channels (not resized down so _Count might be < Channels.Size) - inline ImDrawListSplitter() { Clear(); } + inline ImDrawListSplitter() { memset(this, 0, sizeof(*this)); } inline ~ImDrawListSplitter() { ClearFreeMemory(); } inline void Clear() { _Current = 0; _Count = 1; } // Do not clear Channels[] so our allocations are reused next frame IMGUI_API void ClearFreeMemory(); @@ -2072,19 +2080,19 @@ struct ImDrawList ImDrawListFlags Flags; // Flags, you may poke into these to adjust anti-aliasing settings per-primitive. // [Internal, used while building lists] + unsigned int _VtxCurrentIdx; // [Internal] generally == VtxBuffer.Size unless we are past 64K vertices, in which case this gets reset to 0. const ImDrawListSharedData* _Data; // Pointer to shared draw data (you can use ImGui::GetDrawListSharedData() to get the one from current ImGui context) const char* _OwnerName; // Pointer to owner window's name for debugging - unsigned int _VtxCurrentIdx; // [Internal] Generally == VtxBuffer.Size unless we are past 64K vertices, in which case this gets reset to 0. ImDrawVert* _VtxWritePtr; // [Internal] point within VtxBuffer.Data after each add command (to avoid using the ImVector<> operators too much) ImDrawIdx* _IdxWritePtr; // [Internal] point within IdxBuffer.Data after each add command (to avoid using the ImVector<> operators too much) ImVector _ClipRectStack; // [Internal] ImVector _TextureIdStack; // [Internal] ImVector _Path; // [Internal] current path building - ImDrawCmd _CmdHeader; // [Internal] Template of active commands. Fields should match those of CmdBuffer.back(). + ImDrawCmdHeader _CmdHeader; // [Internal] template of active commands. Fields should match those of CmdBuffer.back(). ImDrawListSplitter _Splitter; // [Internal] for channels api (note: prefer using your own persistent instance of ImDrawListSplitter!) // If you want to create ImDrawList instances, pass them ImGui::GetDrawListSharedData() or create and use your own ImDrawListSharedData (so you can use ImDrawList without ImGui) - ImDrawList(const ImDrawListSharedData* shared_data) { _Data = shared_data; Flags = ImDrawListFlags_None; _VtxCurrentIdx = 0; _VtxWritePtr = NULL; _IdxWritePtr = NULL; _OwnerName = NULL; } + ImDrawList(const ImDrawListSharedData* shared_data) { memset(this, 0, sizeof(*this)); _Data = shared_data; } ~ImDrawList() { _ClearFreeMemory(); } IMGUI_API void PushClipRect(ImVec2 clip_rect_min, ImVec2 clip_rect_max, bool intersect_with_current_clip_rect = false); // Render-level scissoring. This is passed down to your render function but not used for CPU-side coarse clipping. Prefer using higher-level ImGui::PushClipRect() to affect logic (hit-testing and widget culling) diff --git a/imgui_internal.h b/imgui_internal.h index 11740019..7fa13392 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -1692,9 +1692,9 @@ struct IMGUI_API ImGuiWindow ImGuiID NavLastIds[ImGuiNavLayer_COUNT]; // Last known NavId for this window, per layer (0/1) ImRect NavRectRel[ImGuiNavLayer_COUNT]; // Reference rectangle, in window relative space - bool MemoryCompacted; // Set when window extraneous data have been garbage collected int MemoryDrawListIdxCapacity; // Backup of last idx/vtx count, so when waking up the window we can preallocate and avoid iterative alloc/copy int MemoryDrawListVtxCapacity; + bool MemoryCompacted; // Set when window extraneous data have been garbage collected public: ImGuiWindow(ImGuiContext* context, const char* name); From 2bf5ca7ef2f01a30758bb2a7060d902c22b33e9e Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 4 Nov 2020 17:50:30 +0100 Subject: [PATCH 06/10] ImDrawListClipper: avoid over reserving memory. --- imgui_draw.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/imgui_draw.cpp b/imgui_draw.cpp index 8ce1739f..3dd0a360 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -1429,7 +1429,10 @@ void ImDrawListSplitter::Split(ImDrawList* draw_list, int channels_count) IM_ASSERT(_Current == 0 && _Count <= 1 && "Nested channel splitting is not supported. Please use separate instances of ImDrawListSplitter."); int old_channels_count = _Channels.Size; if (old_channels_count < channels_count) + { + _Channels.reserve(channels_count); // Avoid over reserving since this is likely to stay stable _Channels.resize(channels_count); + } _Count = channels_count; // Channels[] (24/32 bytes each) hold storage that we'll swap with draw_list->_CmdBuffer/_IdxBuffer From 7a27b2a28232b8b0f1738fdbad6cc28efe09a2e4 Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 4 Nov 2020 20:11:05 +0100 Subject: [PATCH 07/10] Update Readme, links to Useful Widgets, updated a gif. --- docs/README.md | 9 +++++++-- docs/TODO.txt | 3 ++- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/docs/README.md b/docs/README.md index 30151a91..a5555883 100644 --- a/docs/README.md +++ b/docs/README.md @@ -81,7 +81,7 @@ ImGui::EndChild(); ImGui::End(); ``` Result: -
![sample code output](https://raw.githubusercontent.com/wiki/ocornut/imgui/web/v160/code_sample_03_color.gif) +
![sample code output](https://raw.githubusercontent.com/wiki/ocornut/imgui/web/v180/code_sample_04_color.gif) Dear ImGui allows you to **create elaborate tools** as well as very short-lived ones. On the extreme side of short-livedness: using the Edit&Continue (hot code reload) feature of modern compilers you can add a few widgets to tweaks variables while your application is running, and remove the code a minute later! Dear ImGui is not just for tweaking values. You can use it to trace a running algorithm by just emitting text commands. You can use it along with your own reflection data to browse your dataset live. You can use it to expose the internals of a subsystem in your engine, to create a logger, an inspection tool, a profiler, a debugger, an entire game making editor/framework, etc. @@ -119,11 +119,14 @@ Officially maintained backends/bindings (in repository): - Platforms: GLFW, SDL2, Win32, Glut, OSX. - Frameworks: Emscripten, Allegro5, Marmalade. -Third-party backends/bindings (see [Bindings](https://github.com/ocornut/imgui/wiki/Bindings/) page): +[Third-party backends/bindings](https://github.com/ocornut/imgui/wiki/Bindings) wiki page: - Languages: C, C# and: Beef, ChaiScript, Crystal, D, Go, Haskell, Haxe/hxcpp, Java, JavaScript, Julia, Kotlin, Lua, Odin, Pascal, PureBasic, Python, Ruby, Rust, Swift... - Frameworks: AGS/Adventure Game Studio, Amethyst, bsf, Cinder, Cocos2d-x, Diligent Engine, Flexium, GML/Game Maker Studio2, Godot, GTK3+OpenGL3, Irrlicht Engine, LÖVE+LUA, Magnum, NanoRT, nCine, Nim Game Lib, Ogre, openFrameworks, OSG/OpenSceneGraph, Orx, Photoshop, px_render, Qt/QtDirect3D, SFML, Sokol, Unity, Unreal Engine 4, vtk, Win32 GDI, WxWidgets. - Note that C bindings ([cimgui](https://github.com/cimgui/cimgui)) are auto-generated, you can use its json/lua output to generate bindings for other languages. +[Useful widgets and extensions](https://github.com/ocornut/imgui/wiki/Useful-Widgets) wiki page: +- Text editors, node editors, timeline editors, plotting, software renderers, remote network access, memory editors, gizmos etc. + Also see [Wiki](https://github.com/ocornut/imgui/wiki) for more links and ideas. ### Upcoming Changes @@ -140,6 +143,8 @@ Some of the goals for 2020 are: For more user-submitted screenshots of projects using Dear ImGui, check out the [Gallery Threads](https://github.com/ocornut/imgui/issues/3488)! +For a list of third-party widgets and extensions, check out the [Useful Widgets](https://github.com/ocornut/imgui/wiki/Useful-Widgets) wiki page. + Custom engine [![screenshot game](https://raw.githubusercontent.com/wiki/ocornut/imgui/web/v149/gallery_TheDragonsTrap-01-thumb.jpg)](https://cloud.githubusercontent.com/assets/8225057/20628927/33e14cac-b329-11e6-80f6-9524e93b048a.png) diff --git a/docs/TODO.txt b/docs/TODO.txt index 8473d720..fa299c96 100644 --- a/docs/TODO.txt +++ b/docs/TODO.txt @@ -167,7 +167,7 @@ It's mostly a bunch of personal notes, probably incomplete. Feel free to query i - dock: dock out from a collapsing header? would work nicely but need emitting window to keep submitting the code. - tabs: "there is currently a problem because TabItem() will try to submit their own tooltip after 0.50 second, and this will have the effect of making your tooltip flicker once." -> tooltip priority work - - tabs: close button tends to overlap unsaved-document star + - tabs: close button tends to overlap unsaved-document star - tabs: consider showing the star at the same spot as the close button, like VS Code does. - tabs: make EndTabBar fail if users doesn't respect BeginTabBar return value, for consistency/future-proofing. - tabs: persistent order/focus in BeginTabBar() api (#261, #351) @@ -271,6 +271,7 @@ It's mostly a bunch of personal notes, probably incomplete. Feel free to query i - filters: fuzzy matches (may use code at blog.forrestthewoods.com/4cffeed33fdb) - drag and drop: fix/support/options for overlapping drag sources. + - drag and drop: focus drag target window on hold (even without open) - drag and drop: releasing a drop shows the "..." tooltip for one frame - since e13e598 (#1725) - drag and drop: drag source on a group object (would need e.g. an invisible button covering group in EndGroup) https://twitter.com/paniq/status/1121446364909535233 - drag and drop: have some way to know when a drag begin from BeginDragDropSource() pov. (see 2018/01/11 post in #143) From 046057cebbd7d22fb97c062f8c6907b0174aa7d5 Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 4 Nov 2020 20:11:34 +0100 Subject: [PATCH 08/10] Selectable: Avoid pushing span-column background if clipped. --- imgui_widgets.cpp | 30 ++++++++++++++++++++++-------- 1 file changed, 22 insertions(+), 8 deletions(-) diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index 9b440878..ca5c3b9a 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -5909,10 +5909,6 @@ bool ImGui::Selectable(const char* label, bool selected, ImGuiSelectableFlags fl ImGuiContext& g = *GImGui; const ImGuiStyle& style = g.Style; - const bool span_all_columns = (flags & ImGuiSelectableFlags_SpanAllColumns) != 0; - if (span_all_columns && window->DC.CurrentColumns) // FIXME-OPT: Avoid if vertically clipped. - PushColumnsBackground(); - // Submit label or explicit size to ItemSize(), whereas ItemAdd() will submit a larger/spanning rectangle. ImGuiID id = window->GetID(label); ImVec2 label_size = CalcTextSize(label, NULL, true); @@ -5923,6 +5919,7 @@ bool ImGui::Selectable(const char* label, bool selected, ImGuiSelectableFlags fl // Fill horizontal space // We don't support (size < 0.0f) in Selectable() because the ItemSpacing extension would make explicitely right-aligned sizes not visibly match other widgets. + const bool span_all_columns = (flags & ImGuiSelectableFlags_SpanAllColumns) != 0; const float min_x = span_all_columns ? window->ParentWorkRect.Min.x : pos.x; const float max_x = span_all_columns ? window->ParentWorkRect.Max.x : window->WorkRect.Max.x; if (size_arg.x == 0.0f || (flags & ImGuiSelectableFlags_SpanAvailWidth)) @@ -5947,6 +5944,15 @@ bool ImGui::Selectable(const char* label, bool selected, ImGuiSelectableFlags fl } //if (g.IO.KeyCtrl) { GetForegroundDrawList()->AddRect(bb.Min, bb.Max, IM_COL32(0, 255, 0, 255)); } + // Modify ClipRect for the ItemAdd(), faster than doing a PushColumnsBackground/PushTableBackground for every Selectable.. + const float backup_clip_rect_min_x = window->ClipRect.Min.x; + const float backup_clip_rect_max_x = window->ClipRect.Max.x; + if (span_all_columns) + { + window->ClipRect.Min.x = window->ParentWorkRect.Min.x; + window->ClipRect.Max.x = window->ParentWorkRect.Max.x; + } + bool item_add; if (flags & ImGuiSelectableFlags_Disabled) { @@ -5959,13 +5965,21 @@ bool ImGui::Selectable(const char* label, bool selected, ImGuiSelectableFlags fl { item_add = ItemAdd(bb, id); } - if (!item_add) + + if (span_all_columns) { - if (span_all_columns && window->DC.CurrentColumns) - PopColumnsBackground(); - return false; + window->ClipRect.Min.x = backup_clip_rect_min_x; + window->ClipRect.Max.x = backup_clip_rect_max_x; } + if (!item_add) + return false; + + // FIXME: We can standardize the behavior of those two, we could also keep the fast path of override ClipRect + full push on render only, + // which would be advantageous since most selectable are not selected. + if (span_all_columns && window->DC.CurrentColumns) + PushColumnsBackground(); + // We use NoHoldingActiveID on menus so user can click and _hold_ on a menu then drag to browse child entries ImGuiButtonFlags button_flags = 0; if (flags & ImGuiSelectableFlags_NoHoldingActiveID) { button_flags |= ImGuiButtonFlags_NoHoldingActiveId; } From 5f97809cab996ed2b76ccc9097d2e84bd71985e6 Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 5 Nov 2020 13:15:02 +0100 Subject: [PATCH 09/10] Misc tidying up (zero-clear structures, more unused default in ClipRetFullscreen, NavApplyItemToResult() coding style fix) Zero-clearing more structures Remove arbitrary default ClipRetFullscreen value in ImDrawListSharedData. Nav extracted NavApplyItemToResult() function. Coding style fixes in OSX Backends. --- examples/example_apple_metal/main.mm | 69 ++++++++++++++++---------- examples/example_apple_opengl2/main.mm | 2 +- imgui.cpp | 24 ++++----- imgui_draw.cpp | 11 +--- imgui_internal.h | 24 ++------- imgui_widgets.cpp | 7 --- 6 files changed, 62 insertions(+), 75 deletions(-) diff --git a/examples/example_apple_metal/main.mm b/examples/example_apple_metal/main.mm index ec6482ee..541dc5e1 100644 --- a/examples/example_apple_metal/main.mm +++ b/examples/example_apple_metal/main.mm @@ -1,3 +1,6 @@ +// Dear ImGui: standalone example application for OSX + Metal. +// If you are new to Dear ImGui, read documentation from the docs/ folder + read the top of imgui.cpp. +// Read online: https://github.com/ocornut/imgui/tree/master/docs #import @@ -31,13 +34,15 @@ @implementation ViewController -- (instancetype)initWithNibName:(nullable NSString *)nibNameOrNil bundle:(nullable NSBundle *)nibBundleOrNil { +- (instancetype)initWithNibName:(nullable NSString *)nibNameOrNil bundle:(nullable NSBundle *)nibBundleOrNil +{ self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]; _device = MTLCreateSystemDefaultDevice(); _commandQueue = [_device newCommandQueue]; - if (!self.device) { + if (!self.device) + { NSLog(@"Metal is not supported"); abort(); } @@ -75,11 +80,13 @@ return self; } -- (MTKView *)mtkView { +- (MTKView *)mtkView +{ return (MTKView *)self.view; } -- (void)loadView { +- (void)loadView +{ self.view = [[MTKView alloc] initWithFrame:CGRectMake(0, 0, 1200, 720)]; } @@ -104,14 +111,13 @@ // window, we'd want to be much more careful than just ingesting the complete event stream, though we // do make an effort to be good citizens by passing along events when Dear ImGui doesn't want to capture. NSEventMask eventMask = NSEventMaskKeyDown | NSEventMaskKeyUp | NSEventMaskFlagsChanged | NSEventTypeScrollWheel; - [NSEvent addLocalMonitorForEventsMatchingMask:eventMask handler:^NSEvent * _Nullable(NSEvent *event) { + [NSEvent addLocalMonitorForEventsMatchingMask:eventMask handler:^NSEvent * _Nullable(NSEvent *event) + { BOOL wantsCapture = ImGui_ImplOSX_HandleEvent(event, self.view); - if (event.type == NSEventTypeKeyDown && wantsCapture) { + if (event.type == NSEventTypeKeyDown && wantsCapture) return nil; - } else { + else return event; - } - }]; ImGui_ImplOSX_Init(); @@ -174,15 +180,18 @@ // multitouch correctly at all. This causes the "cursor" to behave very erratically // when there are multiple active touches. But for demo purposes, single-touch // interaction actually works surprisingly well. -- (void)updateIOWithTouchEvent:(UIEvent *)event { +- (void)updateIOWithTouchEvent:(UIEvent *)event +{ UITouch *anyTouch = event.allTouches.anyObject; CGPoint touchLocation = [anyTouch locationInView:self.view]; ImGuiIO &io = ImGui::GetIO(); io.MousePos = ImVec2(touchLocation.x, touchLocation.y); BOOL hasActiveTouch = NO; - for (UITouch *touch in event.allTouches) { - if (touch.phase != UITouchPhaseEnded && touch.phase != UITouchPhaseCancelled) { + for (UITouch *touch in event.allTouches) + { + if (touch.phase != UITouchPhaseEnded && touch.phase != UITouchPhaseCancelled) + { hasActiveTouch = YES; break; } @@ -190,19 +199,23 @@ io.MouseDown[0] = hasActiveTouch; } -- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { +- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event +{ [self updateIOWithTouchEvent:event]; } -- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event { +- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event +{ [self updateIOWithTouchEvent:event]; } -- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event { +- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event +{ [self updateIOWithTouchEvent:event]; } -- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event { +- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event +{ [self updateIOWithTouchEvent:event]; } @@ -212,7 +225,7 @@ - (void)drawInMTKView:(MTKView*)view { - ImGuiIO &io = ImGui::GetIO(); + ImGuiIO& io = ImGui::GetIO(); io.DisplaySize.x = view.bounds.size.width; io.DisplaySize.y = view.bounds.size.height; @@ -288,8 +301,8 @@ // Rendering ImGui::Render(); - ImDrawData* drawData = ImGui::GetDrawData(); - ImGui_ImplMetal_RenderDrawData(drawData, commandBuffer, renderEncoder); + ImDrawData* draw_data = ImGui::GetDrawData(); + ImGui_ImplMetal_RenderDrawData(draw_data, commandBuffer, renderEncoder); [renderEncoder popDebugGroup]; [renderEncoder endEncoding]; @@ -316,8 +329,10 @@ @implementation AppDelegate -- (instancetype)init { - if (self = [super init]) { +- (instancetype)init +{ + if (self = [super init]) + { NSViewController *rootViewController = [[ViewController alloc] initWithNibName:nil bundle:nil]; self.window = [[NSWindow alloc] initWithContentRect:NSZeroRect styleMask:NSWindowStyleMaskTitled | NSWindowStyleMaskClosable | NSWindowStyleMaskResizable | NSWindowStyleMaskMiniaturizable @@ -331,7 +346,8 @@ return self; } -- (BOOL)applicationShouldTerminateAfterLastWindowClosed:(NSApplication *)sender { +- (BOOL)applicationShouldTerminateAfterLastWindowClosed:(NSApplication *)sender +{ return YES; } @@ -363,14 +379,17 @@ #if TARGET_OS_OSX -int main(int argc, const char * argv[]) { +int main(int argc, const char * argv[]) +{ return NSApplicationMain(argc, argv); } #else -int main(int argc, char * argv[]) { - @autoreleasepool { +int main(int argc, char * argv[]) +{ + @autoreleasepool + { return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); } } diff --git a/examples/example_apple_opengl2/main.mm b/examples/example_apple_opengl2/main.mm index c3f43bdb..5bcc9ea4 100644 --- a/examples/example_apple_opengl2/main.mm +++ b/examples/example_apple_opengl2/main.mm @@ -139,7 +139,7 @@ animationTimer = nil; } -// Forward Mouse/Keyboard events to dear imgui OSX backend. It returns true when imgui is expecting to use the event. +// Forward Mouse/Keyboard events to Dear ImGui OSX backend. -(void)keyUp:(NSEvent *)event { ImGui_ImplOSX_HandleEvent(event, self); } -(void)keyDown:(NSEvent *)event { ImGui_ImplOSX_HandleEvent(event, self); } -(void)flagsChanged:(NSEvent *)event { ImGui_ImplOSX_HandleEvent(event, self); } diff --git a/imgui.cpp b/imgui.cpp index 7f2bd0ae..427806d8 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -862,6 +862,7 @@ static float NavUpdatePageUpPageDown(); static inline void NavUpdateAnyRequestFlag(); static void NavEndFrame(); static bool NavScoreItem(ImGuiNavMoveResult* result, ImRect cand); +static void NavApplyItemToResult(ImGuiNavMoveResult* result, ImGuiWindow* window, ImGuiID id, const ImRect& nav_bb_rel); static void NavProcessItem(ImGuiWindow* window, const ImRect& nav_bb, ImGuiID id); static ImVec2 NavCalcPreferredRefPos(); static void NavSaveLastChildNavWindowIntoParent(ImGuiWindow* nav_window); @@ -8377,6 +8378,14 @@ static bool ImGui::NavScoreItem(ImGuiNavMoveResult* result, ImRect cand) return new_best; } +static void ImGui::NavApplyItemToResult(ImGuiNavMoveResult* result, ImGuiWindow* window, ImGuiID id, const ImRect& nav_bb_rel) +{ + result->Window = window; + result->ID = id; + result->FocusScopeId = window->DC.NavFocusScopeIdCurrent; + result->RectRel = nav_bb_rel; +} + // We get there when either NavId == id, or when g.NavAnyRequest is set (which is updated by NavUpdateAnyRequestFlag above) static void ImGui::NavProcessItem(ImGuiWindow* window, const ImRect& nav_bb, const ImGuiID id) { @@ -8417,25 +8426,14 @@ static void ImGui::NavProcessItem(ImGuiWindow* window, const ImRect& nav_bb, con bool new_best = g.NavMoveRequest && NavScoreItem(result, nav_bb); #endif if (new_best) - { - result->Window = window; - result->ID = id; - result->FocusScopeId = window->DC.NavFocusScopeIdCurrent; - result->RectRel = nav_bb_rel; - } + NavApplyItemToResult(result, window, id, nav_bb_rel); // Features like PageUp/PageDown need to maintain a separate score for the visible set of items. const float VISIBLE_RATIO = 0.70f; if ((g.NavMoveRequestFlags & ImGuiNavMoveFlags_AlsoScoreVisibleSet) && window->ClipRect.Overlaps(nav_bb)) if (ImClamp(nav_bb.Max.y, window->ClipRect.Min.y, window->ClipRect.Max.y) - ImClamp(nav_bb.Min.y, window->ClipRect.Min.y, window->ClipRect.Max.y) >= (nav_bb.Max.y - nav_bb.Min.y) * VISIBLE_RATIO) if (NavScoreItem(&g.NavMoveResultLocalVisibleSet, nav_bb)) - { - result = &g.NavMoveResultLocalVisibleSet; - result->Window = window; - result->ID = id; - result->FocusScopeId = window->DC.NavFocusScopeIdCurrent; - result->RectRel = nav_bb_rel; - } + NavApplyItemToResult(&g.NavMoveResultLocalVisibleSet, window, id, nav_bb_rel); } // Update window-relative bounding box of navigated item diff --git a/imgui_draw.cpp b/imgui_draw.cpp index 3dd0a360..8a102220 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -344,21 +344,12 @@ void ImGui::StyleColorsLight(ImGuiStyle* dst) ImDrawListSharedData::ImDrawListSharedData() { - Font = NULL; - FontSize = 0.0f; - CurveTessellationTol = 0.0f; - CircleSegmentMaxError = 0.0f; - ClipRectFullscreen = ImVec4(-8192.0f, -8192.0f, +8192.0f, +8192.0f); - InitialFlags = ImDrawListFlags_None; - - // Lookup tables + memset(this, 0, sizeof(*this)); for (int i = 0; i < IM_ARRAYSIZE(ArcFastVtx); i++) { const float a = ((float)i * 2 * IM_PI) / (float)IM_ARRAYSIZE(ArcFastVtx); ArcFastVtx[i] = ImVec2(ImCos(a), ImSin(a)); } - memset(CircleSegmentCounts, 0, sizeof(CircleSegmentCounts)); // This will be set by SetCircleSegmentMaxError() - TexUvLines = NULL; } void ImDrawListSharedData::SetCircleSegmentMaxError(float max_error) diff --git a/imgui_internal.h b/imgui_internal.h index 7fa13392..ff8dbe6f 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -844,7 +844,7 @@ struct IMGUI_API ImGuiMenuColumns float Width, NextWidth; float Pos[3], NextWidths[3]; - ImGuiMenuColumns(); + ImGuiMenuColumns() { memset(this, 0, sizeof(*this)); } void Update(int count, float spacing, bool clear); float DeclColumns(float w0, float w1, float w2); float CalcExtraSpace(float avail_w) const; @@ -897,7 +897,7 @@ struct ImGuiPopupData ImVec2 OpenPopupPos; // Set on OpenPopup(), preferred popup position (typically == OpenMousePos when using mouse) ImVec2 OpenMousePos; // Set on OpenPopup(), copy of mouse position at the time of opening popup - ImGuiPopupData() { PopupId = 0; Window = SourceWindow = NULL; OpenFrameCount = -1; OpenParentId = 0; } + ImGuiPopupData() { memset(this, 0, sizeof(*this)); OpenFrameCount = -1; } }; struct ImGuiNavMoveResult @@ -1006,7 +1006,7 @@ struct ImGuiColumnData ImGuiColumnsFlags Flags; // Not exposed ImRect ClipRect; - ImGuiColumnData() { OffsetNorm = OffsetNormBeforeResize = 0.0f; Flags = ImGuiColumnsFlags_None; } + ImGuiColumnData() { memset(this, 0, sizeof(*this)); } }; struct ImGuiColumns @@ -1027,21 +1027,7 @@ struct ImGuiColumns ImVector Columns; ImDrawListSplitter Splitter; - ImGuiColumns() { Clear(); } - void Clear() - { - ID = 0; - Flags = ImGuiColumnsFlags_None; - IsFirstFrame = false; - IsBeingResized = false; - Current = 0; - Count = 1; - OffMinX = OffMaxX = 0.0f; - LineMinY = LineMaxY = 0.0f; - HostCursorPosY = 0.0f; - HostCursorMaxPosX = 0.0f; - Columns.clear(); - } + ImGuiColumns() { memset(this, 0, sizeof(*this)); } }; //----------------------------------------------------------------------------- @@ -1083,7 +1069,7 @@ struct ImGuiWindowSettings bool Collapsed; bool WantApply; // Set when loaded from .ini data (to enable merging/loading .ini data into an already running context) - ImGuiWindowSettings() { ID = 0; Pos = Size = ImVec2ih(0, 0); Collapsed = WantApply = false; } + ImGuiWindowSettings() { memset(this, 0, sizeof(*this)); } char* GetName() { return (char*)(this + 1); } }; diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index ca5c3b9a..eed4a048 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -6388,13 +6388,6 @@ void ImGui::Value(const char* prefix, float v, const char* float_format) //------------------------------------------------------------------------- // Helpers for internal use -ImGuiMenuColumns::ImGuiMenuColumns() -{ - Spacing = Width = NextWidth = 0.0f; - memset(Pos, 0, sizeof(Pos)); - memset(NextWidths, 0, sizeof(NextWidths)); -} - void ImGuiMenuColumns::Update(int count, float spacing, bool clear) { IM_ASSERT(count == IM_ARRAYSIZE(Pos)); From 5789e69a6259f4cf91ed9a523604b911c4e41191 Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 5 Nov 2020 21:23:02 +0100 Subject: [PATCH 10/10] Checkbox: Added CheckboxFlags() helper with int* type. Demo: removed extraneous casts. --- docs/CHANGELOG.txt | 1 + imgui.h | 1 + imgui_demo.cpp | 67 +++++++++++++++++++++++----------------------- imgui_internal.h | 1 + imgui_widgets.cpp | 34 +++++++++++++++-------- 5 files changed, 59 insertions(+), 45 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 6d21f86a..7b8254ac 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -63,6 +63,7 @@ Other Changes: or CollapsingHeader() while dragging. (#1738) - Drag and Drop: Fix drag and drop to tie same-size drop targets by choosen the later one. Fixes dragging into a full-window-sized dockspace inside a zero-padded window. (#3519, #2717) [@Black-Cat] +- Checkbox: Added CheckboxFlags() helper with int* type. - Metrics: Fixed mishandling of ImDrawCmd::VtxOffset in wireframe mesh renderer. - Misc: Replaced UTF-8 decoder by branchless one by Christopher Wellons (30~40% faster). [@rokups] Super minor fix handling incomplete UTF-8 contents: if input does not contain enough bytes, decoder diff --git a/imgui.h b/imgui.h index bbedcfc8..f3dcac71 100644 --- a/imgui.h +++ b/imgui.h @@ -444,6 +444,7 @@ namespace ImGui IMGUI_API void Image(ImTextureID user_texture_id, const ImVec2& size, const ImVec2& uv0 = ImVec2(0, 0), const ImVec2& uv1 = ImVec2(1,1), const ImVec4& tint_col = ImVec4(1,1,1,1), const ImVec4& border_col = ImVec4(0,0,0,0)); IMGUI_API bool ImageButton(ImTextureID user_texture_id, const ImVec2& size, const ImVec2& uv0 = ImVec2(0, 0), const ImVec2& uv1 = ImVec2(1,1), int frame_padding = -1, const ImVec4& bg_col = ImVec4(0,0,0,0), const ImVec4& tint_col = ImVec4(1,1,1,1)); // <0 frame_padding uses default frame padding settings. 0 for no padding IMGUI_API bool Checkbox(const char* label, bool* v); + IMGUI_API bool CheckboxFlags(const char* label, int* flags, int flags_value); IMGUI_API bool CheckboxFlags(const char* label, unsigned int* flags, unsigned int flags_value); IMGUI_API bool RadioButton(const char* label, bool active); // use with e.g. if (RadioButton("one", my_value==1)) { my_value = 1; } IMGUI_API bool RadioButton(const char* label, int* v, int v_button); // shortcut to handle the above pattern when value is an integer diff --git a/imgui_demo.cpp b/imgui_demo.cpp index dd897236..07cd3a23 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -379,16 +379,15 @@ void ImGui::ShowDemoWindow(bool* p_open) if (ImGui::TreeNode("Configuration##2")) { - ImGui::CheckboxFlags("io.ConfigFlags: NavEnableKeyboard", (unsigned int*)&io.ConfigFlags, ImGuiConfigFlags_NavEnableKeyboard); - ImGui::CheckboxFlags("io.ConfigFlags: NavEnableGamepad", (unsigned int*)&io.ConfigFlags, ImGuiConfigFlags_NavEnableGamepad); + ImGui::CheckboxFlags("io.ConfigFlags: NavEnableKeyboard", &io.ConfigFlags, ImGuiConfigFlags_NavEnableKeyboard); + ImGui::CheckboxFlags("io.ConfigFlags: NavEnableGamepad", &io.ConfigFlags, ImGuiConfigFlags_NavEnableGamepad); ImGui::SameLine(); HelpMarker("Required backend to feed in gamepad inputs in io.NavInputs[] and set io.BackendFlags |= ImGuiBackendFlags_HasGamepad.\n\nRead instructions in imgui.cpp for details."); - ImGui::CheckboxFlags("io.ConfigFlags: NavEnableSetMousePos", (unsigned int*)&io.ConfigFlags, ImGuiConfigFlags_NavEnableSetMousePos); + ImGui::CheckboxFlags("io.ConfigFlags: NavEnableSetMousePos", &io.ConfigFlags, ImGuiConfigFlags_NavEnableSetMousePos); ImGui::SameLine(); HelpMarker("Instruct navigation to move the mouse cursor. See comment for ImGuiConfigFlags_NavEnableSetMousePos."); - ImGui::CheckboxFlags("io.ConfigFlags: NoMouse", (unsigned int*)&io.ConfigFlags, ImGuiConfigFlags_NoMouse); - - // The "NoMouse" option above can get us stuck with a disable mouse! Provide an alternative way to fix it: + ImGui::CheckboxFlags("io.ConfigFlags: NoMouse", &io.ConfigFlags, ImGuiConfigFlags_NoMouse); if (io.ConfigFlags & ImGuiConfigFlags_NoMouse) { + // The "NoMouse" option can get us stuck with a disabled mouse! Let's provide an alternative way to fix it: if (fmodf((float)ImGui::GetTime(), 0.40f) < 0.20f) { ImGui::SameLine(); @@ -397,7 +396,7 @@ void ImGui::ShowDemoWindow(bool* p_open) if (ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_Space))) io.ConfigFlags &= ~ImGuiConfigFlags_NoMouse; } - ImGui::CheckboxFlags("io.ConfigFlags: NoMouseCursorChange", (unsigned int*)&io.ConfigFlags, ImGuiConfigFlags_NoMouseCursorChange); + ImGui::CheckboxFlags("io.ConfigFlags: NoMouseCursorChange", &io.ConfigFlags, ImGuiConfigFlags_NoMouseCursorChange); ImGui::SameLine(); HelpMarker("Instruct backend to not alter mouse cursor shape and visibility."); ImGui::Checkbox("io.ConfigInputTextCursorBlink", &io.ConfigInputTextCursorBlink); ImGui::SameLine(); HelpMarker("Set to false to disable blinking cursor, for users who consider it distracting"); @@ -419,10 +418,10 @@ void ImGui::ShowDemoWindow(bool* p_open) // Make a local copy to avoid modifying actual backend flags. ImGuiBackendFlags backend_flags = io.BackendFlags; - ImGui::CheckboxFlags("io.BackendFlags: HasGamepad", (unsigned int*)&backend_flags, ImGuiBackendFlags_HasGamepad); - ImGui::CheckboxFlags("io.BackendFlags: HasMouseCursors", (unsigned int*)&backend_flags, ImGuiBackendFlags_HasMouseCursors); - ImGui::CheckboxFlags("io.BackendFlags: HasSetMousePos", (unsigned int*)&backend_flags, ImGuiBackendFlags_HasSetMousePos); - ImGui::CheckboxFlags("io.BackendFlags: RendererHasVtxOffset", (unsigned int*)&backend_flags, ImGuiBackendFlags_RendererHasVtxOffset); + ImGui::CheckboxFlags("io.BackendFlags: HasGamepad", &backend_flags, ImGuiBackendFlags_HasGamepad); + ImGui::CheckboxFlags("io.BackendFlags: HasMouseCursors", &backend_flags, ImGuiBackendFlags_HasMouseCursors); + ImGui::CheckboxFlags("io.BackendFlags: HasSetMousePos", &backend_flags, ImGuiBackendFlags_HasSetMousePos); + ImGui::CheckboxFlags("io.BackendFlags: RendererHasVtxOffset", &backend_flags, ImGuiBackendFlags_RendererHasVtxOffset); ImGui::TreePop(); ImGui::Separator(); } @@ -710,10 +709,10 @@ static void ShowDemoWindowWidgets() static ImGuiTreeNodeFlags base_flags = ImGuiTreeNodeFlags_OpenOnArrow | ImGuiTreeNodeFlags_OpenOnDoubleClick | ImGuiTreeNodeFlags_SpanAvailWidth; static bool align_label_with_current_x_position = false; static bool test_drag_and_drop = false; - ImGui::CheckboxFlags("ImGuiTreeNodeFlags_OpenOnArrow", (unsigned int*)&base_flags, ImGuiTreeNodeFlags_OpenOnArrow); - ImGui::CheckboxFlags("ImGuiTreeNodeFlags_OpenOnDoubleClick", (unsigned int*)&base_flags, ImGuiTreeNodeFlags_OpenOnDoubleClick); - ImGui::CheckboxFlags("ImGuiTreeNodeFlags_SpanAvailWidth", (unsigned int*)&base_flags, ImGuiTreeNodeFlags_SpanAvailWidth); ImGui::SameLine(); HelpMarker("Extend hit area to all available width instead of allowing more items to be laid out after the node."); - ImGui::CheckboxFlags("ImGuiTreeNodeFlags_SpanFullWidth", (unsigned int*)&base_flags, ImGuiTreeNodeFlags_SpanFullWidth); + ImGui::CheckboxFlags("ImGuiTreeNodeFlags_OpenOnArrow", &base_flags, ImGuiTreeNodeFlags_OpenOnArrow); + ImGui::CheckboxFlags("ImGuiTreeNodeFlags_OpenOnDoubleClick", &base_flags, ImGuiTreeNodeFlags_OpenOnDoubleClick); + ImGui::CheckboxFlags("ImGuiTreeNodeFlags_SpanAvailWidth", &base_flags, ImGuiTreeNodeFlags_SpanAvailWidth); ImGui::SameLine(); HelpMarker("Extend hit area to all available width instead of allowing more items to be laid out after the node."); + ImGui::CheckboxFlags("ImGuiTreeNodeFlags_SpanFullWidth", &base_flags, ImGuiTreeNodeFlags_SpanFullWidth); ImGui::Checkbox("Align label with current X position", &align_label_with_current_x_position); ImGui::Checkbox("Test tree node as drag source", &test_drag_and_drop); ImGui::Text("Hello!"); @@ -970,11 +969,11 @@ static void ShowDemoWindowWidgets() { // Expose flags as checkbox for the demo static ImGuiComboFlags flags = 0; - ImGui::CheckboxFlags("ImGuiComboFlags_PopupAlignLeft", (unsigned int*)&flags, ImGuiComboFlags_PopupAlignLeft); + ImGui::CheckboxFlags("ImGuiComboFlags_PopupAlignLeft", &flags, ImGuiComboFlags_PopupAlignLeft); ImGui::SameLine(); HelpMarker("Only makes a difference if the popup is larger than the combo"); - if (ImGui::CheckboxFlags("ImGuiComboFlags_NoArrowButton", (unsigned int*)&flags, ImGuiComboFlags_NoArrowButton)) + if (ImGui::CheckboxFlags("ImGuiComboFlags_NoArrowButton", &flags, ImGuiComboFlags_NoArrowButton)) flags &= ~ImGuiComboFlags_NoPreview; // Clear the other flag, as we cannot combine both - if (ImGui::CheckboxFlags("ImGuiComboFlags_NoPreview", (unsigned int*)&flags, ImGuiComboFlags_NoPreview)) + if (ImGui::CheckboxFlags("ImGuiComboFlags_NoPreview", &flags, ImGuiComboFlags_NoPreview)) flags &= ~ImGuiComboFlags_NoArrowButton; // Clear the other flag, as we cannot combine both // Using the generic BeginCombo() API, you have full control over how to display the combo contents. @@ -1165,9 +1164,9 @@ static void ShowDemoWindowWidgets() static ImGuiInputTextFlags flags = ImGuiInputTextFlags_AllowTabInput; HelpMarker("You can use the ImGuiInputTextFlags_CallbackResize facility if you need to wire InputTextMultiline() to a dynamic string type. See misc/cpp/imgui_stdlib.h for an example. (This is not demonstrated in imgui_demo.cpp because we don't want to include in here)"); - ImGui::CheckboxFlags("ImGuiInputTextFlags_ReadOnly", (unsigned int*)&flags, ImGuiInputTextFlags_ReadOnly); - ImGui::CheckboxFlags("ImGuiInputTextFlags_AllowTabInput", (unsigned int*)&flags, ImGuiInputTextFlags_AllowTabInput); - ImGui::CheckboxFlags("ImGuiInputTextFlags_CtrlEnterForNewLine", (unsigned int*)&flags, ImGuiInputTextFlags_CtrlEnterForNewLine); + ImGui::CheckboxFlags("ImGuiInputTextFlags_ReadOnly", &flags, ImGuiInputTextFlags_ReadOnly); + ImGui::CheckboxFlags("ImGuiInputTextFlags_AllowTabInput", &flags, ImGuiInputTextFlags_AllowTabInput); + ImGui::CheckboxFlags("ImGuiInputTextFlags_CtrlEnterForNewLine", &flags, ImGuiInputTextFlags_CtrlEnterForNewLine); ImGui::InputTextMultiline("##source", text, IM_ARRAYSIZE(text), ImVec2(-FLT_MIN, ImGui::GetTextLineHeight() * 16), flags); ImGui::TreePop(); } @@ -1565,13 +1564,13 @@ static void ShowDemoWindowWidgets() { // Demonstrate using advanced flags for DragXXX and SliderXXX functions. Note that the flags are the same! static ImGuiSliderFlags flags = ImGuiSliderFlags_None; - ImGui::CheckboxFlags("ImGuiSliderFlags_AlwaysClamp", (unsigned int*)&flags, ImGuiSliderFlags_AlwaysClamp); + ImGui::CheckboxFlags("ImGuiSliderFlags_AlwaysClamp", &flags, ImGuiSliderFlags_AlwaysClamp); ImGui::SameLine(); HelpMarker("Always clamp value to min/max bounds (if any) when input manually with CTRL+Click."); - ImGui::CheckboxFlags("ImGuiSliderFlags_Logarithmic", (unsigned int*)&flags, ImGuiSliderFlags_Logarithmic); + ImGui::CheckboxFlags("ImGuiSliderFlags_Logarithmic", &flags, ImGuiSliderFlags_Logarithmic); ImGui::SameLine(); HelpMarker("Enable logarithmic editing (more precision for small values)."); - ImGui::CheckboxFlags("ImGuiSliderFlags_NoRoundToFormat", (unsigned int*)&flags, ImGuiSliderFlags_NoRoundToFormat); + ImGui::CheckboxFlags("ImGuiSliderFlags_NoRoundToFormat", &flags, ImGuiSliderFlags_NoRoundToFormat); ImGui::SameLine(); HelpMarker("Disable rounding underlying value to match precision of the format string (e.g. %.3f values are rounded to those 3 digits)."); - ImGui::CheckboxFlags("ImGuiSliderFlags_NoInput", (unsigned int*)&flags, ImGuiSliderFlags_NoInput); + ImGui::CheckboxFlags("ImGuiSliderFlags_NoInput", &flags, ImGuiSliderFlags_NoInput); ImGui::SameLine(); HelpMarker("Disable CTRL+Click or Enter key allowing to input text directly into the widget."); // Drags @@ -2324,15 +2323,15 @@ static void ShowDemoWindowLayout() { // Expose a couple of the available flags. In most cases you may just call BeginTabBar() with no flags (0). static ImGuiTabBarFlags tab_bar_flags = ImGuiTabBarFlags_Reorderable; - ImGui::CheckboxFlags("ImGuiTabBarFlags_Reorderable", (unsigned int*)&tab_bar_flags, ImGuiTabBarFlags_Reorderable); - ImGui::CheckboxFlags("ImGuiTabBarFlags_AutoSelectNewTabs", (unsigned int*)&tab_bar_flags, ImGuiTabBarFlags_AutoSelectNewTabs); - ImGui::CheckboxFlags("ImGuiTabBarFlags_TabListPopupButton", (unsigned int*)&tab_bar_flags, ImGuiTabBarFlags_TabListPopupButton); - ImGui::CheckboxFlags("ImGuiTabBarFlags_NoCloseWithMiddleMouseButton", (unsigned int*)&tab_bar_flags, ImGuiTabBarFlags_NoCloseWithMiddleMouseButton); + ImGui::CheckboxFlags("ImGuiTabBarFlags_Reorderable", &tab_bar_flags, ImGuiTabBarFlags_Reorderable); + ImGui::CheckboxFlags("ImGuiTabBarFlags_AutoSelectNewTabs", &tab_bar_flags, ImGuiTabBarFlags_AutoSelectNewTabs); + ImGui::CheckboxFlags("ImGuiTabBarFlags_TabListPopupButton", &tab_bar_flags, ImGuiTabBarFlags_TabListPopupButton); + ImGui::CheckboxFlags("ImGuiTabBarFlags_NoCloseWithMiddleMouseButton", &tab_bar_flags, ImGuiTabBarFlags_NoCloseWithMiddleMouseButton); if ((tab_bar_flags & ImGuiTabBarFlags_FittingPolicyMask_) == 0) tab_bar_flags |= ImGuiTabBarFlags_FittingPolicyDefault_; - if (ImGui::CheckboxFlags("ImGuiTabBarFlags_FittingPolicyResizeDown", (unsigned int*)&tab_bar_flags, ImGuiTabBarFlags_FittingPolicyResizeDown)) + if (ImGui::CheckboxFlags("ImGuiTabBarFlags_FittingPolicyResizeDown", &tab_bar_flags, ImGuiTabBarFlags_FittingPolicyResizeDown)) tab_bar_flags &= ~(ImGuiTabBarFlags_FittingPolicyMask_ ^ ImGuiTabBarFlags_FittingPolicyResizeDown); - if (ImGui::CheckboxFlags("ImGuiTabBarFlags_FittingPolicyScroll", (unsigned int*)&tab_bar_flags, ImGuiTabBarFlags_FittingPolicyScroll)) + if (ImGui::CheckboxFlags("ImGuiTabBarFlags_FittingPolicyScroll", &tab_bar_flags, ImGuiTabBarFlags_FittingPolicyScroll)) tab_bar_flags &= ~(ImGuiTabBarFlags_FittingPolicyMask_ ^ ImGuiTabBarFlags_FittingPolicyScroll); // Tab Bar @@ -2380,10 +2379,10 @@ static void ShowDemoWindowLayout() // Expose some other flags which are useful to showcase how they interact with Leading/Trailing tabs static ImGuiTabBarFlags tab_bar_flags = ImGuiTabBarFlags_AutoSelectNewTabs | ImGuiTabBarFlags_Reorderable | ImGuiTabBarFlags_FittingPolicyResizeDown; - ImGui::CheckboxFlags("ImGuiTabBarFlags_TabListPopupButton", (unsigned int*)&tab_bar_flags, ImGuiTabBarFlags_TabListPopupButton); - if (ImGui::CheckboxFlags("ImGuiTabBarFlags_FittingPolicyResizeDown", (unsigned int*)&tab_bar_flags, ImGuiTabBarFlags_FittingPolicyResizeDown)) + ImGui::CheckboxFlags("ImGuiTabBarFlags_TabListPopupButton", &tab_bar_flags, ImGuiTabBarFlags_TabListPopupButton); + if (ImGui::CheckboxFlags("ImGuiTabBarFlags_FittingPolicyResizeDown", &tab_bar_flags, ImGuiTabBarFlags_FittingPolicyResizeDown)) tab_bar_flags &= ~(ImGuiTabBarFlags_FittingPolicyMask_ ^ ImGuiTabBarFlags_FittingPolicyResizeDown); - if (ImGui::CheckboxFlags("ImGuiTabBarFlags_FittingPolicyScroll", (unsigned int*)&tab_bar_flags, ImGuiTabBarFlags_FittingPolicyScroll)) + if (ImGui::CheckboxFlags("ImGuiTabBarFlags_FittingPolicyScroll", &tab_bar_flags, ImGuiTabBarFlags_FittingPolicyScroll)) tab_bar_flags &= ~(ImGuiTabBarFlags_FittingPolicyMask_ ^ ImGuiTabBarFlags_FittingPolicyScroll); if (ImGui::BeginTabBar("MyTabBar", tab_bar_flags)) diff --git a/imgui_internal.h b/imgui_internal.h index ff8dbe6f..6b701a0b 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -2044,6 +2044,7 @@ namespace ImGui template IMGUI_API bool DragBehaviorT(ImGuiDataType data_type, T* v, float v_speed, T v_min, T v_max, const char* format, ImGuiSliderFlags flags); template IMGUI_API bool SliderBehaviorT(const ImRect& bb, ImGuiID id, ImGuiDataType data_type, T* v, T v_min, T v_max, const char* format, ImGuiSliderFlags flags, ImRect* out_grab_bb); template IMGUI_API T RoundScalarWithFormatT(const char* format, ImGuiDataType data_type, T v); + template IMGUI_API bool CheckboxFlagsT(const char* label, T* flags, T flags_value); // Data type helpers IMGUI_API const ImGuiDataTypeInfo* DataTypeGetInfo(ImGuiDataType data_type); diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index eed4a048..2c5e1814 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -408,6 +408,7 @@ void ImGui::BulletTextV(const char* fmt, va_list args) // - Image() // - ImageButton() // - Checkbox() +// - CheckboxFlagsT() [Internal] // - CheckboxFlags() // - RadioButton() // - ProgressBar() @@ -1075,6 +1076,7 @@ bool ImGui::Checkbox(const char* label, bool* v) if (mixed_value) { // Undocumented tristate/mixed/indeterminate checkbox (#2644) + // This may seem awkwardly designed because the aim is to make ImGuiItemFlags_MixedValue supported by all widgets (not just checkbox) ImVec2 pad(ImMax(1.0f, IM_FLOOR(square_sz / 3.6f)), ImMax(1.0f, IM_FLOOR(square_sz / 3.6f))); window->DrawList->AddRectFilled(check_bb.Min + pad, check_bb.Max - pad, check_col, style.FrameRounding); } @@ -1093,35 +1095,45 @@ bool ImGui::Checkbox(const char* label, bool* v) return pressed; } -bool ImGui::CheckboxFlags(const char* label, unsigned int* flags, unsigned int flags_value) +template +bool ImGui::CheckboxFlagsT(const char* label, T* flags, T flags_value) { - bool v = ((*flags & flags_value) == flags_value); + bool all_on = (*flags & flags_value) == flags_value; + bool any_on = (*flags & flags_value) != 0; bool pressed; - if (v == false && (*flags & flags_value) != 0) + if (!all_on && any_on) { - // Mixed value (FIXME: find a way to expose neatly to Checkbox?) ImGuiWindow* window = GetCurrentWindow(); - const ImGuiItemFlags backup_item_flags = window->DC.ItemFlags; + ImGuiItemFlags backup_item_flags = window->DC.ItemFlags; window->DC.ItemFlags |= ImGuiItemFlags_MixedValue; - pressed = Checkbox(label, &v); + pressed = Checkbox(label, &all_on); window->DC.ItemFlags = backup_item_flags; } else { - // Regular checkbox - pressed = Checkbox(label, &v); + pressed = Checkbox(label, &all_on); + } if (pressed) { - if (v) + if (all_on) *flags |= flags_value; else *flags &= ~flags_value; } - return pressed; } +bool ImGui::CheckboxFlags(const char* label, int* flags, int flags_value) +{ + return CheckboxFlagsT(label, flags, flags_value); +} + +bool ImGui::CheckboxFlags(const char* label, unsigned int* flags, unsigned int flags_value) +{ + return CheckboxFlagsT(label, flags, flags_value); +} + bool ImGui::RadioButton(const char* label, bool active) { ImGuiWindow* window = GetCurrentWindow(); @@ -5434,7 +5446,7 @@ void ImGui::ColorPickerOptionsPopup(const float* ref_col, ImGuiColorEditFlags fl if (allow_opt_alpha_bar) { if (allow_opt_picker) Separator(); - CheckboxFlags("Alpha Bar", (unsigned int*)&g.ColorEditOptions, ImGuiColorEditFlags_AlphaBar); + CheckboxFlags("Alpha Bar", &g.ColorEditOptions, ImGuiColorEditFlags_AlphaBar); } EndPopup(); }