Skip to content

Commit 9b27394

Browse files
thedmdpthom
authored andcommitted
thedmd: Stack Layout implementation v2.1 / pthom: revert clipping
See ocornut#846 (comment) : clipping has an issue, when mixed with your node editor and springs. # Conflicts: # imgui.h
1 parent 5b41d2f commit 9b27394

File tree

7 files changed

+1403
-5
lines changed

7 files changed

+1403
-5
lines changed

imgui.cpp

Lines changed: 40 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1444,6 +1444,7 @@ ImGuiStyle::ImGuiStyle()
14441444
ScrollbarPadding = 2.0f; // Padding of scrollbar grab within its frame (same for both axises)
14451445
GrabMinSize = 12.0f; // Minimum width/height of a grab box for slider/scrollbar
14461446
GrabRounding = 0.0f; // Radius of grabs corners rounding. Set to 0.0f to have rectangular slider grabs.
1447+
LayoutAlign = 0.5f; // Element alignment inside horizontal and vertical layouts (0.0f - left/top, 1.0f - right/bottom, 0.5f - center).
14471448
LogSliderDeadzone = 4.0f; // The size in pixels of the dead-zone around zero on logarithmic sliders that cross zero.
14481449
ImageBorderSize = 0.0f; // Thickness of border around tabs.
14491450
TabRounding = 5.0f; // Radius of upper corners of a tab. Set to 0.0f to have rectangular tabs.
@@ -3631,7 +3632,8 @@ static const ImGuiStyleVarInfo GStyleVarsInfo[] =
36313632
{ 1, ImGuiDataType_Float, (ImU32)offsetof(ImGuiStyle, ScrollbarPadding) }, // ImGuiStyleVar_ScrollbarPadding
36323633
{ 1, ImGuiDataType_Float, (ImU32)offsetof(ImGuiStyle, GrabMinSize) }, // ImGuiStyleVar_GrabMinSize
36333634
{ 1, ImGuiDataType_Float, (ImU32)offsetof(ImGuiStyle, GrabRounding) }, // ImGuiStyleVar_GrabRounding
3634-
{ 1, ImGuiDataType_Float, (ImU32)offsetof(ImGuiStyle, ImageBorderSize) }, // ImGuiStyleVar_ImageBorderSize
3635+
{ 1, ImGuiDataType_Float, (ImU32)offsetof(ImGuiStyle, ImageBorderSize) }, // ImGuiStyleVar_ImageBorderSize
3636+
{ 1, ImGuiDataType_Float, (ImU32)offsetof(ImGuiStyle, LayoutAlign) }, // ImGuiStyleVar_LayoutAlign
36353637
{ 1, ImGuiDataType_Float, (ImU32)offsetof(ImGuiStyle, TabRounding) }, // ImGuiStyleVar_TabRounding
36363638
{ 1, ImGuiDataType_Float, (ImU32)offsetof(ImGuiStyle, TabBorderSize) }, // ImGuiStyleVar_TabBorderSize
36373639
{ 1, ImGuiDataType_Float, (ImU32)offsetof(ImGuiStyle, TabMinWidthBase) }, // ImGuiStyleVar_TabMinWidthBase
@@ -11882,6 +11884,10 @@ bool ImGui::ItemAdd(const ImRect& bb, ImGuiID id, const ImRect* nav_bb_arg, ImGu
1188211884
g.NextItemData.HasFlags = ImGuiNextItemDataFlags_None;
1188311885
g.NextItemData.ItemFlags = ImGuiItemFlags_None;
1188411886

11887+
#if IMGUI_HAS_STACK_LAYOUT
11888+
ImGuiInternal::UpdateItemRect(window->ID, bb.Min, bb.Max);
11889+
#endif
11890+
1188511891
#ifdef IMGUI_ENABLE_TEST_ENGINE
1188611892
if (id != 0)
1188711893
IMGUI_TEST_ENGINE_ITEM_ADD(id, g.LastItemData.NavRect, &g.LastItemData);
@@ -11981,6 +11987,38 @@ void ImGui::ItemSize(const ImVec2& size, float text_baseline_y)
1198111987
if (window->SkipItems)
1198211988
return;
1198311989

11990+
#if IMGUI_HAS_STACK_LAYOUT
11991+
ImGuiLayoutType layout_type = ImGuiInternal::GetCurrentLayoutType(window->ID);
11992+
#else
11993+
ImGuiLayoutType layout_type = window->DC.LayoutType;
11994+
#endif
11995+
11996+
//if (g.IO.KeyAlt) window->DrawList->AddCircle(window->DC.CursorPos, 3.0f, IM_COL32(255,255,0,255), 4); // [DEBUG] Widget position
11997+
11998+
// Stack Layouts: Handle horizontal case first to simplify merge in case code handling vertical changes.
11999+
if (layout_type == ImGuiLayoutType_Horizontal)
12000+
{
12001+
const float line_width = ImMax(window->DC.CurrLineSize.x, size.x);
12002+
12003+
// Always align ourselves on pixel boundaries
12004+
//if (g.IO.KeyAlt) window->DrawList->AddRect(window->DC.CursorPos, window->DC.CursorPos + ImVec2(size.x, line_height), IM_COL32(255,0,0,200)); // [DEBUG]
12005+
window->DC.CursorPosPrevLine.x = window->DC.CursorPos.x;
12006+
window->DC.CursorPosPrevLine.y = window->DC.CursorPos.y + size.y;
12007+
window->DC.CursorPos.x = IM_TRUNC(window->DC.CursorPos.x + line_width + g.Style.ItemSpacing.x);
12008+
window->DC.CursorPos.y = IM_TRUNC(window->DC.CursorPosPrevLine.y - size.y);
12009+
window->DC.CursorMaxPos.x = ImMax(window->DC.CursorMaxPos.x, window->DC.CursorPos.x - g.Style.ItemSpacing.x);
12010+
window->DC.CursorMaxPos.y = ImMax(window->DC.CursorMaxPos.y, window->DC.CursorPosPrevLine.y);
12011+
//if (g.IO.KeyAlt) window->DrawList->AddCircle(window->DC.CursorMaxPos, 3.0f, IM_COL32(255,0,0,255), 4); // [DEBUG]
12012+
12013+
window->DC.PrevLineSize.x = line_width;
12014+
window->DC.PrevLineSize.y = 0.0f;
12015+
window->DC.CurrLineSize.x = 0.0f;
12016+
window->DC.PrevLineTextBaseOffset = ImMax(window->DC.CurrLineTextBaseOffset, text_baseline_y);
12017+
window->DC.CurrLineTextBaseOffset = window->DC.PrevLineTextBaseOffset;
12018+
window->DC.IsSameLine = window->DC.IsSetPos = false;
12019+
return;
12020+
}
12021+
1198412022
// We increase the height in this function to accommodate for baseline offset.
1198512023
// In theory we should be offsetting the starting position (window->DC.CursorPos), that will be the topic of a larger refactor,
1198612024
// but since ItemSize() is not yet an API that moves the cursor (to handle e.g. wrapping) enlarging the height has the same effect.
@@ -11999,15 +12037,12 @@ void ImGui::ItemSize(const ImVec2& size, float text_baseline_y)
1199912037
window->DC.CursorMaxPos.y = ImMax(window->DC.CursorMaxPos.y, window->DC.CursorPos.y - g.Style.ItemSpacing.y);
1200012038
//if (g.IO.KeyAlt) window->DrawList->AddCircle(window->DC.CursorMaxPos, 3.0f, IM_COL32(255,0,0,255), 4); // [DEBUG]
1200112039

12040+
window->DC.PrevLineSize.x = 0.0f;
1200212041
window->DC.PrevLineSize.y = line_height;
1200312042
window->DC.CurrLineSize.y = 0.0f;
1200412043
window->DC.PrevLineTextBaseOffset = ImMax(window->DC.CurrLineTextBaseOffset, text_baseline_y);
1200512044
window->DC.CurrLineTextBaseOffset = 0.0f;
1200612045
window->DC.IsSameLine = window->DC.IsSetPos = false;
12007-
12008-
// Horizontal layout mode
12009-
if (window->DC.LayoutType == ImGuiLayoutType_Horizontal)
12010-
SameLine();
1201112046
}
1201212047
IM_MSVC_RUNTIME_CHECKS_RESTORE
1201312048

imgui.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,8 @@
3434
#define IMGUI_HAS_TEXTURES // Added ImGuiBackendFlags_RendererHasTextures - from IMGUI_VERSION_NUM >= 19198
3535
#define IMGUI_HAS_VIEWPORT // In 'docking' WIP branch.
3636
#define IMGUI_HAS_DOCK // In 'docking' WIP branch.
37+
#define IMGUI_HAS_STACK_LAYOUT 1 // Stack-Layout PR #846
38+
3739

3840
//
3941
// Adaptations for ImGui Bundle are noted with [ADAPT_IMGUI_BUNDLE]
@@ -1962,6 +1964,7 @@ enum ImGuiStyleVar_
19621964
ImGuiStyleVar_GrabMinSize, // float GrabMinSize
19631965
ImGuiStyleVar_GrabRounding, // float GrabRounding
19641966
ImGuiStyleVar_ImageBorderSize, // float ImageBorderSize
1967+
ImGuiStyleVar_LayoutAlign, // float LayoutAlign
19651968
ImGuiStyleVar_TabRounding, // float TabRounding
19661969
ImGuiStyleVar_TabBorderSize, // float TabBorderSize
19671970
ImGuiStyleVar_TabMinWidthBase, // float TabMinWidthBase
@@ -2469,6 +2472,7 @@ struct ImGuiStyle
24692472
float ScrollbarPadding; // Padding of scrollbar grab within its frame (same for both axises).
24702473
float GrabMinSize; // Minimum width/height of a grab box for slider/scrollbar.
24712474
float GrabRounding; // Radius of grabs corners rounding. Set to 0.0f to have rectangular slider grabs.
2475+
float LayoutAlign; // Element alignment inside horizontal and vertical layouts (0.0f - left/top, 1.0f - right/bottom, 0.5f - center).
24722476
float LogSliderDeadzone; // The size in pixels of the dead-zone around zero on logarithmic sliders that cross zero.
24732477
float ImageBorderSize; // Thickness of border around Image() calls.
24742478
float TabRounding; // Radius of upper corners of a tab. Set to 0.0f to have rectangular tabs.
@@ -4587,6 +4591,10 @@ typedef ImFontAtlasRect ImFontAtlasCustomRect;
45874591
#pragma warning (pop)
45884592
#endif
45894593

4594+
#if IMGUI_HAS_STACK_LAYOUT
4595+
#include "imgui_stacklayout.h"
4596+
#endif
4597+
45904598
// Include imgui_user.h at the end of imgui.h
45914599
// May be convenient for some users to only explicitly include vanilla imgui.h and have extra stuff included.
45924600
#ifdef IMGUI_INCLUDE_IMGUI_USER_H

imgui_demo.cpp

Lines changed: 150 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5286,6 +5286,156 @@ static void DemoWindowLayout()
52865286

52875287
ImGui::TreePop();
52885288
}
5289+
5290+
#if IMGUI_HAS_STACK_LAYOUT
5291+
IMGUI_DEMO_MARKER("Layout/Stack Layout");
5292+
if (ImGui::TreeNode("Stack Layout"))
5293+
{
5294+
static bool widget_a = true, widget_b = true, widget_c = true;
5295+
static bool spring_a = true, spring_ab = true, spring_bc = true, spring_c = true;
5296+
static bool minimize_width = false, minimize_height = true;
5297+
static bool horizontal = true, draw_springs = true;
5298+
static ImVec2 item_spacing = ImGui::GetStyle().ItemSpacing;
5299+
static float a_c_spring_weight = 0.0f;
5300+
static float ab_spring_weight = 0.5f;
5301+
static float alignment = 0.5f;
5302+
5303+
struct funcs
5304+
{
5305+
static void VisibleSpring(float spring_weight)
5306+
{
5307+
ImGui::Spring(spring_weight);
5308+
if (!draw_springs)
5309+
return;
5310+
5311+
ImVec2 rect_min = ImGui::GetItemRectMin();
5312+
ImVec2 rect_max = ImGui::GetItemRectMax();
5313+
5314+
ImVec2 rect_size = ImGui::GetItemRectSize();
5315+
if (rect_size.x <= 0.0f && rect_size.y <= 0.0f)
5316+
return;
5317+
5318+
// Draw zig-zag
5319+
float width = 0.0f, spacing = 0.0f;
5320+
ImVec2 direction, origin;
5321+
ImVec2 spacing_min, spring_max;
5322+
5323+
if (horizontal)
5324+
{
5325+
spacing = floorf(item_spacing.x);
5326+
width = rect_size.x - spacing;
5327+
origin = ImVec2(floorf(rect_min.x), floorf(rect_min.y + (rect_max.y - rect_min.y) / 2));
5328+
direction = ImVec2(1.0f, 0.0f);
5329+
spring_max = ImVec2(rect_min.x + width, rect_max.y);
5330+
spacing_min = ImVec2(rect_min.x + width, rect_min.y);
5331+
}
5332+
else
5333+
{
5334+
spacing = floorf(item_spacing.y);
5335+
width = rect_size.y - spacing;
5336+
origin = ImVec2(floorf(rect_min.x + (rect_max.x - rect_min.x) / 2), floorf(rect_min.y));
5337+
direction = ImVec2(0.0f, 1.0f);
5338+
spring_max = ImVec2(rect_max.x, rect_min.y + width);
5339+
spacing_min = ImVec2(rect_min.x, rect_min.y + width);
5340+
}
5341+
5342+
if (spring_weight <= 0.0f && spacing <= 0.0f)
5343+
return;
5344+
5345+
ImDrawList* draw_list = ImGui::GetWindowDrawList();
5346+
5347+
draw_list->PushClipRect(rect_min, rect_max, true);
5348+
5349+
draw_list->AddRectFilled(rect_min, spring_max, ImColor(80, 20, 80));
5350+
draw_list->AddRectFilled(spacing_min, rect_max, ImColor(80, 20, 20));
5351+
5352+
const float zig_zag_size = 3;
5353+
ImVec2 normal = ImVec2(-direction.y, direction.x);
5354+
5355+
draw_list->PathClear();
5356+
origin.x += 0.5f;
5357+
origin.y += 0.5f;
5358+
draw_list->PathLineTo(origin);
5359+
for (float x = zig_zag_size * 0.5f; x <= width; x += zig_zag_size)
5360+
{
5361+
ImVec2 p;
5362+
p.x = origin.x + direction.x * x + normal.x * zig_zag_size;
5363+
p.y = origin.y + direction.y * x + normal.y * zig_zag_size;
5364+
draw_list->PathLineTo(p);
5365+
normal = ImVec2(-normal.x, -normal.y);
5366+
}
5367+
draw_list->PathStroke(ImColor(255, 255, 255, 190), false, 1.0f);
5368+
5369+
draw_list->PopClipRect();
5370+
}
5371+
};
5372+
5373+
ImGui::Checkbox("Widget A", &widget_a); ImGui::SameLine();
5374+
ImGui::Checkbox("Widget B", &widget_b); ImGui::SameLine();
5375+
ImGui::Checkbox("Widget C", &widget_c);
5376+
ImGui::Checkbox("Spring A", &spring_a); ImGui::SameLine();
5377+
ImGui::Checkbox("Spring AB", &spring_ab); ImGui::SameLine();
5378+
ImGui::Checkbox("Spring BC", &spring_bc); ImGui::SameLine();
5379+
ImGui::Checkbox("Spring C", &spring_c);
5380+
ImGui::Checkbox("Horizontal", &horizontal); ImGui::SameLine();
5381+
ImGui::Checkbox("Minimize Width", &minimize_width); ImGui::SameLine();
5382+
ImGui::Checkbox("Minimize Height", &minimize_height);
5383+
ImGui::Checkbox("Draw Springs", &draw_springs); ImGui::SameLine();
5384+
ImGui::TextUnformatted(" "); ImGui::SameLine();
5385+
ImGui::ColorButton("- Spring", ImColor(80, 20, 80), ImGuiColorEditFlags_NoTooltip | ImGuiColorEditFlags_NoPicker); ImGui::SameLine();
5386+
ImGui::TextUnformatted("Spring"); ImGui::SameLine();
5387+
ImGui::TextUnformatted(" "); ImGui::SameLine();
5388+
ImGui::ColorButton("- Spacing", ImColor(80, 20, 20), ImGuiColorEditFlags_NoTooltip | ImGuiColorEditFlags_NoPicker); ImGui::SameLine();
5389+
ImGui::TextUnformatted("Item Spacing");
5390+
ImGui::DragFloat("Item Spacing", horizontal ? &item_spacing.x : &item_spacing.y, 0.1f, 0.0f, 50.0f);
5391+
ImGui::DragFloat("A & C Spring Weight", &a_c_spring_weight, 0.002f, 0.0f, 1.0f);
5392+
ImGui::DragFloat("AB Spring Weight", &ab_spring_weight, 0.002f, 0.0f, 1.0f);
5393+
if (ImGui::IsItemHovered()) ImGui::SetTooltip("BC Spring Weight = 1 - AB Spring Weight");
5394+
ImGui::DragFloat("Minor Axis Alignment", &alignment, 0.002f, 0.0f, 1.0f);
5395+
if (ImGui::IsItemHovered()) ImGui::SetTooltip("This is vertical alignment for horizontal layouts and horizontal alignment for vertical layouts.");
5396+
ImGui::Text("Layout widgets:");
5397+
ImGui::Text("| Spring A | Widget A | Spring AB | Widget B | Spring BC | Widget C | Spring C |");
5398+
5399+
ImGui::Spacing();
5400+
5401+
ImVec2 widget_size;
5402+
widget_size.x = floorf(ImGui::GetContentRegionAvail().x / 4);
5403+
widget_size.y = horizontal ? floorf(widget_size.x / 3) : widget_size.x;
5404+
5405+
ImVec2 small_widget_size = widget_size;
5406+
if (horizontal)
5407+
small_widget_size.y = floorf(small_widget_size.y / 2);
5408+
else
5409+
small_widget_size.x = floorf(small_widget_size.x / 2);
5410+
5411+
ImVec2 layout_size = ImVec2(widget_size.x * 4, widget_size.y * 4);
5412+
if (minimize_width) layout_size.x = 0.0f;
5413+
if (minimize_height) layout_size.y = 0.0f;
5414+
5415+
// Minor axis alignment can be set by style or directly in BeginHorizontal/BeginVertical
5416+
// Example:
5417+
// ImGui::PushStyleVar(ImGuiStyleVar_LayoutAlign, alignment);
5418+
5419+
ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(floorf(item_spacing.x), floorf(item_spacing.y)));
5420+
5421+
if (horizontal) { ImGui::BeginHorizontal("h1", layout_size, alignment); } else { ImGui::BeginVertical("v1", layout_size, alignment); }
5422+
if (spring_a) { funcs::VisibleSpring(a_c_spring_weight); }
5423+
if (widget_a) { ImGui::Button("Widget A", widget_size); }
5424+
if (spring_ab) { funcs::VisibleSpring(ab_spring_weight); }
5425+
if (widget_b) { ImGui::Button("Widget B", small_widget_size); }
5426+
if (spring_bc) { funcs::VisibleSpring(1.0f - ab_spring_weight); }
5427+
if (widget_c) { ImGui::Button("Widget C", widget_size); }
5428+
if (spring_c) { funcs::VisibleSpring(a_c_spring_weight); }
5429+
if (horizontal) { ImGui::EndHorizontal(); } else { ImGui::EndVertical(); }
5430+
5431+
ImGui::PopStyleVar();
5432+
5433+
ImDrawList* draw_list = ImGui::GetWindowDrawList();
5434+
draw_list->AddRect(ImGui::GetItemRectMin(), ImGui::GetItemRectMax(), ImGui::GetColorU32(ImGuiCol_Border));
5435+
5436+
ImGui::TreePop();
5437+
}
5438+
#endif // IMGUI_HAS_STACK_LAYOUT
52895439
}
52905440

52915441
//-----------------------------------------------------------------------------

imgui_internal.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ Index of this file:
1111
// [SECTION] Forward declarations
1212
// [SECTION] Context pointer
1313
// [SECTION] STB libraries includes
14+
// [SECTION] Stack Layout includes
1415
// [SECTION] Macros
1516
// [SECTION] Generic helpers
1617
// [SECTION] ImDrawList support
@@ -248,6 +249,14 @@ typedef ImU16 ImGuiTableDrawChannelIdx;
248249
extern IMGUI_API ImGuiContext* GImGui; // Current implicit context pointer
249250
#endif
250251

252+
//-------------------------------------------------------------------------
253+
// [SECTION] Stack Layout includes
254+
//-------------------------------------------------------------------------
255+
256+
#if IMGUI_HAS_STACK_LAYOUT
257+
# include "imgui_stacklayout_internal.h"
258+
#endif
259+
251260
//-----------------------------------------------------------------------------
252261
// [SECTION] Macros
253262
//-----------------------------------------------------------------------------

0 commit comments

Comments
 (0)