From 7baf45cffac4a434cb36c3342a3fd88271ce2351 Mon Sep 17 00:00:00 2001 From: omar Date: Tue, 16 Apr 2019 22:02:30 +0200 Subject: [PATCH 01/13] Metrics: Added "Show windows rectangles" tool to visualize the different rectangles. --- docs/CHANGELOG.txt | 1 + imgui.cpp | 85 +++++++++++++++++++++++++++++++++------------- imgui_widgets.cpp | 2 +- 3 files changed, 63 insertions(+), 25 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index a91fd118..16681c6e 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -53,6 +53,7 @@ Other Changes: - Window: Window close button is horizontally aligned with style.FramePadding.x. - Misc: Added IM_MALLOC/IM_FREE macros mimicking IM_NEW/IM_DELETE so user doesn't need to revert to using the ImGui::MemAlloc()/MemFree() calls directly. +- Metrics: Added "Show windows rectangles" tool to visualize the different rectangles. - Examples: OpenGL: Added a dummy GL call + comments in ImGui_ImplOpenGL3_Init() to detect uninitialized GL function loaders early, and help users understand what they are missing. (#2421) - Examples: Emscripten: Added Emscripten+SDL+GLES2 example. (#2494, #2492, #2351, #336) [@nicolasnoble] diff --git a/imgui.cpp b/imgui.cpp index ee5f6c73..1ab21c7d 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -9500,16 +9500,18 @@ void ImGui::ShowMetricsWindow(bool* p_open) return; } - static bool show_draw_cmd_clip_rects = true; - static bool show_window_begin_order = false; + enum { RT_OuterRect, RT_OuterRectClipped, RT_InnerMainRect, RT_InnerClipRect, RT_ContentsRegionRect, RT_ContentsFullRect }; + static bool show_windows_begin_order = false; + static bool show_windows_rects = false; + static int show_windows_rect_type = RT_ContentsRegionRect; + static bool show_drawcmd_clip_rects = true; + ImGuiIO& io = ImGui::GetIO(); ImGui::Text("Dear ImGui %s", ImGui::GetVersion()); ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", 1000.0f / io.Framerate, io.Framerate); ImGui::Text("%d vertices, %d indices (%d triangles)", io.MetricsRenderVertices, io.MetricsRenderIndices, io.MetricsRenderIndices / 3); ImGui::Text("%d active windows (%d visible)", io.MetricsActiveWindows, io.MetricsRenderWindows); - ImGui::Text("%d allocations", io.MetricsActiveAllocations); - ImGui::Checkbox("Show clipping rectangles when hovering draw commands", &show_draw_cmd_clip_rects); - ImGui::Checkbox("Ctrl shows window begin order", &show_window_begin_order); + ImGui::Text("%d active allocations", io.MetricsActiveAllocations); ImGui::Separator(); struct Funcs @@ -9543,7 +9545,7 @@ void ImGui::ShowMetricsWindow(bool* p_open) } 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); - if (show_draw_cmd_clip_rects && fg_draw_list && ImGui::IsItemHovered()) + if (show_drawcmd_clip_rects && fg_draw_list && ImGui::IsItemHovered()) { ImRect clip_rect = pcmd->ClipRect; ImRect vtxs_rect; @@ -9585,6 +9587,16 @@ void ImGui::ShowMetricsWindow(bool* p_open) ImGui::TreePop(); } + static void NodeColumns(const ImGuiColumns* columns) + { + if (!ImGui::TreeNode((void*)(uintptr_t)columns->ID, "Columns Id: 0x%08X, Count: %d, Flags: 0x%04X", columns->ID, columns->Count, columns->Flags)) + return; + ImGui::BulletText("Width: %.1f (MinX: %.1f, MaxX: %.1f)", columns->MaxX - columns->MinX, columns->MinX, columns->MaxX); + for (int column_n = 0; column_n < columns->Columns.Size; column_n++) + ImGui::BulletText("Column %02d: OffsetNorm %.3f (= %.1f px)", column_n, columns->Columns[column_n].OffsetNorm, OffsetNormToPixels(columns, columns->Columns[column_n].OffsetNorm)); + ImGui::TreePop(); + } + static void NodeWindows(ImVector& windows, const char* label) { if (!ImGui::TreeNode(label, "%s (%d)", label, windows.Size)) @@ -9596,8 +9608,15 @@ void ImGui::ShowMetricsWindow(bool* p_open) static void NodeWindow(ImGuiWindow* window, const char* label) { - if (!ImGui::TreeNode(window, "%s '%s', %d @ 0x%p", label, window->Name, window->Active || window->WasActive, window)) + bool node_open = ImGui::TreeNode(window, "%s '%s', %d @ 0x%p", label, window->Name, window->Active || window->WasActive, window); + if (show_windows_rects && ImGui::IsItemHovered()) + if (ImDrawList* fg_draw_list = GetForegroundDrawList(window)) + { + } + + if (!node_open) return; + ImGuiWindowFlags flags = window->Flags; NodeDrawList(window, window->DrawList, "DrawList"); ImGui::BulletText("Pos: (%.1f,%.1f), Size: (%.1f,%.1f), SizeContents (%.1f,%.1f)", window->Pos.x, window->Pos.y, window->Size.x, window->Size.y, window->SizeContents.x, window->SizeContents.y); @@ -9620,16 +9639,7 @@ void ImGui::ShowMetricsWindow(bool* p_open) if (window->ColumnsStorage.Size > 0 && ImGui::TreeNode("Columns", "Columns sets (%d)", window->ColumnsStorage.Size)) { for (int n = 0; n < window->ColumnsStorage.Size; n++) - { - const ImGuiColumns* columns = &window->ColumnsStorage[n]; - if (ImGui::TreeNode((void*)(uintptr_t)columns->ID, "Columns Id: 0x%08X, Count: %d, Flags: 0x%04X", columns->ID, columns->Count, columns->Flags)) - { - ImGui::BulletText("Width: %.1f (MinX: %.1f, MaxX: %.1f)", columns->MaxX - columns->MinX, columns->MinX, columns->MaxX); - for (int column_n = 0; column_n < columns->Columns.Size; column_n++) - ImGui::BulletText("Column %02d: OffsetNorm %.3f (= %.1f px)", column_n, columns->Columns[column_n].OffsetNorm, OffsetNormToPixels(columns, columns->Columns[column_n].OffsetNorm)); - ImGui::TreePop(); - } - } + NodeColumns(&window->ColumnsStorage[n]); ImGui::TreePop(); } ImGui::BulletText("Storage: %d bytes", window->StateStorage.Data.Size * (int)sizeof(ImGuiStorage::Pair)); @@ -9668,6 +9678,7 @@ void ImGui::ShowMetricsWindow(bool* p_open) Funcs::NodeDrawList(NULL, g.DrawDataBuilder.Layers[0][i], "DrawList"); ImGui::TreePop(); } + if (ImGui::TreeNode("Popups", "Popups (%d)", g.OpenPopupStack.Size)) { for (int i = 0; i < g.OpenPopupStack.Size; i++) @@ -9677,12 +9688,14 @@ void ImGui::ShowMetricsWindow(bool* p_open) } ImGui::TreePop(); } + if (ImGui::TreeNode("TabBars", "Tab Bars (%d)", g.TabBars.Data.Size)) { for (int n = 0; n < g.TabBars.Data.Size; n++) Funcs::NodeTabBar(g.TabBars.GetByIndex(n)); ImGui::TreePop(); } + if (ImGui::TreeNode("Internal state")) { const char* input_source_names[] = { "None", "Mouse", "Nav", "NavKeyboard", "NavGamepad" }; IM_ASSERT(IM_ARRAYSIZE(input_source_names) == ImGuiInputSource_COUNT); @@ -9703,20 +9716,44 @@ void ImGui::ShowMetricsWindow(bool* p_open) ImGui::TreePop(); } + if (ImGui::TreeNode("Tools")) + { + ImGui::Checkbox("Show windows begin order", &show_windows_begin_order); + ImGui::Checkbox("Show windows rectangles", &show_windows_rects); + ImGui::SameLine(); + ImGui::PushItemWidth(ImGui::GetFontSize() * 12); + show_windows_rects |= ImGui::Combo("##rects_type", &show_windows_rect_type, "OuterRect\0" "OuterRectClipped\0" "InnerMainRect\0" "InnerClipRect\0" "ContentsRegionRect\0"); + ImGui::PopItemWidth(); + ImGui::Checkbox("Show clipping rectangle when hovering ImDrawCmd node", &show_drawcmd_clip_rects); + ImGui::TreePop(); + } - if (g.IO.KeyCtrl && show_window_begin_order) + if (show_windows_rects || show_windows_begin_order) { for (int n = 0; n < g.Windows.Size; n++) { ImGuiWindow* window = g.Windows[n]; if ((window->Flags & ImGuiWindowFlags_ChildWindow) || !window->WasActive) continue; - char buf[32]; - ImFormatString(buf, IM_ARRAYSIZE(buf), "%d", window->BeginOrderWithinContext); - float font_size = ImGui::GetFontSize() * 2; - ImDrawList* fg_draw_list = GetForegroundDrawList(window); - fg_draw_list->AddRectFilled(window->Pos, window->Pos + ImVec2(font_size, font_size), IM_COL32(200, 100, 100, 255)); - fg_draw_list->AddText(NULL, font_size, window->Pos, IM_COL32(255, 255, 255, 255), buf); + ImDrawList* draw_list = GetForegroundDrawList(window); + if (show_windows_rects) + { + ImRect r; + if (show_windows_rect_type == RT_OuterRect) { r = window->Rect(); } + else if (show_windows_rect_type == RT_OuterRectClipped) { r = window->OuterRectClipped; } + else if (show_windows_rect_type == RT_InnerMainRect) { r = window->InnerMainRect; } + else if (show_windows_rect_type == RT_InnerClipRect) { r = window->InnerClipRect; } + else if (show_windows_rect_type == RT_ContentsRegionRect) { r = window->ContentsRegionRect; } + draw_list->AddRect(r.Min, r.Max, IM_COL32(255, 0, 128, 255)); + } + if (show_windows_begin_order) + { + char buf[32]; + ImFormatString(buf, IM_ARRAYSIZE(buf), "%d", window->BeginOrderWithinContext); + float font_size = ImGui::GetFontSize(); + draw_list->AddRectFilled(window->Pos, window->Pos + ImVec2(font_size, font_size), IM_COL32(200, 100, 100, 255)); + draw_list->AddText(window->Pos, IM_COL32(255, 255, 255, 255), buf); + } } } ImGui::End(); diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index b209f033..c9a47b14 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -793,7 +793,7 @@ void ImGui::Scrollbar(ImGuiAxis axis) ? ImRect(window->Pos.x + border_size, window_rect.Max.y - style.ScrollbarSize, window_rect.Max.x - other_scrollbar_size_w - border_size, window_rect.Max.y - border_size) : ImRect(window_rect.Max.x - style.ScrollbarSize, window->Pos.y + border_size, window_rect.Max.x - border_size, window_rect.Max.y - other_scrollbar_size_w - border_size); if (!horizontal) - bb.Min.y += window->TitleBarHeight() + ((window->Flags & ImGuiWindowFlags_MenuBar) ? window->MenuBarHeight() : 0.0f); + bb.Min.y += window->TitleBarHeight() + ((window->Flags & ImGuiWindowFlags_MenuBar) ? window->MenuBarHeight() : 0.0f); // FIXME: InnerRect? const float bb_height = bb.GetHeight(); if (bb.GetWidth() <= 0.0f || bb_height <= 0.0f) From 1f25cdd6b4b92bc557ab15d45fb5d4f92320fea9 Mon Sep 17 00:00:00 2001 From: omar Date: Wed, 17 Apr 2019 09:59:03 +0200 Subject: [PATCH 02/13] Clarified asserts comments + todo entries. (#2500) --- docs/TODO.txt | 5 ++++- examples/imgui_impl_metal.mm | 2 +- imgui.cpp | 6 +++--- 3 files changed, 8 insertions(+), 5 deletions(-) diff --git a/docs/TODO.txt b/docs/TODO.txt index a837b8b5..279342ca 100644 --- a/docs/TODO.txt +++ b/docs/TODO.txt @@ -28,13 +28,14 @@ It's mostly a bunch of personal notes, probably incomplete. Feel free to query i - window/opt: freeze window flag: if not focused/hovered, return false, render with previous ImDrawList. and/or reduce refresh rate. -> this may require enforcing that it is illegal to submit contents if Begin returns false. - window/child: the first draw command of a child window could be moved into the current draw command of the parent window (unless child+tooltip?). - window/clipping: some form of clipping when DisplaySize (or corresponding viewport) is zero. + - window/tab: add a way to signify that a window or docked window requires attention (e.g. blinking title bar). - scrolling: while holding down a scrollbar, try to keep the same contents visible (at least while not moving mouse) - scrolling: allow immediately effective change of scroll after Begin() if we haven't appended items yet. - scrolling/clipping: separator on the initial position of a window is not visible (cursorpos.y <= clippos.y). (2017-08-20: can't repro) - scrolling/style: shadows on scrollable areas to denote that there is more contents - drawdata: make it easy to clone (or swap?) a ImDrawData so user can easily save that data if they use threaded rendering. - - drawlist: add calctextsize func to facilitate consistent code from user pov + ! drawlist: add calctextsize func to facilitate consistent code from user pov (currently need to use ImGui or ImFont alternatives!) - drawlist: end-user probably can't call Clear() directly because we expect a texture to be pushed in the stack. - drawlist: maintaining bounding box per command would allow to merge draw command when clipping isn't relied on (typical non-scrolling window or non-overflowing column would merge with previous command). - drawlist: primitives/helpers to manipulate vertices post submission, so e.g. a quad/rect can be resized to fit later submitted content, _without_ using the ChannelSplit api @@ -44,6 +45,7 @@ It's mostly a bunch of personal notes, probably incomplete. Feel free to query i - drawlist: rendering: provide a way for imgui to output to a single/global vertex buffer, re-order indices only at the end of the frame (ref: https://gist.github.com/floooh/10388a0afbe08fce9e617d8aefa7d302) - drawlist: callback: add an extra void* in ImDrawCallback to allow passing render-local data to the callback (would break API). - drawlist: AddRect vs AddLine position confusing (#2441) + - drawlist: channel splitter should be external helper and not stored in ImDrawList. - drawlist/opt: store rounded corners in texture to use 1 quad per corner (filled and wireframe) to lower the cost of rounding. (#1962) - drawlist/opt: AddRect() axis aligned pixel aligned (no-aa) could use 8 triangles instead of 16 and no normal calculation. - drawlist/opt: thick AA line could be doable in same number of triangles as 1.0 AA line by storing gradient+full color in atlas. @@ -330,6 +332,7 @@ It's mostly a bunch of personal notes, probably incomplete. Feel free to query i - examples: glfw: could go idle when minimized? if (glfwGetWindowAttrib(window, GLFW_ICONIFIED)) { glfwWaitEvents(); continue; } // issue: DeltaTime will be super high on resume, perhaps provide a way to let impl know (#440) - examples: opengl: rename imgui_impl_opengl2 to impl_opengl_legacy and imgui_impl_opengl3 to imgui_impl_opengl? (#1900) - examples: opengl: could use a single vertex buffer and glBufferSubData for uploads? + - examples: opengl: explicitly disable GL_STENCIL_TEST in bindings. - examples: vulkan: viewport: support for synchronized swapping of multiple swap chains. - optimization: replace vsnprintf with stb_printf? or enable the defines/infrastructure to allow it (#1038) - optimization: add clipping for multi-component widgets (SliderFloatX, ColorEditX, etc.). one problem is that nav branch can't easily clip parent group when there is a move request. diff --git a/examples/imgui_impl_metal.mm b/examples/imgui_impl_metal.mm index c04ecbf1..c559590b 100644 --- a/examples/imgui_impl_metal.mm +++ b/examples/imgui_impl_metal.mm @@ -87,7 +87,7 @@ void ImGui_ImplMetal_Shutdown() void ImGui_ImplMetal_NewFrame(MTLRenderPassDescriptor *renderPassDescriptor) { - IM_ASSERT(g_sharedMetalContext != nil && "No Metal context. Did you call ImGui_ImplMetal_Init?"); + IM_ASSERT(g_sharedMetalContext != nil && "No Metal context. Did you call ImGui_ImplMetal_Init() ?"); g_sharedMetalContext.framebufferDescriptor = [[FramebufferDescriptor alloc] initWithRenderPassDescriptor:renderPassDescriptor]; } diff --git a/imgui.cpp b/imgui.cpp index 1ab21c7d..23e3c8ef 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -3091,13 +3091,13 @@ void ImGui::DestroyContext(ImGuiContext* ctx) ImGuiIO& ImGui::GetIO() { - IM_ASSERT(GImGui != NULL && "No current context. Did you call ImGui::CreateContext() or ImGui::SetCurrentContext()?"); + IM_ASSERT(GImGui != NULL && "No current context. Did you call ImGui::CreateContext() and ImGui::SetCurrentContext() ?"); return GImGui->IO; } ImGuiStyle& ImGui::GetStyle() { - IM_ASSERT(GImGui != NULL && "No current context. Did you call ImGui::CreateContext() or ImGui::SetCurrentContext()?"); + IM_ASSERT(GImGui != NULL && "No current context. Did you call ImGui::CreateContext() and ImGui::SetCurrentContext() ?"); return GImGui->Style; } @@ -3424,7 +3424,7 @@ void ImGui::UpdateHoveredWindowAndCaptureFlags() void ImGui::NewFrame() { - IM_ASSERT(GImGui != NULL && "No current context. Did you call ImGui::CreateContext() or ImGui::SetCurrentContext()?"); + IM_ASSERT(GImGui != NULL && "No current context. Did you call ImGui::CreateContext() and ImGui::SetCurrentContext() ?"); ImGuiContext& g = *GImGui; #ifdef IMGUI_ENABLE_TEST_ENGINE From 74a3878be4a5e123ab21d71f94664eb3d4c05c7e Mon Sep 17 00:00:00 2001 From: Andre Weissflog Date: Mon, 15 Apr 2019 20:55:52 +0200 Subject: [PATCH 03/13] emscripten: replace shell_minimal.html with 'soft fullscreen' version --- .../example_emscripten/shell_minimal.html | 155 ++++-------------- 1 file changed, 33 insertions(+), 122 deletions(-) diff --git a/examples/example_emscripten/shell_minimal.html b/examples/example_emscripten/shell_minimal.html index aab79f1b..514385d7 100644 --- a/examples/example_emscripten/shell_minimal.html +++ b/examples/example_emscripten/shell_minimal.html @@ -2,150 +2,61 @@ - + Dear ImGui Emscripten example -
emscripten
-
Downloading...
-
- -
-
- - Example compiled from https://github.com/ocornut/imgui -
-
-
- - -
-
- - + {{{ SCRIPT }}} From 1d3ebef364ebec80a3e9b70cc46071f65382339d Mon Sep 17 00:00:00 2001 From: omar Date: Wed, 17 Apr 2019 21:50:15 +0200 Subject: [PATCH 04/13] Columns: Fixed boundary of clipping being off by 1 pixel within the left column. --- docs/CHANGELOG.txt | 1 + imgui.cpp | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 16681c6e..c5ecdfe3 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -51,6 +51,7 @@ Other Changes: - Inputs: Also add support for horizontal scroll with Shift+Mouse Wheel. (#2424, #1463) [@LucaRood] - PlotLines, PlotHistogram: Ignore NaN values when calculating min/max bounds. (#2485) - Window: Window close button is horizontally aligned with style.FramePadding.x. +- Columns: Fixed boundary of clipping being off by 1 pixel within the left column. - Misc: Added IM_MALLOC/IM_FREE macros mimicking IM_NEW/IM_DELETE so user doesn't need to revert to using the ImGui::MemAlloc()/MemFree() calls directly. - Metrics: Added "Show windows rectangles" tool to visualize the different rectangles. diff --git a/imgui.cpp b/imgui.cpp index 23e3c8ef..e12c466c 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -8542,7 +8542,7 @@ void ImGui::BeginColumns(const char* str_id, int columns_count, ImGuiColumnsFlag { // Compute clipping rectangle ImGuiColumnData* column = &columns->Columns[n]; - float clip_x1 = ImFloor(0.5f + window->Pos.x + GetColumnOffset(n) - 1.0f); + float clip_x1 = ImFloor(0.5f + window->Pos.x + GetColumnOffset(n)); float clip_x2 = ImFloor(0.5f + window->Pos.x + GetColumnOffset(n + 1) - 1.0f); column->ClipRect = ImRect(clip_x1, -FLT_MAX, clip_x2, +FLT_MAX); column->ClipRect.ClipWith(window->ClipRect); From 1aeee9d40f7e057230d22f1c5c4b476a00e9dbe7 Mon Sep 17 00:00:00 2001 From: omar Date: Wed, 17 Apr 2019 12:26:51 +0200 Subject: [PATCH 05/13] Internals: Columns: Tweaks, renaming. Metrics: Show rectangles for child windows. Renamed SameLine() first parameter. --- imgui.cpp | 68 ++++++++++++++++++++++------------------------- imgui.h | 2 +- imgui_demo.cpp | 3 ++- imgui_internal.h | 12 ++++----- imgui_widgets.cpp | 3 ++- 5 files changed, 43 insertions(+), 45 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index e12c466c..18b368d5 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -6740,21 +6740,21 @@ void ImGui::EndGroup() } // Gets back to previous line and continue with horizontal layout -// pos_x == 0 : follow right after previous item -// pos_x != 0 : align to specified x position (relative to window/group left) -// spacing_w < 0 : use default spacing if pos_x == 0, no spacing if pos_x != 0 -// spacing_w >= 0 : enforce spacing amount -void ImGui::SameLine(float pos_x, float spacing_w) +// offset_from_start_x == 0 : follow right after previous item +// offset_from_start_x != 0 : align to specified x position (relative to window/group left) +// spacing_w < 0 : use default spacing if pos_x == 0, no spacing if pos_x != 0 +// spacing_w >= 0 : enforce spacing amount +void ImGui::SameLine(float offset_from_start_x, float spacing_w) { ImGuiWindow* window = GetCurrentWindow(); if (window->SkipItems) return; ImGuiContext& g = *GImGui; - if (pos_x != 0.0f) + if (offset_from_start_x != 0.0f) { if (spacing_w < 0.0f) spacing_w = 0.0f; - window->DC.CursorPos.x = window->Pos.x - window->Scroll.x + pos_x + spacing_w + window->DC.GroupOffset.x + window->DC.ColumnsOffset.x; + window->DC.CursorPos.x = window->Pos.x - window->Scroll.x + offset_from_start_x + spacing_w + window->DC.GroupOffset.x + window->DC.ColumnsOffset.x; window->DC.CursorPos.y = window->DC.CursorPosPrevLine.y; } else @@ -8322,13 +8322,13 @@ void ImGui::NextColumn() columns->LineMaxY = ImMax(columns->LineMaxY, window->DC.CursorPos.y); if (++columns->Current < columns->Count) { - // Columns 1+ cancel out IndentX + // New column (columns 1+ cancels out IndentX) window->DC.ColumnsOffset.x = GetColumnOffset(columns->Current) - window->DC.Indent.x + g.Style.ItemSpacing.x; window->DrawList->ChannelsSetCurrent(columns->Current); } else { - // New line + // New row/line window->DC.ColumnsOffset.x = 0.0f; window->DrawList->ChannelsSetCurrent(0); columns->Current = 0; @@ -8340,7 +8340,7 @@ void ImGui::NextColumn() window->DC.CurrentLineTextBaseOffset = 0.0f; PushColumnClipRect(); - PushItemWidth(GetColumnWidth() * 0.65f); // FIXME: Move on columns setup + PushItemWidth(GetColumnWidth() * 0.65f); // FIXME-COLUMNS: Move on columns setup } int ImGui::GetColumnIndex() @@ -8365,7 +8365,7 @@ static float PixelsToOffsetNorm(const ImGuiColumns* columns, float offset) return offset / (columns->MaxX - columns->MinX); } -static inline float GetColumnsRectHalfWidth() { return 4.0f; } +static const float COLUMNS_HIT_RECT_HALF_WIDTH = 4.0f; static float GetDraggedColumnOffset(ImGuiColumns* columns, int column_index) { @@ -8376,7 +8376,7 @@ static float GetDraggedColumnOffset(ImGuiColumns* columns, int column_index) IM_ASSERT(column_index > 0); // We are not supposed to drag column 0. IM_ASSERT(g.ActiveId == columns->ID + ImGuiID(column_index)); - float x = g.IO.MousePos.x - g.ActiveIdClickOffset.x + GetColumnsRectHalfWidth() - window->Pos.x; + float x = g.IO.MousePos.x - g.ActiveIdClickOffset.x + COLUMNS_HIT_RECT_HALF_WIDTH - window->Pos.x; x = ImMax(x, ImGui::GetColumnOffset(column_index - 1) + g.Style.ColumnsMinSpacing); if ((columns->Flags & ImGuiColumnsFlags_NoPreserveWidths)) x = ImMin(x, ImGui::GetColumnOffset(column_index + 1) - g.Style.ColumnsMinSpacing); @@ -8515,8 +8515,8 @@ void ImGui::BeginColumns(const char* str_id, int columns_count, ImGuiColumnsFlag const float content_region_width = (window->SizeContentsExplicit.x != 0.0f) ? (window->SizeContentsExplicit.x) : (window->InnerClipRect.Max.x - window->Pos.x); columns->MinX = window->DC.Indent.x - g.Style.ItemSpacing.x; // Lock our horizontal range columns->MaxX = ImMax(content_region_width - window->Scroll.x, columns->MinX + 1.0f); - columns->StartPosY = window->DC.CursorPos.y; - columns->StartMaxPosX = window->DC.CursorMaxPos.x; + columns->BackupCursorPosY = window->DC.CursorPos.y; + columns->BackupCursorMaxPosX = window->DC.CursorMaxPos.x; columns->LineMinY = columns->LineMaxY = window->DC.CursorPos.y; window->DC.ColumnsOffset.x = 0.0f; window->DC.CursorPos.x = (float)(int)(window->Pos.x + window->DC.Indent.x + window->DC.ColumnsOffset.x); @@ -8573,39 +8573,41 @@ void ImGui::EndColumns() columns->LineMaxY = ImMax(columns->LineMaxY, window->DC.CursorPos.y); window->DC.CursorPos.y = columns->LineMaxY; if (!(columns->Flags & ImGuiColumnsFlags_GrowParentContentsSize)) - window->DC.CursorMaxPos.x = columns->StartMaxPosX; // Restore cursor max pos, as columns don't grow parent + window->DC.CursorMaxPos.x = columns->BackupCursorMaxPosX; // Restore cursor max pos, as columns don't grow parent // Draw columns borders and handle resize bool is_being_resized = false; if (!(columns->Flags & ImGuiColumnsFlags_NoBorder) && !window->SkipItems) { - const float y1 = columns->StartPosY; - const float y2 = window->DC.CursorPos.y; + // We clip Y boundaries CPU side because very long triangles are mishandled by some GPU drivers. + const float y1 = ImMax(columns->BackupCursorPosY, window->ClipRect.Min.y); + const float y2 = ImMin(window->DC.CursorPos.y, window->ClipRect.Max.y); int dragging_column = -1; for (int n = 1; n < columns->Count; n++) { + ImGuiColumnData* column = &columns->Columns[n]; float x = window->Pos.x + GetColumnOffset(n); const ImGuiID column_id = columns->ID + ImGuiID(n); - const float column_hw = GetColumnsRectHalfWidth(); // Half-width for interaction - const ImRect column_rect(ImVec2(x - column_hw, y1), ImVec2(x + column_hw, y2)); + const float column_hit_hw = COLUMNS_HIT_RECT_HALF_WIDTH; + const ImRect column_hit_rect(ImVec2(x - column_hit_hw, y1), ImVec2(x + column_hit_hw, y2)); KeepAliveID(column_id); - if (IsClippedEx(column_rect, column_id, false)) + if (IsClippedEx(column_hit_rect, column_id, false)) continue; bool hovered = false, held = false; if (!(columns->Flags & ImGuiColumnsFlags_NoResize)) { - ButtonBehavior(column_rect, column_id, &hovered, &held); + ButtonBehavior(column_hit_rect, column_id, &hovered, &held); if (hovered || held) g.MouseCursor = ImGuiMouseCursor_ResizeEW; - if (held && !(columns->Columns[n].Flags & ImGuiColumnsFlags_NoResize)) + if (held && !(column->Flags & ImGuiColumnsFlags_NoResize)) dragging_column = n; } - // Draw column (we clip the Y boundaries CPU side because very long triangles are mishandled by some GPU drivers.) + // Draw column const ImU32 col = GetColorU32(held ? ImGuiCol_SeparatorActive : hovered ? ImGuiCol_SeparatorHovered : ImGuiCol_Separator); const float xi = (float)(int)x; - window->DrawList->AddLine(ImVec2(xi, ImMax(y1 + 1.0f, window->ClipRect.Min.y)), ImVec2(xi, ImMin(y2, window->ClipRect.Max.y)), col); + window->DrawList->AddLine(ImVec2(xi, y1 + 1.0f), ImVec2(xi, y2), col); } // Apply dragging after drawing the column lines, so our rendered lines are in sync with how items were displayed during the frame. @@ -8634,10 +8636,11 @@ void ImGui::Columns(int columns_count, const char* id, bool border) ImGuiColumnsFlags flags = (border ? 0 : ImGuiColumnsFlags_NoBorder); //flags |= ImGuiColumnsFlags_NoPreserveWidths; // NB: Legacy behavior - if (window->DC.CurrentColumns != NULL && window->DC.CurrentColumns->Count == columns_count && window->DC.CurrentColumns->Flags == flags) + ImGuiColumns* columns = window->DC.CurrentColumns; + if (columns != NULL && columns->Count == columns_count && columns->Flags == flags) return; - if (window->DC.CurrentColumns != NULL) + if (columns != NULL) EndColumns(); if (columns_count != 1) @@ -9608,15 +9611,8 @@ void ImGui::ShowMetricsWindow(bool* p_open) static void NodeWindow(ImGuiWindow* window, const char* label) { - bool node_open = ImGui::TreeNode(window, "%s '%s', %d @ 0x%p", label, window->Name, window->Active || window->WasActive, window); - if (show_windows_rects && ImGui::IsItemHovered()) - if (ImDrawList* fg_draw_list = GetForegroundDrawList(window)) - { - } - - if (!node_open) + if (!ImGui::TreeNode(window, "%s '%s', %d @ 0x%p", label, window->Name, window->Active || window->WasActive, window)) return; - ImGuiWindowFlags flags = window->Flags; NodeDrawList(window, window->DrawList, "DrawList"); ImGui::BulletText("Pos: (%.1f,%.1f), Size: (%.1f,%.1f), SizeContents (%.1f,%.1f)", window->Pos.x, window->Pos.y, window->Size.x, window->Size.y, window->SizeContents.x, window->SizeContents.y); @@ -9733,7 +9729,7 @@ void ImGui::ShowMetricsWindow(bool* p_open) for (int n = 0; n < g.Windows.Size; n++) { ImGuiWindow* window = g.Windows[n]; - if ((window->Flags & ImGuiWindowFlags_ChildWindow) || !window->WasActive) + if (!window->WasActive) continue; ImDrawList* draw_list = GetForegroundDrawList(window); if (show_windows_rects) @@ -9746,7 +9742,7 @@ void ImGui::ShowMetricsWindow(bool* p_open) else if (show_windows_rect_type == RT_ContentsRegionRect) { r = window->ContentsRegionRect; } draw_list->AddRect(r.Min, r.Max, IM_COL32(255, 0, 128, 255)); } - if (show_windows_begin_order) + if (show_windows_begin_order && !(window->Flags & ImGuiWindowFlags_ChildWindow)) { char buf[32]; ImFormatString(buf, IM_ARRAYSIZE(buf), "%d", window->BeginOrderWithinContext); diff --git a/imgui.h b/imgui.h index c4400d84..f11a3a50 100644 --- a/imgui.h +++ b/imgui.h @@ -332,7 +332,7 @@ namespace ImGui // - By "cursor" we mean the current output position. // - The typical widget behavior is to output themselves at the current cursor position, then move the cursor one line down. IMGUI_API void Separator(); // separator, generally horizontal. inside a menu bar or in horizontal layout mode, this becomes a vertical separator. - IMGUI_API void SameLine(float local_pos_x = 0.0f, float spacing_w = -1.0f); // call between widgets or groups to layout them horizontally. X position given in window coordinates. + IMGUI_API void SameLine(float offset_from_start_x=0.0f, float spacing=-1.0f); // call between widgets or groups to layout them horizontally. X position given in window coordinates. IMGUI_API void NewLine(); // undo a SameLine() or force a new line when in an horizontal-layout context. IMGUI_API void Spacing(); // add vertical spacing. IMGUI_API void Dummy(const ImVec2& size); // add a dummy item of given size. unlike InvisibleButton(), Dummy() won't take the mouse click or be navigable into. diff --git a/imgui_demo.cpp b/imgui_demo.cpp index 9b732c3f..443c3c23 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -252,7 +252,6 @@ void ImGui::ShowDemoWindow(bool* p_open) ImGui::End(); return; } - ImGui::Text("dear imgui says hello. (%s)", IMGUI_VERSION); // Most "big" widgets share a common width settings by default. //ImGui::PushItemWidth(ImGui::GetWindowWidth() * 0.65f); // Use 2/3 of the space for widgets and 1/3 for labels (default) @@ -292,7 +291,9 @@ void ImGui::ShowDemoWindow(bool* p_open) ImGui::EndMenuBar(); } + ImGui::Text("dear imgui says hello. (%s)", IMGUI_VERSION); ImGui::Spacing(); + if (ImGui::CollapsingHeader("Help")) { ImGui::Text("PROGRAMMER GUIDE:"); diff --git a/imgui_internal.h b/imgui_internal.h index 1b0fd35c..7ed26cfd 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -658,7 +658,7 @@ struct ImGuiColumnData ImGuiColumnsFlags Flags; // Not exposed ImRect ClipRect; - ImGuiColumnData() { OffsetNorm = OffsetNormBeforeResize = 0.0f; Flags = 0; } + ImGuiColumnData() { OffsetNorm = OffsetNormBeforeResize = 0.0f; Flags = ImGuiColumnsFlags_None; } }; struct ImGuiColumns @@ -671,23 +671,23 @@ struct ImGuiColumns int Count; float MinX, MaxX; float LineMinY, LineMaxY; - float StartPosY; // Copy of CursorPos - float StartMaxPosX; // Copy of CursorMaxPos + float BackupCursorPosY; // Backup of CursorPos at the time of BeginColumns() + float BackupCursorMaxPosX; // Backup of CursorMaxPos at the time of BeginColumns() ImVector Columns; ImGuiColumns() { Clear(); } void Clear() { ID = 0; - Flags = 0; + Flags = ImGuiColumnsFlags_None; IsFirstFrame = false; IsBeingResized = false; Current = 0; Count = 1; MinX = MaxX = 0.0f; LineMinY = LineMaxY = 0.0f; - StartPosY = 0.0f; - StartMaxPosX = 0.0f; + BackupCursorPosY = 0.0f; + BackupCursorMaxPosX = 0.0f; Columns.clear(); } }; diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index c9a47b14..dd821ef5 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -299,7 +299,8 @@ void ImGui::TextWrapped(const char* fmt, ...) void ImGui::TextWrappedV(const char* fmt, va_list args) { - bool need_backup = (GImGui->CurrentWindow->DC.TextWrapPos < 0.0f); // Keep existing wrap position if one is already set + ImGuiWindow* window = GetCurrentWindow(); + bool need_backup = (window->DC.TextWrapPos < 0.0f); // Keep existing wrap position if one is already set if (need_backup) PushTextWrapPos(0.0f); TextV(fmt, args); From 240dddff87326abb9990fc938dfe9ced6ad79d9e Mon Sep 17 00:00:00 2001 From: omar Date: Thu, 18 Apr 2019 15:00:40 +0200 Subject: [PATCH 06/13] Combo, Slider: Improve rendering in situation when there's there's very little space available. --- docs/CHANGELOG.txt | 1 + imgui_widgets.cpp | 64 +++++++++++++++++++++++++++------------------- 2 files changed, 39 insertions(+), 26 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index c5ecdfe3..c9401b3a 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -52,6 +52,7 @@ Other Changes: - PlotLines, PlotHistogram: Ignore NaN values when calculating min/max bounds. (#2485) - Window: Window close button is horizontally aligned with style.FramePadding.x. - Columns: Fixed boundary of clipping being off by 1 pixel within the left column. +- Combo, Slider, Scrollbar: Improve rendering in situation when there's only a few pixels available (<3 pixels). - Misc: Added IM_MALLOC/IM_FREE macros mimicking IM_NEW/IM_DELETE so user doesn't need to revert to using the ImGui::MemAlloc()/MemFree() calls directly. - Metrics: Added "Show windows rectangles" tool to visualize the different rectangles. diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index dd821ef5..2e93b853 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -788,16 +788,19 @@ void ImGui::Scrollbar(ImGuiAxis axis) // Render background bool other_scrollbar = (horizontal ? window->ScrollbarY : window->ScrollbarX); float other_scrollbar_size_w = other_scrollbar ? style.ScrollbarSize : 0.0f; - const ImRect window_rect = window->Rect(); + const ImRect host_rect = window->Rect(); const float border_size = window->WindowBorderSize; ImRect bb = horizontal - ? ImRect(window->Pos.x + border_size, window_rect.Max.y - style.ScrollbarSize, window_rect.Max.x - other_scrollbar_size_w - border_size, window_rect.Max.y - border_size) - : ImRect(window_rect.Max.x - style.ScrollbarSize, window->Pos.y + border_size, window_rect.Max.x - border_size, window_rect.Max.y - other_scrollbar_size_w - border_size); + ? ImRect(host_rect.Min.x + border_size, host_rect.Max.y - style.ScrollbarSize, host_rect.Max.x - other_scrollbar_size_w - border_size, host_rect.Max.y - border_size) + : ImRect(host_rect.Max.x - style.ScrollbarSize, host_rect.Min.y + border_size, host_rect.Max.x - border_size, host_rect.Max.y - other_scrollbar_size_w - border_size); + bb.Min.x = ImMax(host_rect.Min.x, bb.Min.x); // Handle case where the host rectangle is smaller than the scrollbar + bb.Min.y = ImMax(host_rect.Min.y, bb.Min.y); if (!horizontal) bb.Min.y += window->TitleBarHeight() + ((window->Flags & ImGuiWindowFlags_MenuBar) ? window->MenuBarHeight() : 0.0f); // FIXME: InnerRect? + const float bb_width = bb.GetWidth(); const float bb_height = bb.GetHeight(); - if (bb.GetWidth() <= 0.0f || bb_height <= 0.0f) + if (bb_width <= 0.0f || bb_height <= 0.0f) return; // When we are too small, start hiding and disabling the grab (this reduce visual noise on very small window and facilitate using the resize grab) @@ -816,7 +819,7 @@ void ImGui::Scrollbar(ImGuiAxis axis) else window_rounding_corners = (((window->Flags & ImGuiWindowFlags_NoTitleBar) && !(window->Flags & ImGuiWindowFlags_MenuBar)) ? ImDrawCornerFlags_TopRight : 0) | (other_scrollbar ? 0 : ImDrawCornerFlags_BotRight); window->DrawList->AddRectFilled(bb.Min, bb.Max, GetColorU32(ImGuiCol_ScrollbarBg), window->WindowRounding, window_rounding_corners); - bb.Expand(ImVec2(-ImClamp((float)(int)((bb.Max.x - bb.Min.x - 2.0f) * 0.5f), 0.0f, 3.0f), -ImClamp((float)(int)((bb.Max.y - bb.Min.y - 2.0f) * 0.5f), 0.0f, 3.0f))); + bb.Expand(ImVec2(-ImClamp((float)(int)((bb_width - 2.0f) * 0.5f), 0.0f, 3.0f), -ImClamp((float)(int)((bb_height - 2.0f) * 0.5f), 0.0f, 3.0f))); // V denote the main, longer axis of the scrollbar (= height for a vertical scrollbar) float scrollbar_size_v = horizontal ? bb.GetWidth() : bb.GetHeight(); @@ -887,9 +890,9 @@ void ImGui::Scrollbar(ImGuiAxis axis) const ImU32 grab_col = GetColorU32(held ? ImGuiCol_ScrollbarGrabActive : hovered ? ImGuiCol_ScrollbarGrabHovered : ImGuiCol_ScrollbarGrab, alpha); ImRect grab_rect; if (horizontal) - grab_rect = ImRect(ImLerp(bb.Min.x, bb.Max.x, grab_v_norm), bb.Min.y, ImMin(ImLerp(bb.Min.x, bb.Max.x, grab_v_norm) + grab_h_pixels, window_rect.Max.x), bb.Max.y); + grab_rect = ImRect(ImLerp(bb.Min.x, bb.Max.x, grab_v_norm), bb.Min.y, ImMin(ImLerp(bb.Min.x, bb.Max.x, grab_v_norm) + grab_h_pixels, host_rect.Max.x), bb.Max.y); else - grab_rect = ImRect(bb.Min.x, ImLerp(bb.Min.y, bb.Max.y, grab_v_norm), bb.Max.x, ImMin(ImLerp(bb.Min.y, bb.Max.y, grab_v_norm) + grab_h_pixels, window_rect.Max.y)); + grab_rect = ImRect(bb.Min.x, ImLerp(bb.Min.y, bb.Max.y, grab_v_norm), bb.Max.x, ImMin(ImLerp(bb.Min.y, bb.Max.y, grab_v_norm) + grab_h_pixels, host_rect.Max.y)); window->DrawList->AddRectFilled(grab_rect.Min, grab_rect.Max, grab_col, style.ScrollbarRounding); } @@ -1361,19 +1364,19 @@ bool ImGui::BeginCombo(const char* label, const char* preview_value, ImGuiComboF bool pressed = ButtonBehavior(frame_bb, id, &hovered, &held); bool popup_open = IsPopupOpen(id); - const ImRect value_bb(frame_bb.Min, frame_bb.Max - ImVec2(arrow_size, 0.0f)); const ImU32 frame_col = GetColorU32(hovered ? ImGuiCol_FrameBgHovered : ImGuiCol_FrameBg); + const float value_x2 = ImMax(frame_bb.Min.x, frame_bb.Max.x - arrow_size); RenderNavHighlight(frame_bb, id); if (!(flags & ImGuiComboFlags_NoPreview)) - window->DrawList->AddRectFilled(frame_bb.Min, ImVec2(frame_bb.Max.x - arrow_size, frame_bb.Max.y), frame_col, style.FrameRounding, ImDrawCornerFlags_Left); + window->DrawList->AddRectFilled(frame_bb.Min, ImVec2(value_x2, frame_bb.Max.y), frame_col, style.FrameRounding, ImDrawCornerFlags_Left); if (!(flags & ImGuiComboFlags_NoArrowButton)) { - window->DrawList->AddRectFilled(ImVec2(frame_bb.Max.x - arrow_size, frame_bb.Min.y), frame_bb.Max, GetColorU32((popup_open || hovered) ? ImGuiCol_ButtonHovered : ImGuiCol_Button), style.FrameRounding, (w <= arrow_size) ? ImDrawCornerFlags_All : ImDrawCornerFlags_Right); - RenderArrow(ImVec2(frame_bb.Max.x - arrow_size + style.FramePadding.y, frame_bb.Min.y + style.FramePadding.y), ImGuiDir_Down); + window->DrawList->AddRectFilled(ImVec2(value_x2, frame_bb.Min.y), frame_bb.Max, GetColorU32((popup_open || hovered) ? ImGuiCol_ButtonHovered : ImGuiCol_Button), style.FrameRounding, (w <= arrow_size) ? ImDrawCornerFlags_All : ImDrawCornerFlags_Right); + RenderArrow(ImVec2(value_x2 + style.FramePadding.y, frame_bb.Min.y + style.FramePadding.y), ImGuiDir_Down); } RenderFrameBorder(frame_bb.Min, frame_bb.Max, style.FrameRounding); if (preview_value != NULL && !(flags & ImGuiComboFlags_NoPreview)) - RenderTextClipped(frame_bb.Min + style.FramePadding, value_bb.Max, preview_value, NULL, NULL, ImVec2(0.0f,0.0f)); + RenderTextClipped(frame_bb.Min + style.FramePadding, ImVec2(value_x2, frame_bb.Max.y), preview_value, NULL, NULL, ImVec2(0.0f,0.0f)); if (label_size.x > 0) RenderText(ImVec2(frame_bb.Max.x + style.ItemInnerSpacing.x, frame_bb.Min.y + style.FramePadding.y), label); @@ -2223,16 +2226,16 @@ bool ImGui::SliderBehaviorT(const ImRect& bb, ImGuiID id, ImGuiDataType data_typ grab_sz = ImMax((float)(slider_sz / (v_range + 1)), style.GrabMinSize); // For integer sliders: if possible have the grab size represent 1 unit grab_sz = ImMin(grab_sz, slider_sz); const float slider_usable_sz = slider_sz - grab_sz; - const float slider_usable_pos_min = bb.Min[axis] + grab_padding + grab_sz*0.5f; - const float slider_usable_pos_max = bb.Max[axis] - grab_padding - grab_sz*0.5f; + const float slider_usable_pos_min = bb.Min[axis] + grab_padding + grab_sz * 0.5f; + const float slider_usable_pos_max = bb.Max[axis] - grab_padding - grab_sz * 0.5f; // For power curve sliders that cross over sign boundary we want the curve to be symmetric around 0.0f float linear_zero_pos; // 0.0->1.0f if (is_power && v_min * v_max < 0.0f) { // Different sign - const FLOATTYPE linear_dist_min_to_0 = ImPow(v_min >= 0 ? (FLOATTYPE)v_min : -(FLOATTYPE)v_min, (FLOATTYPE)1.0f/power); - const FLOATTYPE linear_dist_max_to_0 = ImPow(v_max >= 0 ? (FLOATTYPE)v_max : -(FLOATTYPE)v_max, (FLOATTYPE)1.0f/power); + const FLOATTYPE linear_dist_min_to_0 = ImPow(v_min >= 0 ? (FLOATTYPE)v_min : -(FLOATTYPE)v_min, (FLOATTYPE)1.0f / power); + const FLOATTYPE linear_dist_max_to_0 = ImPow(v_max >= 0 ? (FLOATTYPE)v_max : -(FLOATTYPE)v_max, (FLOATTYPE)1.0f / power); linear_zero_pos = (float)(linear_dist_min_to_0 / (linear_dist_min_to_0 + linear_dist_max_to_0)); } else @@ -2355,15 +2358,22 @@ bool ImGui::SliderBehaviorT(const ImRect& bb, ImGuiID id, ImGuiDataType data_typ } } - // Output grab position so it can be displayed by the caller - float grab_t = SliderCalcRatioFromValueT(data_type, *v, v_min, v_max, power, linear_zero_pos); - if (axis == ImGuiAxis_Y) - grab_t = 1.0f - grab_t; - const float grab_pos = ImLerp(slider_usable_pos_min, slider_usable_pos_max, grab_t); - if (axis == ImGuiAxis_X) - *out_grab_bb = ImRect(grab_pos - grab_sz*0.5f, bb.Min.y + grab_padding, grab_pos + grab_sz*0.5f, bb.Max.y - grab_padding); + if (slider_sz < 1.0f) + { + *out_grab_bb = ImRect(bb.Min, bb.Min); + } else - *out_grab_bb = ImRect(bb.Min.x + grab_padding, grab_pos - grab_sz*0.5f, bb.Max.x - grab_padding, grab_pos + grab_sz*0.5f); + { + // Output grab position so it can be displayed by the caller + float grab_t = SliderCalcRatioFromValueT(data_type, *v, v_min, v_max, power, linear_zero_pos); + if (axis == ImGuiAxis_Y) + grab_t = 1.0f - grab_t; + const float grab_pos = ImLerp(slider_usable_pos_min, slider_usable_pos_max, grab_t); + if (axis == ImGuiAxis_X) + *out_grab_bb = ImRect(grab_pos - grab_sz * 0.5f, bb.Min.y + grab_padding, grab_pos + grab_sz * 0.5f, bb.Max.y - grab_padding); + else + *out_grab_bb = ImRect(bb.Min.x + grab_padding, grab_pos - grab_sz * 0.5f, bb.Max.x - grab_padding, grab_pos + grab_sz * 0.5f); + } return value_changed; } @@ -2465,7 +2475,8 @@ bool ImGui::SliderScalar(const char* label, ImGuiDataType data_type, void* v, co MarkItemEdited(id); // Render grab - window->DrawList->AddRectFilled(grab_bb.Min, grab_bb.Max, GetColorU32(g.ActiveId == id ? ImGuiCol_SliderGrabActive : ImGuiCol_SliderGrab), style.GrabRounding); + if (grab_bb.Max.x > grab_bb.Min.x) + window->DrawList->AddRectFilled(grab_bb.Min, grab_bb.Max, GetColorU32(g.ActiveId == id ? ImGuiCol_SliderGrabActive : ImGuiCol_SliderGrab), style.GrabRounding); // Display value using user-provided display format so user can add prefix/suffix/decorations to the value. char value_buf[64]; @@ -2605,7 +2616,8 @@ bool ImGui::VSliderScalar(const char* label, const ImVec2& size, ImGuiDataType d MarkItemEdited(id); // Render grab - window->DrawList->AddRectFilled(grab_bb.Min, grab_bb.Max, GetColorU32(g.ActiveId == id ? ImGuiCol_SliderGrabActive : ImGuiCol_SliderGrab), style.GrabRounding); + if (grab_bb.Max.y > grab_bb.Min.y) + window->DrawList->AddRectFilled(grab_bb.Min, grab_bb.Max, GetColorU32(g.ActiveId == id ? ImGuiCol_SliderGrabActive : ImGuiCol_SliderGrab), style.GrabRounding); // Display value using user-provided display format so user can add prefix/suffix/decorations to the value. // For the vertical slider we allow centered text to overlap the frame padding From 9d4a893a774603fb2fa0c19ba063d9df46baa1a5 Mon Sep 17 00:00:00 2001 From: omar Date: Thu, 18 Apr 2019 13:46:45 +0200 Subject: [PATCH 07/13] Internals: Moved CalcItemSize next to CalcItemWidth, added comments to clarify their respective intent. Should have no side effect. --- imgui.cpp | 31 +++++++++++++++++-------------- imgui_internal.h | 2 +- imgui_widgets.cpp | 3 +++ 3 files changed, 21 insertions(+), 15 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 18b368d5..d08f9d5a 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -2973,19 +2973,6 @@ void ImGui::FocusableItemUnregister(ImGuiWindow* window) window->DC.FocusCounterTab--; } -ImVec2 ImGui::CalcItemSize(ImVec2 size, float default_x, float default_y) -{ - ImGuiContext& g = *GImGui; - ImVec2 content_max; - if (size.x < 0.0f || size.y < 0.0f) - content_max = g.CurrentWindow->Pos + GetContentRegionMax(); - if (size.x <= 0.0f) - size.x = (size.x == 0.0f) ? default_x : ImMax(content_max.x - g.CurrentWindow->DC.CursorPos.x, 4.0f) + size.x; - if (size.y <= 0.0f) - size.y = (size.y == 0.0f) ? default_y : ImMax(content_max.y - g.CurrentWindow->DC.CursorPos.y, 4.0f) + size.y; - return size; -} - float ImGui::CalcWrapWidthForPos(const ImVec2& pos, float wrap_pos_x) { if (wrap_pos_x < 0.0f) @@ -5785,13 +5772,13 @@ 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() float ImGui::CalcItemWidth() { ImGuiWindow* window = GetCurrentWindowRead(); float w = window->DC.ItemWidth; if (w < 0.0f) { - // Align to a right-side limit. We include 1 frame padding in the calculation because this is how the width is always used (we add 2 frame padding to it), but we could move that responsibility to the widget as well. float width_to_right_edge = GetContentRegionAvail().x; w = ImMax(1.0f, width_to_right_edge + w); } @@ -5799,6 +5786,22 @@ float ImGui::CalcItemWidth() return w; } +// [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. +ImVec2 ImGui::CalcItemSize(ImVec2 size, float default_w, float default_h) +{ + ImGuiWindow* window = GetCurrentWindowRead(); + ImVec2 content_max; + if (size.x < 0.0f || size.y < 0.0f) + content_max = window->Pos + GetContentRegionMax(); + if (size.x <= 0.0f) + size.x = (size.x == 0.0f) ? default_w : ImMax(content_max.x - window->DC.CursorPos.x, 4.0f) + size.x; + if (size.y <= 0.0f) + size.y = (size.y == 0.0f) ? default_h : ImMax(content_max.y - window->DC.CursorPos.y, 4.0f) + size.y; + return size; +} + void ImGui::SetCurrentFont(ImFont* font) { ImGuiContext& g = *GImGui; diff --git a/imgui_internal.h b/imgui_internal.h index 7ed26cfd..843eaa44 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -1438,7 +1438,7 @@ 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 ImVec2 CalcItemSize(ImVec2 size, float default_x, float default_y); + 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 = 0.0f); IMGUI_API void PushItemFlag(ImGuiItemFlags option, bool enabled); diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index 2e93b853..060c8a32 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -5440,6 +5440,9 @@ bool ImGui::Selectable(const char* label, bool* p_selected, ImGuiSelectableFlags // - ListBoxHeader() // - ListBoxFooter() //------------------------------------------------------------------------- +// FIXME: This is an old API. We should redesign some of it, rename ListBoxHeader->BeginListBox, ListBoxFooter->EndListBox +// and promote using them over existing ListBox() functions, similarly to change with combo boxes. +//------------------------------------------------------------------------- // FIXME: In principle this function should be called BeginListBox(). We should rename it after re-evaluating if we want to keep the same signature. // Helper to calculate the size of a listbox and display a label on the right. From f355a403675c75ec88d0c53322c41fe2d12fa0de Mon Sep 17 00:00:00 2001 From: omar Date: Thu, 18 Apr 2019 14:10:01 +0200 Subject: [PATCH 08/13] Added commentary about ContentRegion functions. Added internal GetContentRegionMaxScreen() to facilitate internal code at the moment. --- imgui.cpp | 26 ++++++++++++++++++-------- imgui.h | 17 ++++++++++------- imgui_internal.h | 1 + imgui_widgets.cpp | 2 +- 4 files changed, 30 insertions(+), 16 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index d08f9d5a..20ecf03c 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -2978,9 +2978,9 @@ float ImGui::CalcWrapWidthForPos(const ImVec2& pos, float wrap_pos_x) if (wrap_pos_x < 0.0f) return 0.0f; - ImGuiWindow* window = GetCurrentWindowRead(); + ImGuiWindow* window = GImGui->CurrentWindow; if (wrap_pos_x == 0.0f) - wrap_pos_x = GetContentRegionMax().x + window->Pos.x; + wrap_pos_x = GetContentRegionMaxScreen().x; else if (wrap_pos_x > 0.0f) wrap_pos_x += window->Pos.x - window->Scroll.x; // wrap_pos_x is provided is window local space @@ -5775,7 +5775,7 @@ void ImGui::PopItemWidth() // Calculate default item width given value passed to PushItemWidth() float ImGui::CalcItemWidth() { - ImGuiWindow* window = GetCurrentWindowRead(); + ImGuiWindow* window = GImGui->CurrentWindow; float w = window->DC.ItemWidth; if (w < 0.0f) { @@ -5791,10 +5791,10 @@ float ImGui::CalcItemWidth() // Note that only CalcItemWidth() is publicly exposed. ImVec2 ImGui::CalcItemSize(ImVec2 size, float default_w, float default_h) { - ImGuiWindow* window = GetCurrentWindowRead(); + ImGuiWindow* window = GImGui->CurrentWindow; ImVec2 content_max; if (size.x < 0.0f || size.y < 0.0f) - content_max = window->Pos + GetContentRegionMax(); + content_max = GetContentRegionMaxScreen(); if (size.x <= 0.0f) size.x = (size.x == 0.0f) ? default_w : ImMax(content_max.x - window->DC.CursorPos.x, 4.0f) + size.x; if (size.y <= 0.0f) @@ -6367,17 +6367,27 @@ void ImGui::SetNextWindowBgAlpha(float alpha) // FIXME: This is in window space (not screen space!) ImVec2 ImGui::GetContentRegionMax() { - ImGuiWindow* window = GetCurrentWindowRead(); + ImGuiWindow* window = GImGui->CurrentWindow; ImVec2 mx = window->ContentsRegionRect.Max - window->Pos; if (window->DC.CurrentColumns) mx.x = GetColumnOffset(window->DC.CurrentColumns->Current + 1) - window->WindowPadding.x; return mx; } +// [Internal] Absolute coordinate. Saner. This is not exposed until we finishing refactoring work rect features. +ImVec2 ImGui::GetContentRegionMaxScreen() +{ + ImGuiWindow* window = GImGui->CurrentWindow; + ImVec2 mx = window->ContentsRegionRect.Max; + if (window->DC.CurrentColumns) + mx.x = window->Pos.x + GetColumnOffset(window->DC.CurrentColumns->Current + 1) - window->WindowPadding.x; + return mx; +} + ImVec2 ImGui::GetContentRegionAvail() { - ImGuiWindow* window = GetCurrentWindowRead(); - return GetContentRegionMax() - (window->DC.CursorPos - window->Pos); + ImGuiWindow* window = GImGui->CurrentWindow; + return GetContentRegionMaxScreen() - window->DC.CursorPos; } float ImGui::GetContentRegionAvailWidth() diff --git a/imgui.h b/imgui.h index f11a3a50..f597e07b 100644 --- a/imgui.h +++ b/imgui.h @@ -261,18 +261,12 @@ namespace ImGui IMGUI_API bool IsWindowFocused(ImGuiFocusedFlags flags=0); // is current window focused? or its root/child, depending on flags. see flags for options. IMGUI_API bool IsWindowHovered(ImGuiHoveredFlags flags=0); // is current window hovered (and typically: not blocked by a popup/modal)? see flags for options. NB: If you are trying to check whether your mouse should be dispatched to imgui or to your app, you should use the 'io.WantCaptureMouse' boolean for that! Please read the FAQ! IMGUI_API ImDrawList* GetWindowDrawList(); // get draw list associated to the current window, to append your own drawing primitives - IMGUI_API ImVec2 GetWindowPos(); // get current window position in screen space (useful if you want to do your own drawing via the DrawList API) IMGUI_API ImVec2 GetWindowSize(); // get current window size IMGUI_API float GetWindowWidth(); // get current window width (shortcut for GetWindowSize().x) IMGUI_API float GetWindowHeight(); // get current window height (shortcut for GetWindowSize().y) - IMGUI_API ImVec2 GetContentRegionMax(); // current content boundaries (typically window boundaries including scrolling, or current column boundaries), in windows coordinates - IMGUI_API ImVec2 GetContentRegionAvail(); // == GetContentRegionMax() - GetCursorPos() - IMGUI_API float GetContentRegionAvailWidth(); // == GetContentRegionAvail().x - IMGUI_API ImVec2 GetWindowContentRegionMin(); // content boundaries min (roughly (0,0)-Scroll), in window coordinates - IMGUI_API ImVec2 GetWindowContentRegionMax(); // content boundaries max (roughly (0,0)+Size-Scroll) where Size can be override with SetNextWindowContentSize(), in window coordinates - IMGUI_API float GetWindowContentRegionWidth(); // + // Prefer using SetNextXXX functions (before Begin) rather that SetXXX functions (after Begin). IMGUI_API void SetNextWindowPos(const ImVec2& pos, ImGuiCond cond = 0, const ImVec2& pivot = ImVec2(0,0)); // set next window position. call before Begin(). use pivot=(0.5f,0.5f) to center on given point, etc. IMGUI_API void SetNextWindowSize(const ImVec2& size, ImGuiCond cond = 0); // set next window size. set axis to 0.0f to force an auto-fit on this axis. call before Begin() IMGUI_API void SetNextWindowSizeConstraints(const ImVec2& size_min, const ImVec2& size_max, ImGuiSizeCallback custom_callback = NULL, void* custom_callback_data = NULL); // set next window size limits. use -1,-1 on either X/Y axis to preserve the current size. Use callback to apply non-trivial programmatic constraints. @@ -290,6 +284,15 @@ namespace ImGui IMGUI_API void SetWindowCollapsed(const char* name, bool collapsed, ImGuiCond cond = 0); // set named window collapsed state IMGUI_API void SetWindowFocus(const char* name); // set named window to be focused / front-most. use NULL to remove focus. + // Content region + // - Those functions are bound to be redesigned soon (they are confusing, incomplete and return values in local window coordinates which increases confusion) + IMGUI_API ImVec2 GetContentRegionMax(); // current content boundaries (typically window boundaries including scrolling, or current column boundaries), in windows coordinates + IMGUI_API ImVec2 GetContentRegionAvail(); // == GetContentRegionMax() - GetCursorPos() + IMGUI_API float GetContentRegionAvailWidth(); // == GetContentRegionAvail().x + IMGUI_API ImVec2 GetWindowContentRegionMin(); // content boundaries min (roughly (0,0)-Scroll), in window coordinates + IMGUI_API ImVec2 GetWindowContentRegionMax(); // content boundaries max (roughly (0,0)+Size-Scroll) where Size can be override with SetNextWindowContentSize(), in window coordinates + IMGUI_API float GetWindowContentRegionWidth(); // + // Windows Scrolling IMGUI_API float GetScrollX(); // get scrolling amount [0..GetScrollMaxX()] IMGUI_API float GetScrollY(); // get scrolling amount [0..GetScrollMaxY()] diff --git a/imgui_internal.h b/imgui_internal.h index 843eaa44..b399becd 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -1444,6 +1444,7 @@ namespace ImGui IMGUI_API void PushItemFlag(ImGuiItemFlags option, bool enabled); IMGUI_API void PopItemFlag(); IMGUI_API bool IsItemToggledSelection(); // was the last item selection toggled? (after Selectable(), TreeNode() etc. We only returns toggle _event_ in order to handle clipping correctly) + IMGUI_API ImVec2 GetContentRegionMaxScreen(); // Logging/Capture IMGUI_API void LogBegin(ImGuiLogType type, int auto_open_depth); // -> BeginCapture() when we design v2 api, for now stay under the radar by using the old name. diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index 060c8a32..6812808e 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -5057,7 +5057,7 @@ bool ImGui::TreeNodeBehavior(ImGuiID id, ImGuiTreeNodeFlags flags, const char* l // 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); - ImRect frame_bb = ImRect(window->DC.CursorPos, ImVec2(window->Pos.x + GetContentRegionMax().x, window->DC.CursorPos.y + frame_height)); + ImRect frame_bb = ImRect(window->DC.CursorPos, ImVec2(GetContentRegionMaxScreen().x, window->DC.CursorPos.y + frame_height)); if (display_frame) { // Framed header expand a little outside the default padding From a1cf7d636d5dca6005a7af0af12da8564e61f723 Mon Sep 17 00:00:00 2001 From: omar Date: Thu, 18 Apr 2019 14:48:36 +0200 Subject: [PATCH 09/13] Internals: Rework CalcItemWidth / CalcItemSize but make their similarities and their differences more obvious. (#2449) --- imgui.cpp | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 20ecf03c..02d7ad9f 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -5779,8 +5779,8 @@ float ImGui::CalcItemWidth() float w = window->DC.ItemWidth; if (w < 0.0f) { - float width_to_right_edge = GetContentRegionAvail().x; - w = ImMax(1.0f, width_to_right_edge + w); + float region_max_x = GetContentRegionMaxScreen().x; + w = ImMax(1.0f, region_max_x - window->DC.CursorPos.x + w); } w = (float)(int)w; return w; @@ -5792,13 +5792,21 @@ float ImGui::CalcItemWidth() ImVec2 ImGui::CalcItemSize(ImVec2 size, float default_w, float default_h) { ImGuiWindow* window = GImGui->CurrentWindow; - ImVec2 content_max; + + ImVec2 region_max; if (size.x < 0.0f || size.y < 0.0f) - content_max = GetContentRegionMaxScreen(); - if (size.x <= 0.0f) - size.x = (size.x == 0.0f) ? default_w : ImMax(content_max.x - window->DC.CursorPos.x, 4.0f) + size.x; - if (size.y <= 0.0f) - size.y = (size.y == 0.0f) ? default_h : ImMax(content_max.y - window->DC.CursorPos.y, 4.0f) + size.y; + region_max = GetContentRegionMaxScreen(); + + if (size.x == 0.0f) + size.x = default_w; + else if (size.x < 0.0f) + size.x = ImMax(4.0f, region_max.x - window->DC.CursorPos.x) + size.x; + + if (size.y == 0.0f) + size.y = default_h; + else if (size.y < 0.0f) + size.y = ImMax(4.0f, region_max.y - window->DC.CursorPos.y) + size.y; + return size; } From 0e46d65b031ea796439d9df2c43215d51b625d44 Mon Sep 17 00:00:00 2001 From: omar Date: Thu, 18 Apr 2019 15:35:20 +0200 Subject: [PATCH 10/13] Misc: Fixed PushItemWidth(-width) (for right-side alignment) laying out certain items (button, listbox, etc.) with negative sizes if the 'width' argument was smaller than the available width at the time of item submission, --- docs/CHANGELOG.txt | 2 ++ imgui.cpp | 5 +++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index c9401b3a..511e381c 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -53,6 +53,8 @@ Other Changes: - Window: Window close button is horizontally aligned with style.FramePadding.x. - Columns: Fixed boundary of clipping being off by 1 pixel within the left column. - Combo, Slider, Scrollbar: Improve rendering in situation when there's only a few pixels available (<3 pixels). +- Misc: Fixed PushItemWidth(-width) (for right-side alignment) laying out certain items (button, listbox, etc.) + with negative sizes if the 'width' argument was smaller than the available width at the time of item submission, - Misc: Added IM_MALLOC/IM_FREE macros mimicking IM_NEW/IM_DELETE so user doesn't need to revert to using the ImGui::MemAlloc()/MemFree() calls directly. - Metrics: Added "Show windows rectangles" tool to visualize the different rectangles. diff --git a/imgui.cpp b/imgui.cpp index 02d7ad9f..2b4b7a83 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -5789,6 +5789,7 @@ float ImGui::CalcItemWidth() // [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 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; @@ -5800,12 +5801,12 @@ ImVec2 ImGui::CalcItemSize(ImVec2 size, float default_w, float default_h) if (size.x == 0.0f) size.x = default_w; else if (size.x < 0.0f) - size.x = ImMax(4.0f, region_max.x - window->DC.CursorPos.x) + size.x; + size.x = ImMax(4.0f, region_max.x - window->DC.CursorPos.x + size.x); if (size.y == 0.0f) size.y = default_h; else if (size.y < 0.0f) - size.y = ImMax(4.0f, region_max.y - window->DC.CursorPos.y) + size.y; + size.y = ImMax(4.0f, region_max.y - window->DC.CursorPos.y + size.y); return size; } From 8d53f834ee1a5ae965fa8562e44039db59aeb199 Mon Sep 17 00:00:00 2001 From: omar Date: Thu, 18 Apr 2019 18:24:51 +0200 Subject: [PATCH 11/13] Demo: Documents: Fix misusage of ListBoxHeader(). --- imgui_demo.cpp | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/imgui_demo.cpp b/imgui_demo.cpp index 443c3c23..6dd69bd3 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -4402,11 +4402,13 @@ void ShowExampleAppDocuments(bool* p_open) { ImGui::Text("Save change to the following items?"); ImGui::PushItemWidth(-1.0f); - ImGui::ListBoxHeader("##", close_queue_unsaved_documents, 6); - for (int n = 0; n < close_queue.Size; n++) - if (close_queue[n]->Dirty) - ImGui::Text("%s", close_queue[n]->Name); - ImGui::ListBoxFooter(); + if (ImGui::ListBoxHeader("##", close_queue_unsaved_documents, 6)) + { + for (int n = 0; n < close_queue.Size; n++) + if (close_queue[n]->Dirty) + ImGui::Text("%s", close_queue[n]->Name); + ImGui::ListBoxFooter(); + } if (ImGui::Button("Yes", ImVec2(80, 0))) { From 5078fa208b2dcfa130fcbaa4260f958894ef16b5 Mon Sep 17 00:00:00 2001 From: omar Date: Thu, 18 Apr 2019 18:29:28 +0200 Subject: [PATCH 12/13] Added SetNextItemWidth() helper to avoid using PushItemWidth/PopItemWidth() for single items. --- docs/CHANGELOG.txt | 4 ++++ imgui.cpp | 49 ++++++++++++++++++++++++++++++------------- imgui.h | 3 ++- imgui_demo.cpp | 52 ++++++++++++++++++++++------------------------ imgui_internal.h | 5 ++++- imgui_widgets.cpp | 46 ++++++++++++++++++---------------------- 6 files changed, 90 insertions(+), 69 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 511e381c..39f0da96 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -46,6 +46,10 @@ Other Changes: - InputText: Work-around for buggy standard libraries where isprint('\t') returns true. (#2467, #1336) - InputText: Fixed ImGuiInputTextFlags_AllowTabInput leading to two tabs characters being inserted if the back-end provided both Key and Character input. (#2467, #1336) +- Added SetNextItemWidth() helper to avoid using PushItemWidth/PopItemWidth() for single items. + Note that SetNextItemWidth() currently only affect the same subset of items as PushItemWidth(), + generally referred to as the large framed+labeled items. + Because the new SetNextItemWidth() function is explicit - GetMouseDragDelta(): also returns the delta on the mouse button released frame. (#2419) - GetMouseDragDelta(): verify that mouse positions are valid otherwise returns zero. - Inputs: Also add support for horizontal scroll with Shift+Mouse Wheel. (#2424, #1463) [@LucaRood] diff --git a/imgui.cpp b/imgui.cpp index 2b4b7a83..8f56ab6c 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -2068,10 +2068,8 @@ ImGuiTextFilter::ImGuiTextFilter(const char* default_filter) bool ImGuiTextFilter::Draw(const char* label, float width) { if (width != 0.0f) - ImGui::PushItemWidth(width); + ImGui::SetNextItemWidth(width); bool value_changed = ImGui::InputText(label, InputBuf, IM_ARRAYSIZE(InputBuf)); - if (width != 0.0f) - ImGui::PopItemWidth(); if (value_changed) Build(); return value_changed; @@ -5744,6 +5742,12 @@ void ImGui::FocusPreviousWindowIgnoringOne(ImGuiWindow* ignore_window) } } +void ImGui::SetNextItemWidth(float item_width) +{ + ImGuiWindow* window = GetCurrentWindow(); + window->DC.NextItemWidth = item_width; +} + void ImGui::PushItemWidth(float item_width) { ImGuiWindow* window = GetCurrentWindow(); @@ -5755,8 +5759,6 @@ void ImGui::PushMultiItemsWidths(int components, float w_full) { ImGuiWindow* window = GetCurrentWindow(); const ImGuiStyle& style = GImGui->Style; - if (w_full <= 0.0f) - w_full = CalcItemWidth(); 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))); window->DC.ItemWidthStack.push_back(w_item_last); @@ -5772,11 +5774,21 @@ 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() -float ImGui::CalcItemWidth() +// Calculate default item width given value passed to PushItemWidth() or SetNextItemWidth(), +// Then consume the +float ImGui::GetNextItemWidth() { ImGuiWindow* window = GImGui->CurrentWindow; - float w = window->DC.ItemWidth; + float w; + if (window->DC.NextItemWidth != FLT_MAX) + { + w = window->DC.NextItemWidth; + window->DC.NextItemWidth = FLT_MAX; + } + else + { + w = window->DC.ItemWidth; + } if (w < 0.0f) { float region_max_x = GetContentRegionMaxScreen().x; @@ -5786,10 +5798,21 @@ float ImGui::CalcItemWidth() return w; } -// [Internal] Calculate full item size given user provided 'size' parameter and default width/height. Default width is often == CalcItemWidth(). +// 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() +{ + ImGuiWindow* window = GImGui->CurrentWindow; + float backup_next_item_width = window->DC.NextItemWidth; + float w = GetNextItemWidth(); + window->DC.NextItemWidth = backup_next_item_width; + return w; +} + +// [Internal] Calculate full item size given user provided 'size' parameter and default width/height. Default width is often == GetNextItemWidth(). // 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 CalcItemWidth() and/or BeginChild() (right now we have a mismatch which is harmless but undesirable) +// The 4.0f here may be changed to match GetNextItemWidth() 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; @@ -9147,11 +9170,10 @@ void ImGui::LogButtons() const bool log_to_tty = Button("Log To TTY"); SameLine(); const bool log_to_file = Button("Log To File"); SameLine(); const bool log_to_clipboard = Button("Log To Clipboard"); SameLine(); - PushItemWidth(80.0f); PushAllowKeyboardFocus(false); + SetNextItemWidth(80.0f); SliderInt("Default Depth", &g.LogDepthToExpandDefault, 0, 9, NULL); PopAllowKeyboardFocus(); - PopItemWidth(); PopID(); // Start logging at the end of the function so that the buttons don't appear in the log @@ -9739,9 +9761,8 @@ void ImGui::ShowMetricsWindow(bool* p_open) ImGui::Checkbox("Show windows begin order", &show_windows_begin_order); ImGui::Checkbox("Show windows rectangles", &show_windows_rects); ImGui::SameLine(); - ImGui::PushItemWidth(ImGui::GetFontSize() * 12); + ImGui::SetNextItemWidth(ImGui::GetFontSize() * 12); show_windows_rects |= ImGui::Combo("##rects_type", &show_windows_rect_type, "OuterRect\0" "OuterRectClipped\0" "InnerMainRect\0" "InnerClipRect\0" "ContentsRegionRect\0"); - ImGui::PopItemWidth(); ImGui::Checkbox("Show clipping rectangle when hovering ImDrawCmd node", &show_drawcmd_clip_rects); ImGui::TreePop(); } diff --git a/imgui.h b/imgui.h index f597e07b..53e17253 100644 --- a/imgui.h +++ b/imgui.h @@ -321,8 +321,9 @@ namespace ImGui IMGUI_API ImU32 GetColorU32(ImU32 col); // retrieve given color with style alpha applied // Parameters stacks (current window) - IMGUI_API void PushItemWidth(float item_width); // width of items for the common item+label case, pixels. 0.0f = default to ~2/3 of windows width, >0.0f: width in pixels, <0.0f align xx pixels to the right of window (so -1.0f always align width to the right side) + IMGUI_API void PushItemWidth(float item_width); // set width of items for common large "item+label" widgets. >0.0f: width in pixels, <0.0f align xx pixels to the right of window (so -1.0f always align width to the right side). 0.0f = default to ~2/3 of windows width, IMGUI_API void PopItemWidth(); + IMGUI_API void SetNextItemWidth(float item_width); // set width of the _next_ common large "item+label" widget. >0.0f: width in pixels, <0.0f align xx pixels to the right of window (so -1.0f always align width to the right side) IMGUI_API float CalcItemWidth(); // width of item given pushed settings and current cursor position IMGUI_API void PushTextWrapPos(float wrap_local_pos_x = 0.0f); // word-wrapping for Text*() commands. < 0.0f: no wrapping; 0.0f: wrap to end of window (or column); > 0.0f: wrap at 'wrap_pos_x' position in window local space IMGUI_API void PopTextWrapPos(); diff --git a/imgui_demo.cpp b/imgui_demo.cpp index 6dd69bd3..2233eab7 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -550,9 +550,8 @@ static void ShowDemoWindowWidgets() ImGui::ListBox("listbox\n(single select)", &listbox_item_current, listbox_items, IM_ARRAYSIZE(listbox_items), 4); //static int listbox_item_current2 = 2; - //ImGui::PushItemWidth(-1); + //ImGui::SetNextItemWidth(-1); //ImGui::ListBox("##listbox2", &listbox_item_current2, listbox_items, IM_ARRAYSIZE(listbox_items), 4); - //ImGui::PopItemWidth(); } ImGui::TreePop(); @@ -1052,7 +1051,8 @@ static void ShowDemoWindowWidgets() }; static int func_type = 0, display_count = 70; ImGui::Separator(); - ImGui::PushItemWidth(100); ImGui::Combo("func", &func_type, "Sin\0Saw\0"); ImGui::PopItemWidth(); + ImGui::SetNextItemWidth(100); + ImGui::Combo("func", &func_type, "Sin\0Saw\0"); ImGui::SameLine(); ImGui::SliderInt("Sample count", &display_count, 1, 400); float (*func)(void*, int) = (func_type == 0) ? Funcs::Sin : Funcs::Saw; @@ -1667,9 +1667,8 @@ static void ShowDemoWindowLayout() static int line = 50; bool goto_line = ImGui::Button("Goto"); ImGui::SameLine(); - ImGui::PushItemWidth(100); + ImGui::SetNextItemWidth(100); goto_line |= ImGui::InputInt("##Line", &line, 0, 0, ImGuiInputTextFlags_EnterReturnsTrue); - ImGui::PopItemWidth(); // Child 1: no border, enable horizontal scrollbar { @@ -1740,35 +1739,36 @@ static void ShowDemoWindowLayout() if (ImGui::TreeNode("Widgets Width")) { + // Use SetNextItemWidth() to set the width of a single upcoming item. + // Use PushItemWidth()/PopItemWidth() to set the width of a group of items. static float f = 0.0f; - ImGui::Text("PushItemWidth(100)"); + ImGui::Text("SetNextItemWidth/PushItemWidth(100)"); ImGui::SameLine(); HelpMarker("Fixed width."); - ImGui::PushItemWidth(100); + ImGui::SetNextItemWidth(100); ImGui::DragFloat("float##1", &f); - ImGui::PopItemWidth(); - ImGui::Text("PushItemWidth(GetWindowWidth() * 0.5f)"); + ImGui::Text("SetNextItemWidth/PushItemWidth(GetWindowWidth() * 0.5f)"); ImGui::SameLine(); HelpMarker("Half of window width."); - ImGui::PushItemWidth(ImGui::GetWindowWidth() * 0.5f); + ImGui::SetNextItemWidth(ImGui::GetWindowWidth() * 0.5f); ImGui::DragFloat("float##2", &f); - ImGui::PopItemWidth(); - ImGui::Text("PushItemWidth(GetContentRegionAvailWidth() * 0.5f)"); + ImGui::Text("SetNextItemWidth/PushItemWidth(GetContentRegionAvailWidth() * 0.5f)"); ImGui::SameLine(); HelpMarker("Half of available width.\n(~ right-cursor_pos)\n(works within a column set)"); - ImGui::PushItemWidth(ImGui::GetContentRegionAvailWidth() * 0.5f); + ImGui::SetNextItemWidth(ImGui::GetContentRegionAvailWidth() * 0.5f); ImGui::DragFloat("float##3", &f); - ImGui::PopItemWidth(); - ImGui::Text("PushItemWidth(-100)"); + ImGui::Text("SetNextItemWidth/PushItemWidth(-100)"); ImGui::SameLine(); HelpMarker("Align to right edge minus 100"); - ImGui::PushItemWidth(-100); + ImGui::SetNextItemWidth(-100); ImGui::DragFloat("float##4", &f); - ImGui::PopItemWidth(); - ImGui::Text("PushItemWidth(-1)"); + // Demonstrate using PushItemWidth to surround three items. Calling SetNextItemWidth() before each of them would have the same effect. + ImGui::Text("SetNextItemWidth/PushItemWidth(-1)"); ImGui::SameLine(); HelpMarker("Align to right edge"); ImGui::PushItemWidth(-1); - ImGui::DragFloat("float##5", &f); + ImGui::DragFloat("float##5a", &f); + ImGui::DragFloat("float##5b", &f); + ImGui::DragFloat("float##5c", &f); ImGui::PopItemWidth(); ImGui::TreePop(); @@ -2241,9 +2241,8 @@ static void ShowDemoWindowPopups() { if (ImGui::Selectable("Set to zero")) value = 0.0f; if (ImGui::Selectable("Set to PI")) value = 3.1415f; - ImGui::PushItemWidth(-1); + ImGui::SetNextItemWidth(-1); ImGui::DragFloat("##Value", &value, 0.1f, 0.0f, 0.0f); - ImGui::PopItemWidth(); ImGui::EndPopup(); } @@ -2968,7 +2967,7 @@ void ImGui::ShowStyleEditor(ImGuiStyle* ref) } ImGui::LogFinish(); } - ImGui::SameLine(); ImGui::PushItemWidth(120); ImGui::Combo("##output_type", &output_dest, "To Clipboard\0To TTY\0"); ImGui::PopItemWidth(); + ImGui::SameLine(); ImGui::SetNextItemWidth(120); ImGui::Combo("##output_type", &output_dest, "To Clipboard\0To TTY\0"); ImGui::SameLine(); ImGui::Checkbox("Only Modified Colors", &output_only_modified); static ImGuiTextFilter filter; @@ -3807,12 +3806,11 @@ static void ShowExampleAppPropertyEditor(bool* p_open) ImGui::AlignTextToFramePadding(); ImGui::TreeNodeEx("Field", ImGuiTreeNodeFlags_Leaf | ImGuiTreeNodeFlags_NoTreePushOnOpen | ImGuiTreeNodeFlags_Bullet, "Field_%d", i); ImGui::NextColumn(); - ImGui::PushItemWidth(-1); + ImGui::SetNextItemWidth(-1); if (i >= 5) ImGui::InputFloat("##value", &dummy_members[i], 1.0f); else ImGui::DragFloat("##value", &dummy_members[i], 0.01f); - ImGui::PopItemWidth(); ImGui::NextColumn(); } ImGui::PopID(); @@ -3952,10 +3950,10 @@ static void ShowExampleAppConstrainedResize(bool* p_open) if (ImGui::Button("200x200")) { ImGui::SetWindowSize(ImVec2(200, 200)); } ImGui::SameLine(); if (ImGui::Button("500x500")) { ImGui::SetWindowSize(ImVec2(500, 500)); } ImGui::SameLine(); if (ImGui::Button("800x200")) { ImGui::SetWindowSize(ImVec2(800, 200)); } - ImGui::PushItemWidth(200); + ImGui::SetNextItemWidth(200); ImGui::Combo("Constraint", &type, desc, IM_ARRAYSIZE(desc)); + ImGui::SetNextItemWidth(200); ImGui::DragInt("Lines", &display_lines, 0.2f, 1, 100); - ImGui::PopItemWidth(); ImGui::Checkbox("Auto-resize", &auto_resize); for (int i = 0; i < display_lines; i++) ImGui::Text("%*sHello, sailor! Making this line long enough for the example.", i * 4, ""); @@ -4401,7 +4399,7 @@ void ShowExampleAppDocuments(bool* p_open) if (ImGui::BeginPopupModal("Save?")) { ImGui::Text("Save change to the following items?"); - ImGui::PushItemWidth(-1.0f); + ImGui::SetNextItemWidth(-1.0f); if (ImGui::ListBoxHeader("##", close_queue_unsaved_documents, 6)) { for (int n = 0; n < close_queue.Size; n++) diff --git a/imgui_internal.h b/imgui_internal.h index b399becd..9107cfea 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -1146,6 +1146,7 @@ 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; @@ -1181,6 +1182,7 @@ struct IMGUI_API ImGuiWindowTempData ItemFlags = ImGuiItemFlags_Default_; ItemWidth = 0.0f; + NextItemWidth = +FLT_MAX; TextWrapPos = -1.0f; memset(StackSizesBackup, 0, sizeof(StackSizesBackup)); @@ -1438,9 +1440,10 @@ 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 = 0.0f); + IMGUI_API void PushMultiItemsWidths(int components, float width_full); IMGUI_API void PushItemFlag(ImGuiItemFlags option, bool enabled); IMGUI_API void PopItemFlag(); IMGUI_API bool IsItemToggledSelection(); // was the last item selection toggled? (after Selectable(), TreeNode() etc. We only returns toggle _event_ in order to handle clipping correctly) diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index 6812808e..d1ecf3ba 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -325,7 +325,7 @@ void ImGui::LabelTextV(const char* label, const char* fmt, va_list args) ImGuiContext& g = *GImGui; const ImGuiStyle& style = g.Style; - const float w = CalcItemWidth(); + const float w = GetNextItemWidth(); 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)); @@ -1089,7 +1089,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, CalcItemWidth(), g.FontSize + style.FramePadding.y*2.0f); + ImVec2 size = CalcItemSize(size_arg, GetNextItemWidth(), g.FontSize + style.FramePadding.y*2.0f); ImRect bb(pos, pos + size); ItemSize(size, style.FramePadding.y); if (!ItemAdd(bb, 0)) @@ -1353,7 +1353,8 @@ 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 w = (flags & ImGuiComboFlags_NoPreview) ? arrow_size : CalcItemWidth(); + const float expected_w = GetNextItemWidth(); + 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)); ItemSize(total_bb, style.FramePadding.y); @@ -1978,7 +1979,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 = CalcItemWidth(); + const float w = GetNextItemWidth(); 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)); @@ -2052,7 +2053,7 @@ bool ImGui::DragScalarN(const char* label, ImGuiDataType data_type, void* v, int bool value_changed = false; BeginGroup(); PushID(label); - PushMultiItemsWidths(components); + PushMultiItemsWidths(components, GetNextItemWidth()); size_t type_size = GDataTypeInfo[data_type].Size; for (int i = 0; i < components; i++) { @@ -2099,7 +2100,7 @@ bool ImGui::DragFloatRange2(const char* label, float* v_current_min, float* v_cu ImGuiContext& g = *GImGui; PushID(label); BeginGroup(); - PushMultiItemsWidths(2); + PushMultiItemsWidths(2, GetNextItemWidth()); 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(); @@ -2144,7 +2145,7 @@ bool ImGui::DragIntRange2(const char* label, int* v_current_min, int* v_current_ ImGuiContext& g = *GImGui; PushID(label); BeginGroup(); - PushMultiItemsWidths(2); + PushMultiItemsWidths(2, GetNextItemWidth()); 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(); @@ -2422,7 +2423,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 = CalcItemWidth(); + const float w = GetNextItemWidth(); 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)); @@ -2501,7 +2502,7 @@ bool ImGui::SliderScalarN(const char* label, ImGuiDataType data_type, void* v, i bool value_changed = false; BeginGroup(); PushID(label); - PushMultiItemsWidths(components); + PushMultiItemsWidths(components, GetNextItemWidth()); size_t type_size = GDataTypeInfo[data_type].Size; for (int i = 0; i < components; i++) { @@ -2790,10 +2791,9 @@ 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); - PushItemWidth(ImMax(1.0f, CalcItemWidth() - (button_size + style.ItemInnerSpacing.x) * 2)); + SetNextItemWidth(ImMax(1.0f, GetNextItemWidth() - (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); - PopItemWidth(); // Step buttons const ImVec2 backup_frame_padding = style.FramePadding; @@ -2839,7 +2839,7 @@ bool ImGui::InputScalarN(const char* label, ImGuiDataType data_type, void* v, in bool value_changed = false; BeginGroup(); PushID(label); - PushMultiItemsWidths(components); + PushMultiItemsWidths(components, GetNextItemWidth()); size_t type_size = GDataTypeInfo[data_type].Size; for (int i = 0; i < components; i++) { @@ -3289,7 +3289,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, CalcItemWidth(), (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, GetNextItemWidth(), (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)); @@ -4047,7 +4047,7 @@ 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 = CalcItemWidth() - w_extra; + const float w_items_all = GetNextItemWidth() - w_extra; const char* label_display_end = FindRenderedTextEnd(label); BeginGroup(); @@ -4112,13 +4112,11 @@ bool ImGui::ColorEdit4(const char* label, float col[4], ImGuiColorEditFlags flag }; const int fmt_idx = hide_prefix ? 0 : (flags & ImGuiColorEditFlags_DisplayHSV) ? 2 : 1; - PushItemWidth(w_item_one); for (int n = 0; n < components; n++) { if (n > 0) SameLine(0, style.ItemInnerSpacing.x); - if (n + 1 == components) - PushItemWidth(w_item_last); + SetNextItemWidth((n + 1 < components) ? w_item_one : w_item_last); if (flags & ImGuiColorEditFlags_Float) { value_changed |= DragFloat(ids[n], &f[n], 1.0f/255.0f, 0.0f, hdr ? 0.0f : 1.0f, fmt_table_float[fmt_idx][n]); @@ -4131,8 +4129,6 @@ bool ImGui::ColorEdit4(const char* label, float col[4], ImGuiColorEditFlags flag if (!(flags & ImGuiColorEditFlags_NoOptions)) OpenPopupOnItemClick("context"); } - PopItemWidth(); - PopItemWidth(); } else if ((flags & ImGuiColorEditFlags_DisplayHex) != 0 && (flags & ImGuiColorEditFlags_NoInputs) == 0) { @@ -4142,7 +4138,7 @@ bool ImGui::ColorEdit4(const char* label, float col[4], ImGuiColorEditFlags flag ImFormatString(buf, IM_ARRAYSIZE(buf), "#%02X%02X%02X%02X", ImClamp(i[0],0,255), ImClamp(i[1],0,255), ImClamp(i[2],0,255), ImClamp(i[3],0,255)); else ImFormatString(buf, IM_ARRAYSIZE(buf), "#%02X%02X%02X", ImClamp(i[0],0,255), ImClamp(i[1],0,255), ImClamp(i[2],0,255)); - PushItemWidth(w_items_all); + SetNextItemWidth(w_items_all); if (InputText("##Text", buf, IM_ARRAYSIZE(buf), ImGuiInputTextFlags_CharsHexadecimal | ImGuiInputTextFlags_CharsUppercase)) { value_changed = true; @@ -4157,7 +4153,6 @@ bool ImGui::ColorEdit4(const char* label, float col[4], ImGuiColorEditFlags flag } if (!(flags & ImGuiColorEditFlags_NoOptions)) OpenPopupOnItemClick("context"); - PopItemWidth(); } ImGuiWindow* picker_active_window = NULL; @@ -4190,9 +4185,8 @@ bool ImGui::ColorEdit4(const char* label, float col[4], ImGuiColorEditFlags flag } ImGuiColorEditFlags picker_flags_to_forward = ImGuiColorEditFlags__DataTypeMask | ImGuiColorEditFlags__PickerMask | ImGuiColorEditFlags__InputMask | ImGuiColorEditFlags_HDR | ImGuiColorEditFlags_NoAlpha | ImGuiColorEditFlags_AlphaBar; ImGuiColorEditFlags picker_flags = (flags_untouched & picker_flags_to_forward) | ImGuiColorEditFlags_DisplayHSV | ImGuiColorEditFlags_NoLabel | ImGuiColorEditFlags_AlphaPreviewHalf; - PushItemWidth(square_sz * 12.0f); // Use 256 + bar sizes? + SetNextItemWidth(square_sz * 12.0f); // Use 256 + bar sizes? value_changed |= ColorPicker4("##picker", col, picker_flags, &g.ColorPickerRef.x); - PopItemWidth(); EndPopup(); } } @@ -4360,7 +4354,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, CalcItemWidth() - (alpha_bar ? 2 : 1) * (bars_width + style.ItemInnerSpacing.x)); // Saturation/Value picking box + float sv_picker_size = ImMax(bars_width * 1, GetNextItemWidth() - (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); @@ -5458,7 +5452,7 @@ bool ImGui::ListBoxHeader(const char* label, const ImVec2& size_arg) 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, CalcItemWidth(), GetTextLineHeightWithSpacing() * 7.4f + style.ItemSpacing.y); + ImVec2 size = CalcItemSize(size_arg, GetNextItemWidth(), 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)); @@ -5575,7 +5569,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 = CalcItemWidth(); + frame_size.x = GetNextItemWidth(); if (frame_size.y == 0.0f) frame_size.y = label_size.y + (style.FramePadding.y * 2); From 59f012d65603c5961b6eb3f6d2a003f0ba9d100e Mon Sep 17 00:00:00 2001 From: omar Date: Fri, 19 Apr 2019 19:48:51 +0200 Subject: [PATCH 13/13] Internals: ImHashStr() default parameter. --- imgui.cpp | 16 ++++++++-------- imgui_internal.h | 4 ++-- imgui_widgets.cpp | 2 +- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 8f56ab6c..5d705e4e 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -2535,7 +2535,7 @@ ImGuiWindow::ImGuiWindow(ImGuiContext* context, const char* name) : DrawListInst(&context->DrawListSharedData) { Name = ImStrdup(name); - ID = ImHashStr(name, 0); + ID = ImHashStr(name); IDStack.push_back(ID); Flags = ImGuiWindowFlags_None; Pos = ImVec2(0.0f, 0.0f); @@ -3629,7 +3629,7 @@ void ImGui::Initialize(ImGuiContext* context) // Add .ini handle for ImGuiWindow type ImGuiSettingsHandler ini_handler; ini_handler.TypeName = "Window"; - ini_handler.TypeHash = ImHashStr("Window", 0); + ini_handler.TypeHash = ImHashStr("Window"); ini_handler.ReadOpenFn = SettingsHandlerWindow_ReadOpen; ini_handler.ReadLineFn = SettingsHandlerWindow_ReadLine; ini_handler.WriteAllFn = SettingsHandlerWindow_WriteAll; @@ -4562,7 +4562,7 @@ ImGuiWindow* ImGui::FindWindowByID(ImGuiID id) ImGuiWindow* ImGui::FindWindowByName(const char* name) { - ImGuiID id = ImHashStr(name, 0); + ImGuiID id = ImHashStr(name); return FindWindowByID(id); } @@ -8769,7 +8769,7 @@ bool ImGui::BeginDragDropSource(ImGuiDragDropFlags flags) else { window = NULL; - source_id = ImHashStr("#SourceExtern", 0); + source_id = ImHashStr("#SourceExtern"); source_drag_active = true; } @@ -9210,7 +9210,7 @@ ImGuiWindowSettings* ImGui::CreateNewWindowSettings(const char* name) g.SettingsWindows.push_back(ImGuiWindowSettings()); ImGuiWindowSettings* settings = &g.SettingsWindows.back(); settings->Name = ImStrdup(name); - settings->ID = ImHashStr(name, 0); + settings->ID = ImHashStr(name); return settings; } @@ -9225,7 +9225,7 @@ ImGuiWindowSettings* ImGui::FindWindowSettings(ImGuiID id) ImGuiWindowSettings* ImGui::FindOrCreateWindowSettings(const char* name) { - if (ImGuiWindowSettings* settings = FindWindowSettings(ImHashStr(name, 0))) + if (ImGuiWindowSettings* settings = FindWindowSettings(ImHashStr(name))) return settings; return CreateNewWindowSettings(name); } @@ -9243,7 +9243,7 @@ void ImGui::LoadIniSettingsFromDisk(const char* ini_filename) ImGuiSettingsHandler* ImGui::FindSettingsHandler(const char* type_name) { ImGuiContext& g = *GImGui; - const ImGuiID type_hash = ImHashStr(type_name, 0); + const ImGuiID type_hash = ImHashStr(type_name); for (int handler_n = 0; handler_n < g.SettingsHandlers.Size; handler_n++) if (g.SettingsHandlers[handler_n].TypeHash == type_hash) return &g.SettingsHandlers[handler_n]; @@ -9347,7 +9347,7 @@ const char* ImGui::SaveIniSettingsToMemory(size_t* out_size) static void* SettingsHandlerWindow_ReadOpen(ImGuiContext*, ImGuiSettingsHandler*, const char* name) { - ImGuiWindowSettings* settings = ImGui::FindWindowSettings(ImHashStr(name, 0)); + ImGuiWindowSettings* settings = ImGui::FindWindowSettings(ImHashStr(name)); if (!settings) settings = ImGui::CreateNewWindowSettings(name); return (void*)settings; diff --git a/imgui_internal.h b/imgui_internal.h index 9107cfea..b0a26a95 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -153,7 +153,7 @@ IMGUI_API int ImTextCountUtf8BytesFromStr(const ImWchar* in_text, cons // Helpers: Misc IMGUI_API ImU32 ImHashData(const void* data, size_t data_size, ImU32 seed = 0); -IMGUI_API ImU32 ImHashStr(const char* data, size_t data_size, ImU32 seed = 0); +IMGUI_API ImU32 ImHashStr(const char* data, size_t data_size = 0, ImU32 seed = 0); IMGUI_API void* ImFileLoadToMemory(const char* filename, const char* file_open_mode, size_t* out_file_size = NULL, int padding_bytes = 0); IMGUI_API FILE* ImFileOpen(const char* filename, const char* file_open_mode); static inline bool ImCharIsBlankA(char c) { return c == ' ' || c == '\t'; } @@ -630,7 +630,7 @@ struct ImGuiWindowSettings struct ImGuiSettingsHandler { const char* TypeName; // Short description stored in .ini file. Disallowed characters: '[' ']' - ImGuiID TypeHash; // == ImHashStr(TypeName, 0, 0) + ImGuiID TypeHash; // == ImHashStr(TypeName) void* (*ReadOpenFn)(ImGuiContext* ctx, ImGuiSettingsHandler* handler, const char* name); // Read: Called when entering into a new ini entry e.g. "[Window][Name]" void (*ReadLineFn)(ImGuiContext* ctx, ImGuiSettingsHandler* handler, void* entry, const char* line); // Read: Called for every line of text within an ini entry void (*WriteAllFn)(ImGuiContext* ctx, ImGuiSettingsHandler* handler, ImGuiTextBuffer* out_buf); // Write: Output every entries into 'out_buf' diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index d1ecf3ba..82d792d6 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -6468,7 +6468,7 @@ static ImU32 ImGui::TabBarCalcTabID(ImGuiTabBar* tab_bar, const char* label) { if (tab_bar->Flags & ImGuiTabBarFlags_DockNode) { - ImGuiID id = ImHashStr(label, 0); + ImGuiID id = ImHashStr(label); KeepAliveID(id); return id; }