Skip to content

Commit 9235352

Browse files
committed
BeginChild: Added ImGuiChildFlags_ResizeX and ImGuiChildFlags_ResizeY. (ocornut#1710)
1 parent 34a0bc4 commit 9235352

File tree

5 files changed

+68
-14
lines changed

5 files changed

+68
-14
lines changed

docs/CHANGELOG.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,9 @@ Breaking changes:
8585
Other changes:
8686

8787
- Windows:
88+
- BeginChild(): Added ImGuiChildFlags_ResizeX and ImGuiChildFlags_ResizeY to allow resizing
89+
child windows from the bottom/right border (toward layout direction). Resized child windows
90+
settings are saved and persistent in .ini file. (#1666, #1496, #1395, #1710)
8891
- BeginChild(): Added ImGuiChildFlags_Border as a replacement for 'bool border = true' parameter.
8992
- BeginChild(): Internal name used by child windows now omits the hash/id if the child
9093
window is submitted in root of id stack of parent window. Makes debugging/metrics easier

imgui.cpp

Lines changed: 38 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -5249,7 +5249,7 @@ static void FindHoveredWindow()
52495249
continue;
52505250

52515251
// Using the clipped AABB, a child window will typically be clipped by its parent (not always)
5252-
ImVec2 hit_padding = (window->Flags & (ImGuiWindowFlags_ChildWindow | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_AlwaysAutoResize)) ? padding_regular : padding_for_resize;
5252+
ImVec2 hit_padding = (window->Flags & (ImGuiWindowFlags_NoResize | ImGuiWindowFlags_AlwaysAutoResize)) ? padding_regular : padding_for_resize;
52535253
if (!window->OuterRectClipped.ContainsWithPad(g.IO.MousePos, hit_padding))
52545254
continue;
52555255

@@ -5442,22 +5442,29 @@ bool ImGui::BeginChildEx(const char* name, ImGuiID id, const ImVec2& size_arg, I
54425442
IM_ASSERT(id != 0);
54435443

54445444
// Sanity check as it is likely that some user will accidentally pass ImGuiWindowFlags into the ImGuiChildFlags argument.
5445-
const ImGuiChildFlags ImGuiChildFlags_SupportedMask_ = ImGuiChildFlags_Border | ImGuiChildFlags_AlwaysUseWindowPadding;
5445+
const ImGuiChildFlags ImGuiChildFlags_SupportedMask_ = ImGuiChildFlags_Border | ImGuiChildFlags_AlwaysUseWindowPadding | ImGuiChildFlags_ResizeX | ImGuiChildFlags_ResizeY;
54465446
IM_UNUSED(ImGuiChildFlags_SupportedMask_);
54475447
IM_ASSERT((child_flags & ~ImGuiChildFlags_SupportedMask_) == 0 && "Illegal ImGuiChildFlags value. Did you pass ImGuiWindowFlags values instead of ImGuiChildFlags?");
5448+
if (window_flags & ImGuiWindowFlags_AlwaysAutoResize)
5449+
IM_ASSERT((child_flags & (ImGuiChildFlags_ResizeX | ImGuiChildFlags_ResizeY)) == 0 && "Cannot combine ImGuiChildFlags_ResizeX/ImGuiChildFlags_ResizeY with ImGuiWindowFlags_AlwaysAutoResize.");
54485450
#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS
54495451
if (window_flags & ImGuiWindowFlags_AlwaysUseWindowPadding)
54505452
child_flags |= ImGuiChildFlags_AlwaysUseWindowPadding;
54515453
#endif
54525454

5453-
window_flags |= ImGuiWindowFlags_ChildWindow | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoSavedSettings;
5455+
window_flags |= ImGuiWindowFlags_ChildWindow | ImGuiWindowFlags_NoTitleBar;
54545456
window_flags |= (parent_window->Flags & ImGuiWindowFlags_NoMove); // Inherit the NoMove flag
54555457

5458+
if ((child_flags & (ImGuiChildFlags_ResizeX | ImGuiChildFlags_ResizeY)) == 0)
5459+
window_flags |= ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoSavedSettings;
5460+
54565461
// Forward child flags
54575462
g.NextWindowData.Flags |= ImGuiNextWindowDataFlags_HasChildFlags;
54585463
g.NextWindowData.ChildFlags = child_flags;
54595464

54605465
// Forward size
5466+
// Important: Begin() has special processing to switch condition to ImGuiCond_FirstUseEver for a given axis when ImGuiChildFlags_ResizeXXX is set.
5467+
// (the alternative would to store conditional flags per axis, which is possible but more code)
54615468
const ImVec2 content_avail = GetContentRegionAvail();
54625469
ImVec2 size = ImTrunc(size_arg);
54635470
if (size.x <= 0.0f)
@@ -5679,7 +5686,8 @@ static inline ImVec2 CalcWindowMinSize(ImGuiWindow* window)
56795686
ImVec2 size_min;
56805687
if (window->Flags & (ImGuiWindowFlags_Popup | ImGuiWindowFlags_ChildMenu | ImGuiWindowFlags_ChildWindow))
56815688
{
5682-
size_min = ImVec2(4.0f, 4.0f);
5689+
size_min.x = (window->ChildFlags & ImGuiChildFlags_ResizeX) ? g.Style.WindowMinSize.x : 4.0f;
5690+
size_min.y = (window->ChildFlags & ImGuiChildFlags_ResizeY) ? g.Style.WindowMinSize.y : 4.0f;
56835691
}
56845692
else
56855693
{
@@ -5939,7 +5947,11 @@ static int ImGui::UpdateWindowManualResize(ImGuiWindow* window, const ImVec2& si
59395947
resize_grip_col[resize_grip_n] = GetColorU32(held ? ImGuiCol_ResizeGripActive : hovered ? ImGuiCol_ResizeGripHovered : ImGuiCol_ResizeGrip);
59405948
}
59415949

5942-
const int resize_border_mask = g.IO.ConfigWindowsResizeFromEdges ? 0x0F : 0x00;
5950+
int resize_border_mask = 0x00;
5951+
if (window->Flags & ImGuiWindowFlags_ChildWindow)
5952+
resize_border_mask |= ((window->ChildFlags & ImGuiChildFlags_ResizeX) ? 0x02 : 0) | ((window->ChildFlags & ImGuiChildFlags_ResizeY) ? 0x08 : 0);
5953+
else
5954+
resize_border_mask = g.IO.ConfigWindowsResizeFromEdges ? 0x0F : 0x00;
59435955
for (int border_n = 0; border_n < 4; border_n++)
59445956
{
59455957
if ((resize_border_mask & (1 << border_n)) == 0)
@@ -5976,6 +5988,8 @@ static int ImGui::UpdateWindowManualResize(ImGuiWindow* window, const ImVec2& si
59765988
ImVec2 border_target = window->Pos;
59775989
border_target[axis] = g.IO.MousePos[axis] - g.ActiveIdClickOffset[axis] + WINDOWS_HOVER_PADDING;
59785990
border_target = ImClamp(border_target, clamp_min, clamp_max);
5991+
if (window->Flags & ImGuiWindowFlags_ChildWindow) // Clamp resizing of childs within parent
5992+
border_target = ImClamp(border_target, window->ParentWindow->InnerClipRect.Min, window->ParentWindow->InnerClipRect.Max);
59795993
CalcResizePosSizeFromAnyCorner(window, border_target, ImMin(def.SegmentN1, def.SegmentN2), &pos_target, &size_target);
59805994
}
59815995
if (hovered)
@@ -6423,6 +6437,10 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags)
64236437
{
64246438
window_size_x_set_by_api = (window->SetWindowSizeAllowFlags & g.NextWindowData.SizeCond) != 0 && (g.NextWindowData.SizeVal.x > 0.0f);
64256439
window_size_y_set_by_api = (window->SetWindowSizeAllowFlags & g.NextWindowData.SizeCond) != 0 && (g.NextWindowData.SizeVal.y > 0.0f);
6440+
if ((window->ChildFlags & ImGuiChildFlags_ResizeX) && (window->SetWindowSizeAllowFlags & ImGuiCond_FirstUseEver) == 0) // Axis-specific conditions for BeginChild()
6441+
g.NextWindowData.SizeVal.x = window->SizeFull.x;
6442+
if ((window->ChildFlags & ImGuiChildFlags_ResizeY) && (window->SetWindowSizeAllowFlags & ImGuiCond_FirstUseEver) == 0)
6443+
g.NextWindowData.SizeVal.y = window->SizeFull.y;
64266444
SetWindowSize(window, g.NextWindowData.SizeVal, g.NextWindowData.SizeCond);
64276445
}
64286446
if (g.NextWindowData.Flags & ImGuiNextWindowDataFlags_HasScroll)
@@ -6680,7 +6698,7 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags)
66806698
// Handle manual resize: Resize Grips, Borders, Gamepad
66816699
int border_hovered = -1, border_held = -1;
66826700
ImU32 resize_grip_col[4] = {};
6683-
const int resize_grip_count = g.IO.ConfigWindowsResizeFromEdges ? 2 : 1; // Allow resize from lower-left if we have the mouse cursor feedback for it.
6701+
const int resize_grip_count = (window->Flags & ImGuiWindowFlags_ChildWindow) ? 0 : g.IO.ConfigWindowsResizeFromEdges ? 2 : 1; // Allow resize from lower-left if we have the mouse cursor feedback for it.
66846702
const float resize_grip_draw_size = IM_TRUNC(ImMax(g.FontSize * 1.10f, window->WindowRounding + 1.0f + g.FontSize * 0.2f));
66856703
if (!window->Collapsed)
66866704
if (int auto_fit_mask = UpdateWindowManualResize(window, size_auto_fit, &border_hovered, &border_held, resize_grip_count, &resize_grip_col[0], visibility_rect))
@@ -13327,6 +13345,7 @@ static void WindowSettingsHandler_ReadLine(ImGuiContext*, ImGuiSettingsHandler*,
1332713345
if (sscanf(line, "Pos=%i,%i", &x, &y) == 2) { settings->Pos = ImVec2ih((short)x, (short)y); }
1332813346
else if (sscanf(line, "Size=%i,%i", &x, &y) == 2) { settings->Size = ImVec2ih((short)x, (short)y); }
1332913347
else if (sscanf(line, "Collapsed=%d", &i) == 1) { settings->Collapsed = (i != 0); }
13348+
else if (sscanf(line, "IsChild=%d", &i) == 1) { settings->IsChild = (i != 0); }
1333013349
}
1333113350

1333213351
// Apply to existing windows (if any)
@@ -13361,7 +13380,7 @@ static void WindowSettingsHandler_WriteAll(ImGuiContext* ctx, ImGuiSettingsHandl
1336113380
IM_ASSERT(settings->ID == window->ID);
1336213381
settings->Pos = ImVec2ih(window->Pos);
1336313382
settings->Size = ImVec2ih(window->SizeFull);
13364-
13383+
settings->IsChild = (window->Flags & ImGuiWindowFlags_ChildWindow) != 0;
1336513384
settings->Collapsed = window->Collapsed;
1336613385
settings->WantDelete = false;
1336713386
}
@@ -13374,10 +13393,18 @@ static void WindowSettingsHandler_WriteAll(ImGuiContext* ctx, ImGuiSettingsHandl
1337413393
continue;
1337513394
const char* settings_name = settings->GetName();
1337613395
buf->appendf("[%s][%s]\n", handler->TypeName, settings_name);
13377-
buf->appendf("Pos=%d,%d\n", settings->Pos.x, settings->Pos.y);
13378-
buf->appendf("Size=%d,%d\n", settings->Size.x, settings->Size.y);
13379-
if (settings->Collapsed)
13380-
buf->appendf("Collapsed=1\n");
13396+
if (settings->IsChild)
13397+
{
13398+
buf->appendf("IsChild=1\n");
13399+
buf->appendf("Size=%d,%d\n", settings->Size.x, settings->Size.y);
13400+
}
13401+
else
13402+
{
13403+
buf->appendf("Pos=%d,%d\n", settings->Pos.x, settings->Pos.y);
13404+
buf->appendf("Size=%d,%d\n", settings->Size.x, settings->Size.y);
13405+
if (settings->Collapsed)
13406+
buf->appendf("Collapsed=1\n");
13407+
}
1338113408
buf->append("\n");
1338213409
}
1338313410
}

imgui.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1022,6 +1022,8 @@ enum ImGuiChildFlags_
10221022
ImGuiChildFlags_None = 0,
10231023
ImGuiChildFlags_Border = 1 << 0, // Show an outer border and enable WindowPadding. (Important: this is always == 1 for legacy reason)
10241024
ImGuiChildFlags_AlwaysUseWindowPadding = 1 << 1, // Pad with style.WindowPadding even if no border are drawn (no padding by default for non-bordered child windows because it makes more sense)
1025+
ImGuiChildFlags_ResizeX = 1 << 2, // Allow resize from right border (layout direction). Enable .ini saving (unless ImGuiWindowFlags_NoSavedSettings passed to window flags)
1026+
ImGuiChildFlags_ResizeY = 1 << 3, // Allow resize from bottom border (layout direction). "
10251027
};
10261028

10271029
// Flags for ImGui::InputText()

imgui_demo.cpp

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2764,6 +2764,18 @@ static void ShowDemoWindowLayout()
27642764
ImGui::PopStyleVar();
27652765
}
27662766

2767+
// Child 3: manual-resize
2768+
ImGui::SeparatorText("Manual-resize");
2769+
{
2770+
HelpMarker("Drag bottom border to resize. Double-click bottom border to auto-fit to vertical contents.");
2771+
ImGui::PushStyleColor(ImGuiCol_ChildBg, ImGui::GetStyleColorVec4(ImGuiCol_FrameBg));
2772+
ImGui::BeginChild("ResizableChild", ImVec2(-FLT_MIN, ImGui::GetTextLineHeightWithSpacing() * 8), ImGuiChildFlags_Border | ImGuiChildFlags_ResizeY);
2773+
ImGui::PopStyleColor();
2774+
for (int n = 0; n < 10; n++)
2775+
ImGui::Text("Line %04d", n);
2776+
ImGui::EndChild();
2777+
}
2778+
27672779
ImGui::SeparatorText("Misc/Advanced");
27682780

27692781
// Demonstrate a few extra things
@@ -2775,13 +2787,22 @@ static void ShowDemoWindowLayout()
27752787
// the POV of the parent window). See 'Demo->Querying Status (Edited/Active/Hovered etc.)' for details.
27762788
{
27772789
static int offset_x = 0;
2790+
static bool override_bg_color = true;
2791+
static ImGuiChildFlags child_flags = ImGuiChildFlags_Border | ImGuiChildFlags_ResizeX | ImGuiChildFlags_ResizeY;
27782792
ImGui::SetNextItemWidth(ImGui::GetFontSize() * 8);
27792793
ImGui::DragInt("Offset X", &offset_x, 1.0f, -1000, 1000);
2794+
ImGui::Checkbox("Override ChildBg color", &override_bg_color);
2795+
ImGui::CheckboxFlags("ImGuiChildFlags_Border", &child_flags, ImGuiChildFlags_Border);
2796+
ImGui::CheckboxFlags("ImGuiChildFlags_AlwaysUseWindowPadding", &child_flags, ImGuiChildFlags_AlwaysUseWindowPadding);
2797+
ImGui::CheckboxFlags("ImGuiChildFlags_ResizeX", &child_flags, ImGuiChildFlags_ResizeX);
2798+
ImGui::CheckboxFlags("ImGuiChildFlags_ResizeY", &child_flags, ImGuiChildFlags_ResizeY);
27802799

27812800
ImGui::SetCursorPosX(ImGui::GetCursorPosX() + (float)offset_x);
2782-
ImGui::PushStyleColor(ImGuiCol_ChildBg, IM_COL32(255, 0, 0, 100));
2783-
ImGui::BeginChild("Red", ImVec2(200, 100), ImGuiChildFlags_Border, ImGuiWindowFlags_None);
2784-
ImGui::PopStyleColor();
2801+
if (override_bg_color)
2802+
ImGui::PushStyleColor(ImGuiCol_ChildBg, IM_COL32(255, 0, 0, 100));
2803+
ImGui::BeginChild("Red", ImVec2(200, 100), child_flags, ImGuiWindowFlags_None);
2804+
if (override_bg_color)
2805+
ImGui::PopStyleColor();
27852806

27862807
for (int n = 0; n < 50; n++)
27872808
ImGui::Text("Some test %d", n);

imgui_internal.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1712,6 +1712,7 @@ struct ImGuiWindowSettings
17121712
ImVec2ih Pos;
17131713
ImVec2ih Size;
17141714
bool Collapsed;
1715+
bool IsChild;
17151716
bool WantApply; // Set when loaded from .ini data (to enable merging/loading .ini data into an already running context)
17161717
bool WantDelete; // Set to invalidate/delete the settings entry
17171718

0 commit comments

Comments
 (0)