diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index 4e276e1de..f7c637cab 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -712,6 +712,8 @@ jobs:
# Fix SDK and toolset for samples that require newer SDK/toolset. At the moment it is only dx12.
(Get-Content $_.FullName) -Replace "v140","v142" | Set-Content -Path $_.FullName
(Get-Content $_.FullName) -Replace "10.0.14393.0","10.0.20348.0" | Set-Content -Path $_.FullName
+ # Stack Layout: the test engine's projects do not list imgui_stacklayout.cpp.
+ (Get-Content $_.FullName) -Replace '^(\s*)','$1$&' | Set-Content -Path $_.FullName
}
- name: Build Tests
@@ -756,7 +758,10 @@ jobs:
- name: Build Tests
working-directory: ${{ github.workspace }}/imgui_test_engine/imgui_test_suite
- run: make -j$(nproc)
+ run: |
+ # Stack Layout: the test engine's Makefile does not list imgui_stacklayout.cpp.
+ sed -i 's|$(IMGUI_DIR)/imgui_tables.cpp|$(IMGUI_DIR)/imgui_stacklayout.cpp $(IMGUI_DIR)/imgui_tables.cpp|' Makefile
+ make -j$(nproc)
- name: Run Tests
working-directory: ${{ github.workspace }}/imgui_test_engine/imgui_test_suite
diff --git a/examples/example_allegro5/example_allegro5.vcxproj b/examples/example_allegro5/example_allegro5.vcxproj
index 36c55bb10..e5d3ffbfd 100644
--- a/examples/example_allegro5/example_allegro5.vcxproj
+++ b/examples/example_allegro5/example_allegro5.vcxproj
@@ -164,6 +164,7 @@
+
@@ -174,6 +175,8 @@
+
+
diff --git a/examples/example_allegro5/example_allegro5.vcxproj.filters b/examples/example_allegro5/example_allegro5.vcxproj.filters
index 84881d371..99a9e8ce9 100644
--- a/examples/example_allegro5/example_allegro5.vcxproj.filters
+++ b/examples/example_allegro5/example_allegro5.vcxproj.filters
@@ -28,6 +28,9 @@
sources
+
+ imgui
+
imgui
@@ -45,6 +48,12 @@
imgui
+
+ imgui
+
+
+ imgui
+
sources
diff --git a/examples/example_android_opengl3/CMakeLists.txt b/examples/example_android_opengl3/CMakeLists.txt
index 63531f4dc..87e8aa186 100644
--- a/examples/example_android_opengl3/CMakeLists.txt
+++ b/examples/example_android_opengl3/CMakeLists.txt
@@ -11,6 +11,7 @@ add_library(${CMAKE_PROJECT_NAME} SHARED
${CMAKE_CURRENT_SOURCE_DIR}/../../imgui.cpp
${CMAKE_CURRENT_SOURCE_DIR}/../../imgui_demo.cpp
${CMAKE_CURRENT_SOURCE_DIR}/../../imgui_draw.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/../../imgui_stacklayout.cpp
${CMAKE_CURRENT_SOURCE_DIR}/../../imgui_tables.cpp
${CMAKE_CURRENT_SOURCE_DIR}/../../imgui_widgets.cpp
${CMAKE_CURRENT_SOURCE_DIR}/../../backends/imgui_impl_android.cpp
diff --git a/examples/example_apple_metal/Makefile b/examples/example_apple_metal/Makefile
index 9412c9b53..937da71e2 100644
--- a/examples/example_apple_metal/Makefile
+++ b/examples/example_apple_metal/Makefile
@@ -3,7 +3,7 @@ CXX = clang++
EXE = example_apple_metal
IMGUI_DIR = ../../
SOURCES = main.mm
-SOURCES += $(IMGUI_DIR)/imgui.cpp $(IMGUI_DIR)/imgui_demo.cpp $(IMGUI_DIR)/imgui_draw.cpp $(IMGUI_DIR)/imgui_tables.cpp $(IMGUI_DIR)/imgui_widgets.cpp
+SOURCES += $(IMGUI_DIR)/imgui.cpp $(IMGUI_DIR)/imgui_demo.cpp $(IMGUI_DIR)/imgui_draw.cpp $(IMGUI_DIR)/imgui_stacklayout.cpp $(IMGUI_DIR)/imgui_tables.cpp $(IMGUI_DIR)/imgui_widgets.cpp
SOURCES += $(IMGUI_DIR)/backends/imgui_impl_osx.mm $(IMGUI_DIR)/backends/imgui_impl_metal.mm
CXXFLAGS = -std=c++11 -ObjC++ -fobjc-arc -Wall -Wextra -I$(IMGUI_DIR) -I$(IMGUI_DIR)/backends
diff --git a/examples/example_apple_metal/example_apple_metal.xcodeproj/project.pbxproj b/examples/example_apple_metal/example_apple_metal.xcodeproj/project.pbxproj
index bf3c80d6e..dc0bb2def 100644
--- a/examples/example_apple_metal/example_apple_metal.xcodeproj/project.pbxproj
+++ b/examples/example_apple_metal/example_apple_metal.xcodeproj/project.pbxproj
@@ -10,6 +10,7 @@
05318E0F274C397200A8DE2E /* GameController.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 05318E0E274C397200A8DE2E /* GameController.framework */; };
07A82ED82139413D0078D120 /* imgui_widgets.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 07A82ED72139413C0078D120 /* imgui_widgets.cpp */; };
07A82ED92139418F0078D120 /* imgui_widgets.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 07A82ED72139413C0078D120 /* imgui_widgets.cpp */; };
+ 5A1A002E257677DB0038A28D /* imgui_stacklayout.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5A1A002D257677DB0038A28D /* imgui_stacklayout.cpp */; };
5079822E257677DB0038A28D /* imgui_tables.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5079822D257677DB0038A28D /* imgui_tables.cpp */; };
8309BD8F253CCAAA0045E2A1 /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8309BD8E253CCAAA0045E2A1 /* UIKit.framework */; };
8309BDA5253CCC070045E2A1 /* main.mm in Sources */ = {isa = PBXBuildFile; fileRef = 8309BDA0253CCBC10045E2A1 /* main.mm */; };
@@ -36,6 +37,7 @@
05318E0E274C397200A8DE2E /* GameController.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = GameController.framework; path = System/Library/Frameworks/GameController.framework; sourceTree = SDKROOT; };
07A82ED62139413C0078D120 /* imgui_internal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = imgui_internal.h; path = ../../imgui_internal.h; sourceTree = ""; };
07A82ED72139413C0078D120 /* imgui_widgets.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = imgui_widgets.cpp; path = ../../imgui_widgets.cpp; sourceTree = ""; };
+ 5A1A002D257677DB0038A28D /* imgui_stacklayout.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = imgui_stacklayout.cpp; path = ../../imgui_stacklayout.cpp; sourceTree = ""; };
5079822D257677DB0038A28D /* imgui_tables.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = imgui_tables.cpp; path = ../../imgui_tables.cpp; sourceTree = ""; };
8307E7C420E9F9C900473790 /* example_apple_metal.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = example_apple_metal.app; sourceTree = BUILT_PRODUCTS_DIR; };
8307E7DA20E9F9C900473790 /* example_apple_metal.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = example_apple_metal.app; sourceTree = BUILT_PRODUCTS_DIR; };
@@ -152,6 +154,7 @@
83BBE9F020EB544400295997 /* imgui */ = {
isa = PBXGroup;
children = (
+ 5A1A002D257677DB0038A28D /* imgui_stacklayout.cpp */,
5079822D257677DB0038A28D /* imgui_tables.cpp */,
8309BDB5253CCC9D0045E2A1 /* imgui_impl_metal.mm */,
8309BDB6253CCC9D0045E2A1 /* imgui_impl_osx.mm */,
@@ -270,6 +273,7 @@
83BBEA0920EB54E700295997 /* imgui.cpp in Sources */,
83BBEA0720EB54E700295997 /* imgui_demo.cpp in Sources */,
83BBEA0520EB54E700295997 /* imgui_draw.cpp in Sources */,
+ 5A1A002E257677DB0038A28D /* imgui_stacklayout.cpp in Sources */,
5079822E257677DB0038A28D /* imgui_tables.cpp in Sources */,
07A82ED82139413D0078D120 /* imgui_widgets.cpp in Sources */,
8309BDA5253CCC070045E2A1 /* main.mm in Sources */,
@@ -285,6 +289,7 @@
83BBEA0A20EB54E700295997 /* imgui.cpp in Sources */,
83BBEA0820EB54E700295997 /* imgui_demo.cpp in Sources */,
83BBEA0620EB54E700295997 /* imgui_draw.cpp in Sources */,
+ 5A1A002E257677DB0038A28D /* imgui_stacklayout.cpp in Sources */,
5079822E257677DB0038A28D /* imgui_tables.cpp in Sources */,
07A82ED92139418F0078D120 /* imgui_widgets.cpp in Sources */,
8309BDA8253CCC080045E2A1 /* main.mm in Sources */,
diff --git a/examples/example_apple_metal4/Makefile b/examples/example_apple_metal4/Makefile
index 35cdac769..818a5dabe 100644
--- a/examples/example_apple_metal4/Makefile
+++ b/examples/example_apple_metal4/Makefile
@@ -3,7 +3,7 @@ CXX = clang++
EXE = example_apple_metal4
IMGUI_DIR = ../../
SOURCES = main.mm
-SOURCES += $(IMGUI_DIR)/imgui.cpp $(IMGUI_DIR)/imgui_demo.cpp $(IMGUI_DIR)/imgui_draw.cpp $(IMGUI_DIR)/imgui_tables.cpp $(IMGUI_DIR)/imgui_widgets.cpp
+SOURCES += $(IMGUI_DIR)/imgui.cpp $(IMGUI_DIR)/imgui_demo.cpp $(IMGUI_DIR)/imgui_draw.cpp $(IMGUI_DIR)/imgui_stacklayout.cpp $(IMGUI_DIR)/imgui_tables.cpp $(IMGUI_DIR)/imgui_widgets.cpp
SOURCES += $(IMGUI_DIR)/backends/imgui_impl_osx.mm $(IMGUI_DIR)/backends/imgui_impl_metal4.mm
CXXFLAGS = -std=c++11 -ObjC++ -fobjc-arc -Wall -Wextra -I$(IMGUI_DIR) -I$(IMGUI_DIR)/backends
diff --git a/examples/example_apple_metal4/example_apple_metal4.xcodeproj/project.pbxproj b/examples/example_apple_metal4/example_apple_metal4.xcodeproj/project.pbxproj
index ed60054fd..3239296c1 100644
--- a/examples/example_apple_metal4/example_apple_metal4.xcodeproj/project.pbxproj
+++ b/examples/example_apple_metal4/example_apple_metal4.xcodeproj/project.pbxproj
@@ -7,12 +7,14 @@
objects = {
/* Begin PBXBuildFile section */
+ 5A1A00AB2768052600AB6805 /* imgui_stacklayout.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5A1A002D257677DB0038A28D /* imgui_stacklayout.cpp */; };
050450AB2768052600AB6805 /* imgui_tables.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5079822D257677DB0038A28D /* imgui_tables.cpp */; };
050450AD276863B000AB6805 /* QuartzCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 050450AC276863B000AB6805 /* QuartzCore.framework */; };
05318E0F274C397200A8DE2E /* GameController.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 05318E0E274C397200A8DE2E /* GameController.framework */; };
05A275442773BEA20084EF39 /* QuartzCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 05A275432773BEA20084EF39 /* QuartzCore.framework */; };
07A82ED82139413D0078D120 /* imgui_widgets.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 07A82ED72139413C0078D120 /* imgui_widgets.cpp */; };
07A82ED92139418F0078D120 /* imgui_widgets.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 07A82ED72139413C0078D120 /* imgui_widgets.cpp */; };
+ 5A1A002E257677DB0038A28D /* imgui_stacklayout.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5A1A002D257677DB0038A28D /* imgui_stacklayout.cpp */; };
5079822E257677DB0038A28D /* imgui_tables.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5079822D257677DB0038A28D /* imgui_tables.cpp */; };
8309BD8F253CCAAA0045E2A1 /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8309BD8E253CCAAA0045E2A1 /* UIKit.framework */; };
8309BDA5253CCC070045E2A1 /* main.mm in Sources */ = {isa = PBXBuildFile; fileRef = 8309BDA0253CCBC10045E2A1 /* main.mm */; };
@@ -43,6 +45,7 @@
05A275432773BEA20084EF39 /* QuartzCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = QuartzCore.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS15.2.sdk/System/Library/Frameworks/QuartzCore.framework; sourceTree = DEVELOPER_DIR; };
07A82ED62139413C0078D120 /* imgui_internal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = imgui_internal.h; path = ../../imgui_internal.h; sourceTree = ""; };
07A82ED72139413C0078D120 /* imgui_widgets.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = imgui_widgets.cpp; path = ../../imgui_widgets.cpp; sourceTree = ""; };
+ 5A1A002D257677DB0038A28D /* imgui_stacklayout.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = imgui_stacklayout.cpp; path = ../../imgui_stacklayout.cpp; sourceTree = ""; };
5079822D257677DB0038A28D /* imgui_tables.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = imgui_tables.cpp; path = ../../imgui_tables.cpp; sourceTree = ""; };
8307E7C420E9F9C900473790 /* example_apple_metal.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = example_apple_metal.app; sourceTree = BUILT_PRODUCTS_DIR; };
8307E7DA20E9F9C900473790 /* example_apple_metal.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = example_apple_metal.app; sourceTree = BUILT_PRODUCTS_DIR; };
@@ -163,6 +166,7 @@
83BBE9F020EB544400295997 /* imgui */ = {
isa = PBXGroup;
children = (
+ 5A1A002D257677DB0038A28D /* imgui_stacklayout.cpp */,
5079822D257677DB0038A28D /* imgui_tables.cpp */,
05A2754027728F5B0084EF39 /* imgui_impl_metal4.h */,
8309BDB5253CCC9D0045E2A1 /* imgui_impl_metal4.mm */,
@@ -283,6 +287,7 @@
83BBEA0920EB54E700295997 /* imgui.cpp in Sources */,
83BBEA0720EB54E700295997 /* imgui_demo.cpp in Sources */,
83BBEA0520EB54E700295997 /* imgui_draw.cpp in Sources */,
+ 5A1A002E257677DB0038A28D /* imgui_stacklayout.cpp in Sources */,
5079822E257677DB0038A28D /* imgui_tables.cpp in Sources */,
07A82ED82139413D0078D120 /* imgui_widgets.cpp in Sources */,
8309BDA5253CCC070045E2A1 /* main.mm in Sources */,
@@ -298,6 +303,7 @@
83BBEA0A20EB54E700295997 /* imgui.cpp in Sources */,
83BBEA0820EB54E700295997 /* imgui_demo.cpp in Sources */,
83BBEA0620EB54E700295997 /* imgui_draw.cpp in Sources */,
+ 5A1A00AB2768052600AB6805 /* imgui_stacklayout.cpp in Sources */,
050450AB2768052600AB6805 /* imgui_tables.cpp in Sources */,
07A82ED92139418F0078D120 /* imgui_widgets.cpp in Sources */,
8309BDA8253CCC080045E2A1 /* main.mm in Sources */,
diff --git a/examples/example_apple_opengl2/Makefile b/examples/example_apple_opengl2/Makefile
index 4ad5fa692..db471a7c0 100644
--- a/examples/example_apple_opengl2/Makefile
+++ b/examples/example_apple_opengl2/Makefile
@@ -3,7 +3,7 @@ CXX = clang++
EXE = example_apple_opengl2
IMGUI_DIR = ../../
SOURCES = main.mm
-SOURCES += $(IMGUI_DIR)/imgui.cpp $(IMGUI_DIR)/imgui_demo.cpp $(IMGUI_DIR)/imgui_draw.cpp $(IMGUI_DIR)/imgui_tables.cpp $(IMGUI_DIR)/imgui_widgets.cpp
+SOURCES += $(IMGUI_DIR)/imgui.cpp $(IMGUI_DIR)/imgui_demo.cpp $(IMGUI_DIR)/imgui_draw.cpp $(IMGUI_DIR)/imgui_stacklayout.cpp $(IMGUI_DIR)/imgui_tables.cpp $(IMGUI_DIR)/imgui_widgets.cpp
SOURCES += $(IMGUI_DIR)/backends/imgui_impl_osx.mm $(IMGUI_DIR)/backends/imgui_impl_opengl2.cpp
CXXFLAGS = -std=c++11 -ObjC++ -fobjc-arc -Wall -Wextra -I$(IMGUI_DIR) -I$(IMGUI_DIR)/backends
diff --git a/examples/example_apple_opengl2/example_apple_opengl2.xcodeproj/project.pbxproj b/examples/example_apple_opengl2/example_apple_opengl2.xcodeproj/project.pbxproj
index 9770e4396..f4d177a8a 100644
--- a/examples/example_apple_opengl2/example_apple_opengl2.xcodeproj/project.pbxproj
+++ b/examples/example_apple_opengl2/example_apple_opengl2.xcodeproj/project.pbxproj
@@ -17,6 +17,7 @@
4080A9B020B0347A0036BA46 /* imgui_impl_osx.mm in Sources */ = {isa = PBXBuildFile; fileRef = 4080A99F20B034280036BA46 /* imgui_impl_osx.mm */; };
4080A9B320B034E40036BA46 /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4080A9B220B034E40036BA46 /* Cocoa.framework */; };
4080A9B520B034EA0036BA46 /* OpenGL.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4080A9B420B034EA0036BA46 /* OpenGL.framework */; };
+ 5A1A0030257677FD0038A28D /* imgui_stacklayout.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5A1A002F257677FC0038A28D /* imgui_stacklayout.cpp */; };
50798230257677FD0038A28D /* imgui_tables.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5079822F257677FC0038A28D /* imgui_tables.cpp */; };
/* End PBXBuildFile section */
@@ -49,6 +50,7 @@
4080A9AC20B0343C0036BA46 /* imconfig.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = imconfig.h; path = ../../imconfig.h; sourceTree = ""; };
4080A9B220B034E40036BA46 /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = System/Library/Frameworks/Cocoa.framework; sourceTree = SDKROOT; };
4080A9B420B034EA0036BA46 /* OpenGL.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = OpenGL.framework; path = System/Library/Frameworks/OpenGL.framework; sourceTree = SDKROOT; };
+ 5A1A002F257677FC0038A28D /* imgui_stacklayout.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = imgui_stacklayout.cpp; path = ../../imgui_stacklayout.cpp; sourceTree = ""; };
5079822F257677FC0038A28D /* imgui_tables.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = imgui_tables.cpp; path = ../../imgui_tables.cpp; sourceTree = ""; };
/* End PBXFileReference section */
@@ -69,6 +71,7 @@
4080A96220B029B00036BA46 = {
isa = PBXGroup;
children = (
+ 5A1A002F257677FC0038A28D /* imgui_stacklayout.cpp */,
5079822F257677FC0038A28D /* imgui_tables.cpp */,
4080A9AC20B0343C0036BA46 /* imconfig.h */,
4080A9A720B0343C0036BA46 /* imgui.cpp */,
@@ -168,6 +171,7 @@
4080A9A220B034280036BA46 /* imgui_impl_opengl2.cpp in Sources */,
4080A9B020B0347A0036BA46 /* imgui_impl_osx.mm in Sources */,
4080A9AE20B0343C0036BA46 /* imgui.cpp in Sources */,
+ 5A1A0030257677FD0038A28D /* imgui_stacklayout.cpp in Sources */,
50798230257677FD0038A28D /* imgui_tables.cpp in Sources */,
07A82EDB213941D00078D120 /* imgui_widgets.cpp in Sources */,
);
diff --git a/examples/example_apple_opengl3/Makefile b/examples/example_apple_opengl3/Makefile
index c9f9d44d3..ece086a36 100644
--- a/examples/example_apple_opengl3/Makefile
+++ b/examples/example_apple_opengl3/Makefile
@@ -3,7 +3,7 @@ CXX = clang++
EXE = example_apple_opengl3
IMGUI_DIR = ../../
SOURCES = main.mm
-SOURCES += $(IMGUI_DIR)/imgui.cpp $(IMGUI_DIR)/imgui_demo.cpp $(IMGUI_DIR)/imgui_draw.cpp $(IMGUI_DIR)/imgui_tables.cpp $(IMGUI_DIR)/imgui_widgets.cpp
+SOURCES += $(IMGUI_DIR)/imgui.cpp $(IMGUI_DIR)/imgui_demo.cpp $(IMGUI_DIR)/imgui_draw.cpp $(IMGUI_DIR)/imgui_stacklayout.cpp $(IMGUI_DIR)/imgui_tables.cpp $(IMGUI_DIR)/imgui_widgets.cpp
SOURCES += $(IMGUI_DIR)/backends/imgui_impl_osx.mm $(IMGUI_DIR)/backends/imgui_impl_opengl3.cpp
CXXFLAGS = -std=c++11 -ObjC++ -fobjc-arc -Wall -Wextra -I$(IMGUI_DIR) -I$(IMGUI_DIR)/backends
diff --git a/examples/example_apple_opengl3/example_apple_opengl3.xcodeproj/project.pbxproj b/examples/example_apple_opengl3/example_apple_opengl3.xcodeproj/project.pbxproj
index 50ee35fd9..327a7a3cf 100644
--- a/examples/example_apple_opengl3/example_apple_opengl3.xcodeproj/project.pbxproj
+++ b/examples/example_apple_opengl3/example_apple_opengl3.xcodeproj/project.pbxproj
@@ -17,6 +17,7 @@
4080A9B020B0347A0036BA46 /* imgui_impl_osx.mm in Sources */ = {isa = PBXBuildFile; fileRef = 4080A99F20B034280036BA46 /* imgui_impl_osx.mm */; };
4080A9B320B034E40036BA46 /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4080A9B220B034E40036BA46 /* Cocoa.framework */; };
4080A9B520B034EA0036BA46 /* OpenGL.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4080A9B420B034EA0036BA46 /* OpenGL.framework */; };
+ 5A1A0030257677FD0038A28D /* imgui_stacklayout.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5A1A002F257677FC0038A28D /* imgui_stacklayout.cpp */; };
50798230257677FD0038A28D /* imgui_tables.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5079822F257677FC0038A28D /* imgui_tables.cpp */; };
/* End PBXBuildFile section */
@@ -50,6 +51,7 @@
4080A9AC20B0343C0036BA46 /* imconfig.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = imconfig.h; path = ../../imconfig.h; sourceTree = ""; };
4080A9B220B034E40036BA46 /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = System/Library/Frameworks/Cocoa.framework; sourceTree = SDKROOT; };
4080A9B420B034EA0036BA46 /* OpenGL.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = OpenGL.framework; path = System/Library/Frameworks/OpenGL.framework; sourceTree = SDKROOT; };
+ 5A1A002F257677FC0038A28D /* imgui_stacklayout.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = imgui_stacklayout.cpp; path = ../../imgui_stacklayout.cpp; sourceTree = ""; };
5079822F257677FC0038A28D /* imgui_tables.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = imgui_tables.cpp; path = ../../imgui_tables.cpp; sourceTree = ""; };
/* End PBXFileReference section */
@@ -70,6 +72,7 @@
4080A96220B029B00036BA46 = {
isa = PBXGroup;
children = (
+ 5A1A002F257677FC0038A28D /* imgui_stacklayout.cpp */,
5079822F257677FC0038A28D /* imgui_tables.cpp */,
4080A9AC20B0343C0036BA46 /* imconfig.h */,
4080A9A720B0343C0036BA46 /* imgui.cpp */,
@@ -170,6 +173,7 @@
4080A9A220B034280036BA46 /* imgui_impl_opengl3.cpp in Sources */,
4080A9B020B0347A0036BA46 /* imgui_impl_osx.mm in Sources */,
4080A9AE20B0343C0036BA46 /* imgui.cpp in Sources */,
+ 5A1A0030257677FD0038A28D /* imgui_stacklayout.cpp in Sources */,
50798230257677FD0038A28D /* imgui_tables.cpp in Sources */,
07A82EDB213941D00078D120 /* imgui_widgets.cpp in Sources */,
);
diff --git a/examples/example_glfw_metal/Makefile b/examples/example_glfw_metal/Makefile
index 32a7aeca2..30782cb9f 100644
--- a/examples/example_glfw_metal/Makefile
+++ b/examples/example_glfw_metal/Makefile
@@ -9,7 +9,7 @@
EXE = example_glfw_metal
IMGUI_DIR = ../..
SOURCES = main.mm
-SOURCES += $(IMGUI_DIR)/imgui.cpp $(IMGUI_DIR)/imgui_demo.cpp $(IMGUI_DIR)/imgui_draw.cpp $(IMGUI_DIR)/imgui_tables.cpp $(IMGUI_DIR)/imgui_widgets.cpp
+SOURCES += $(IMGUI_DIR)/imgui.cpp $(IMGUI_DIR)/imgui_demo.cpp $(IMGUI_DIR)/imgui_draw.cpp $(IMGUI_DIR)/imgui_stacklayout.cpp $(IMGUI_DIR)/imgui_tables.cpp $(IMGUI_DIR)/imgui_widgets.cpp
SOURCES += $(IMGUI_DIR)/backends/imgui_impl_glfw.cpp $(IMGUI_DIR)/backends/imgui_impl_metal.mm
OBJS = $(addsuffix .o, $(basename $(notdir $(SOURCES))))
diff --git a/examples/example_glfw_opengl2/Makefile b/examples/example_glfw_opengl2/Makefile
index a8a0128dc..a68ce712d 100644
--- a/examples/example_glfw_opengl2/Makefile
+++ b/examples/example_glfw_opengl2/Makefile
@@ -17,7 +17,7 @@
EXE = example_glfw_opengl2
IMGUI_DIR = ../..
SOURCES = main.cpp
-SOURCES += $(IMGUI_DIR)/imgui.cpp $(IMGUI_DIR)/imgui_demo.cpp $(IMGUI_DIR)/imgui_draw.cpp $(IMGUI_DIR)/imgui_tables.cpp $(IMGUI_DIR)/imgui_widgets.cpp
+SOURCES += $(IMGUI_DIR)/imgui.cpp $(IMGUI_DIR)/imgui_demo.cpp $(IMGUI_DIR)/imgui_draw.cpp $(IMGUI_DIR)/imgui_stacklayout.cpp $(IMGUI_DIR)/imgui_tables.cpp $(IMGUI_DIR)/imgui_widgets.cpp
SOURCES += $(IMGUI_DIR)/backends/imgui_impl_glfw.cpp $(IMGUI_DIR)/backends/imgui_impl_opengl2.cpp
OBJS = $(addsuffix .o, $(basename $(notdir $(SOURCES))))
UNAME_S := $(shell uname -s)
diff --git a/examples/example_glfw_opengl2/example_glfw_opengl2.vcxproj b/examples/example_glfw_opengl2/example_glfw_opengl2.vcxproj
index 18d95894f..c7e727d23 100644
--- a/examples/example_glfw_opengl2/example_glfw_opengl2.vcxproj
+++ b/examples/example_glfw_opengl2/example_glfw_opengl2.vcxproj
@@ -164,6 +164,7 @@
+
@@ -174,6 +175,8 @@
+
+
diff --git a/examples/example_glfw_opengl2/example_glfw_opengl2.vcxproj.filters b/examples/example_glfw_opengl2/example_glfw_opengl2.vcxproj.filters
index 049b0b1a3..8c6e69bb5 100644
--- a/examples/example_glfw_opengl2/example_glfw_opengl2.vcxproj.filters
+++ b/examples/example_glfw_opengl2/example_glfw_opengl2.vcxproj.filters
@@ -22,6 +22,9 @@
imgui
+
+ imgui
+
imgui
@@ -45,6 +48,12 @@
imgui
+
+ imgui
+
+
+ imgui
+
sources
diff --git a/examples/example_glfw_opengl3/Makefile b/examples/example_glfw_opengl3/Makefile
index 252ce5714..25f63a32f 100644
--- a/examples/example_glfw_opengl3/Makefile
+++ b/examples/example_glfw_opengl3/Makefile
@@ -17,7 +17,7 @@
EXE = example_glfw_opengl3
IMGUI_DIR = ../..
SOURCES = main.cpp
-SOURCES += $(IMGUI_DIR)/imgui.cpp $(IMGUI_DIR)/imgui_demo.cpp $(IMGUI_DIR)/imgui_draw.cpp $(IMGUI_DIR)/imgui_tables.cpp $(IMGUI_DIR)/imgui_widgets.cpp
+SOURCES += $(IMGUI_DIR)/imgui.cpp $(IMGUI_DIR)/imgui_demo.cpp $(IMGUI_DIR)/imgui_draw.cpp $(IMGUI_DIR)/imgui_stacklayout.cpp $(IMGUI_DIR)/imgui_tables.cpp $(IMGUI_DIR)/imgui_widgets.cpp
SOURCES += $(IMGUI_DIR)/backends/imgui_impl_glfw.cpp $(IMGUI_DIR)/backends/imgui_impl_opengl3.cpp
OBJS = $(addsuffix .o, $(basename $(notdir $(SOURCES))))
UNAME_S := $(shell uname -s)
diff --git a/examples/example_glfw_opengl3/Makefile.emscripten b/examples/example_glfw_opengl3/Makefile.emscripten
index 8d2f6e7bd..8a32693ad 100644
--- a/examples/example_glfw_opengl3/Makefile.emscripten
+++ b/examples/example_glfw_opengl3/Makefile.emscripten
@@ -19,7 +19,7 @@ WEB_DIR = web
EXE = $(WEB_DIR)/index.html
IMGUI_DIR = ../..
SOURCES = main.cpp
-SOURCES += $(IMGUI_DIR)/imgui.cpp $(IMGUI_DIR)/imgui_demo.cpp $(IMGUI_DIR)/imgui_draw.cpp $(IMGUI_DIR)/imgui_tables.cpp $(IMGUI_DIR)/imgui_widgets.cpp
+SOURCES += $(IMGUI_DIR)/imgui.cpp $(IMGUI_DIR)/imgui_demo.cpp $(IMGUI_DIR)/imgui_draw.cpp $(IMGUI_DIR)/imgui_stacklayout.cpp $(IMGUI_DIR)/imgui_tables.cpp $(IMGUI_DIR)/imgui_widgets.cpp
SOURCES += $(IMGUI_DIR)/backends/imgui_impl_glfw.cpp $(IMGUI_DIR)/backends/imgui_impl_opengl3.cpp
OBJS = $(addsuffix .o, $(basename $(notdir $(SOURCES))))
UNAME_S := $(shell uname -s)
diff --git a/examples/example_glfw_opengl3/example_glfw_opengl3.vcxproj b/examples/example_glfw_opengl3/example_glfw_opengl3.vcxproj
index 3e9d71e13..0ea36129b 100644
--- a/examples/example_glfw_opengl3/example_glfw_opengl3.vcxproj
+++ b/examples/example_glfw_opengl3/example_glfw_opengl3.vcxproj
@@ -164,6 +164,7 @@
+
@@ -174,6 +175,8 @@
+
+
diff --git a/examples/example_glfw_opengl3/example_glfw_opengl3.vcxproj.filters b/examples/example_glfw_opengl3/example_glfw_opengl3.vcxproj.filters
index bc79bb197..e81bf5043 100644
--- a/examples/example_glfw_opengl3/example_glfw_opengl3.vcxproj.filters
+++ b/examples/example_glfw_opengl3/example_glfw_opengl3.vcxproj.filters
@@ -22,6 +22,9 @@
imgui
+
+ imgui
+
imgui
@@ -45,6 +48,12 @@
imgui
+
+ imgui
+
+
+ imgui
+
sources
diff --git a/examples/example_glfw_vulkan/CMakeLists.txt b/examples/example_glfw_vulkan/CMakeLists.txt
index 75475dbae..6d89557eb 100644
--- a/examples/example_glfw_vulkan/CMakeLists.txt
+++ b/examples/example_glfw_vulkan/CMakeLists.txt
@@ -42,6 +42,6 @@ include_directories(${GLFW_DIR}/deps)
file(GLOB sources *.cpp)
-add_executable(example_glfw_vulkan ${sources} ${IMGUI_DIR}/backends/imgui_impl_glfw.cpp ${IMGUI_DIR}/backends/imgui_impl_vulkan.cpp ${IMGUI_DIR}/imgui.cpp ${IMGUI_DIR}/imgui_draw.cpp ${IMGUI_DIR}/imgui_demo.cpp ${IMGUI_DIR}/imgui_tables.cpp ${IMGUI_DIR}/imgui_widgets.cpp)
+add_executable(example_glfw_vulkan ${sources} ${IMGUI_DIR}/backends/imgui_impl_glfw.cpp ${IMGUI_DIR}/backends/imgui_impl_vulkan.cpp ${IMGUI_DIR}/imgui.cpp ${IMGUI_DIR}/imgui_draw.cpp ${IMGUI_DIR}/imgui_demo.cpp ${IMGUI_DIR}/imgui_stacklayout.cpp ${IMGUI_DIR}/imgui_tables.cpp ${IMGUI_DIR}/imgui_widgets.cpp)
target_link_libraries(example_glfw_vulkan ${LIBRARIES})
diff --git a/examples/example_glfw_vulkan/Makefile b/examples/example_glfw_vulkan/Makefile
index 1a84082d1..2b962b8cd 100644
--- a/examples/example_glfw_vulkan/Makefile
+++ b/examples/example_glfw_vulkan/Makefile
@@ -17,7 +17,7 @@
EXE = example_glfw_vulkan
IMGUI_DIR = ../..
SOURCES = main.cpp
-SOURCES += $(IMGUI_DIR)/imgui.cpp $(IMGUI_DIR)/imgui_demo.cpp $(IMGUI_DIR)/imgui_draw.cpp $(IMGUI_DIR)/imgui_tables.cpp $(IMGUI_DIR)/imgui_widgets.cpp
+SOURCES += $(IMGUI_DIR)/imgui.cpp $(IMGUI_DIR)/imgui_demo.cpp $(IMGUI_DIR)/imgui_draw.cpp $(IMGUI_DIR)/imgui_stacklayout.cpp $(IMGUI_DIR)/imgui_tables.cpp $(IMGUI_DIR)/imgui_widgets.cpp
SOURCES += $(IMGUI_DIR)/backends/imgui_impl_glfw.cpp $(IMGUI_DIR)/backends/imgui_impl_vulkan.cpp
OBJS = $(addsuffix .o, $(basename $(notdir $(SOURCES))))
UNAME_S := $(shell uname -s)
diff --git a/examples/example_glfw_vulkan/example_glfw_vulkan.vcxproj b/examples/example_glfw_vulkan/example_glfw_vulkan.vcxproj
index 492aa0e3f..b800c5436 100644
--- a/examples/example_glfw_vulkan/example_glfw_vulkan.vcxproj
+++ b/examples/example_glfw_vulkan/example_glfw_vulkan.vcxproj
@@ -168,6 +168,7 @@
+
@@ -178,6 +179,8 @@
+
+
diff --git a/examples/example_glfw_vulkan/example_glfw_vulkan.vcxproj.filters b/examples/example_glfw_vulkan/example_glfw_vulkan.vcxproj.filters
index 510fc8547..7b133550d 100644
--- a/examples/example_glfw_vulkan/example_glfw_vulkan.vcxproj.filters
+++ b/examples/example_glfw_vulkan/example_glfw_vulkan.vcxproj.filters
@@ -22,6 +22,9 @@
imgui
+
+ imgui
+
imgui
@@ -45,6 +48,12 @@
imgui
+
+ imgui
+
+
+ imgui
+
sources
diff --git a/examples/example_glfw_wgpu/CMakeLists.txt b/examples/example_glfw_wgpu/CMakeLists.txt
index b76054877..8b61b8b28 100644
--- a/examples/example_glfw_wgpu/CMakeLists.txt
+++ b/examples/example_glfw_wgpu/CMakeLists.txt
@@ -52,6 +52,7 @@ set(IMGUI_EXAMPLE_SOURCE_FILES
${IMGUI_DIR}/imgui.cpp
${IMGUI_DIR}/imgui_draw.cpp
${IMGUI_DIR}/imgui_demo.cpp
+ ${IMGUI_DIR}/imgui_stacklayout.cpp
${IMGUI_DIR}/imgui_tables.cpp
${IMGUI_DIR}/imgui_widgets.cpp
)
diff --git a/examples/example_glfw_wgpu/Makefile.emscripten b/examples/example_glfw_wgpu/Makefile.emscripten
index ff386fec5..75b6eedab 100644
--- a/examples/example_glfw_wgpu/Makefile.emscripten
+++ b/examples/example_glfw_wgpu/Makefile.emscripten
@@ -20,7 +20,7 @@ EXE = $(WEB_DIR)/index.html
IMGUI_DIR = ../..
SOURCES = main.cpp
SOURCES += $(IMGUI_DIR)/backends/imgui_impl_glfw.cpp $(IMGUI_DIR)/backends/imgui_impl_wgpu.cpp
-SOURCES += $(IMGUI_DIR)/imgui.cpp $(IMGUI_DIR)/imgui_demo.cpp $(IMGUI_DIR)/imgui_draw.cpp $(IMGUI_DIR)/imgui_tables.cpp $(IMGUI_DIR)/imgui_widgets.cpp
+SOURCES += $(IMGUI_DIR)/imgui.cpp $(IMGUI_DIR)/imgui_demo.cpp $(IMGUI_DIR)/imgui_draw.cpp $(IMGUI_DIR)/imgui_stacklayout.cpp $(IMGUI_DIR)/imgui_tables.cpp $(IMGUI_DIR)/imgui_widgets.cpp
OBJS = $(addsuffix .o, $(basename $(notdir $(SOURCES))))
UNAME_S := $(shell uname -s)
CPPFLAGS =
diff --git a/examples/example_glut_opengl2/Makefile b/examples/example_glut_opengl2/Makefile
index 7af289dc4..f361980d6 100644
--- a/examples/example_glut_opengl2/Makefile
+++ b/examples/example_glut_opengl2/Makefile
@@ -12,7 +12,7 @@
EXE = example_glut_opengl2
IMGUI_DIR = ../..
SOURCES = main.cpp
-SOURCES += $(IMGUI_DIR)/imgui.cpp $(IMGUI_DIR)/imgui_demo.cpp $(IMGUI_DIR)/imgui_draw.cpp $(IMGUI_DIR)/imgui_tables.cpp $(IMGUI_DIR)/imgui_widgets.cpp
+SOURCES += $(IMGUI_DIR)/imgui.cpp $(IMGUI_DIR)/imgui_demo.cpp $(IMGUI_DIR)/imgui_draw.cpp $(IMGUI_DIR)/imgui_stacklayout.cpp $(IMGUI_DIR)/imgui_tables.cpp $(IMGUI_DIR)/imgui_widgets.cpp
SOURCES += $(IMGUI_DIR)/backends/imgui_impl_glut.cpp $(IMGUI_DIR)/backends/imgui_impl_opengl2.cpp
OBJS = $(addsuffix .o, $(basename $(notdir $(SOURCES))))
UNAME_S := $(shell uname -s)
diff --git a/examples/example_glut_opengl2/example_glut_opengl2.vcxproj b/examples/example_glut_opengl2/example_glut_opengl2.vcxproj
index bdd9af440..f989009a4 100644
--- a/examples/example_glut_opengl2/example_glut_opengl2.vcxproj
+++ b/examples/example_glut_opengl2/example_glut_opengl2.vcxproj
@@ -164,6 +164,7 @@
+
@@ -174,6 +175,8 @@
+
+
diff --git a/examples/example_glut_opengl2/example_glut_opengl2.vcxproj.filters b/examples/example_glut_opengl2/example_glut_opengl2.vcxproj.filters
index 0ac4a0b2e..3f9fac856 100644
--- a/examples/example_glut_opengl2/example_glut_opengl2.vcxproj.filters
+++ b/examples/example_glut_opengl2/example_glut_opengl2.vcxproj.filters
@@ -22,6 +22,9 @@
imgui
+
+ imgui
+
imgui
@@ -45,6 +48,12 @@
imgui
+
+ imgui
+
+
+ imgui
+
sources
diff --git a/examples/example_null/Makefile b/examples/example_null/Makefile
index 4a67cecd8..0df019473 100644
--- a/examples/example_null/Makefile
+++ b/examples/example_null/Makefile
@@ -13,7 +13,7 @@ WITH_FREETYPE ?= 0
EXE = example_null
IMGUI_DIR = ../..
SOURCES = main.cpp
-SOURCES += $(IMGUI_DIR)/imgui.cpp $(IMGUI_DIR)/imgui_demo.cpp $(IMGUI_DIR)/imgui_draw.cpp $(IMGUI_DIR)/imgui_tables.cpp $(IMGUI_DIR)/imgui_widgets.cpp
+SOURCES += $(IMGUI_DIR)/imgui.cpp $(IMGUI_DIR)/imgui_demo.cpp $(IMGUI_DIR)/imgui_draw.cpp $(IMGUI_DIR)/imgui_stacklayout.cpp $(IMGUI_DIR)/imgui_tables.cpp $(IMGUI_DIR)/imgui_widgets.cpp
OBJS = $(addsuffix .o, $(basename $(notdir $(SOURCES))))
UNAME_S := $(shell uname -s)
diff --git a/examples/example_null/example_null.vcxproj b/examples/example_null/example_null.vcxproj
index 61e388f96..1ce6e1e4d 100644
--- a/examples/example_null/example_null.vcxproj
+++ b/examples/example_null/example_null.vcxproj
@@ -155,6 +155,8 @@
+
+
@@ -166,6 +168,7 @@
+
diff --git a/examples/example_null/example_null.vcxproj.filters b/examples/example_null/example_null.vcxproj.filters
index 6d575a8f5..6772cc4c4 100644
--- a/examples/example_null/example_null.vcxproj.filters
+++ b/examples/example_null/example_null.vcxproj.filters
@@ -18,6 +18,12 @@
imgui
+
+ imgui
+
+
+ imgui
+
sources
@@ -35,6 +41,9 @@
imgui
+
+ imgui
+
imgui
diff --git a/examples/example_qnx_opengl3/common.mk b/examples/example_qnx_opengl3/common.mk
index d162d684e..0f07c7933 100644
--- a/examples/example_qnx_opengl3/common.mk
+++ b/examples/example_qnx_opengl3/common.mk
@@ -10,6 +10,7 @@ SRCS = \
imgui.cpp \
imgui_demo.cpp \
imgui_draw.cpp \
+ imgui_stacklayout.cpp \
imgui_tables.cpp \
imgui_widgets.cpp \
imgui_impl_qnx.cpp \
diff --git a/examples/example_qnx_vulkan/common.mk b/examples/example_qnx_vulkan/common.mk
index 7d99539aa..7d698e020 100644
--- a/examples/example_qnx_vulkan/common.mk
+++ b/examples/example_qnx_vulkan/common.mk
@@ -10,6 +10,7 @@ SRCS = \
imgui.cpp \
imgui_demo.cpp \
imgui_draw.cpp \
+ imgui_stacklayout.cpp \
imgui_tables.cpp \
imgui_widgets.cpp \
imgui_impl_qnx.cpp \
diff --git a/examples/example_sdl2_directx11/example_sdl2_directx11.vcxproj b/examples/example_sdl2_directx11/example_sdl2_directx11.vcxproj
index afa9d5de4..f07edc79a 100644
--- a/examples/example_sdl2_directx11/example_sdl2_directx11.vcxproj
+++ b/examples/example_sdl2_directx11/example_sdl2_directx11.vcxproj
@@ -165,6 +165,7 @@
+
@@ -175,6 +176,8 @@
+
+
diff --git a/examples/example_sdl2_directx11/example_sdl2_directx11.vcxproj.filters b/examples/example_sdl2_directx11/example_sdl2_directx11.vcxproj.filters
index 92d11f88e..709de7c7c 100644
--- a/examples/example_sdl2_directx11/example_sdl2_directx11.vcxproj.filters
+++ b/examples/example_sdl2_directx11/example_sdl2_directx11.vcxproj.filters
@@ -18,6 +18,12 @@
imgui
+
+ imgui
+
+
+ imgui
+
sources
@@ -38,6 +44,9 @@
imgui
+
+ imgui
+
imgui
diff --git a/examples/example_sdl2_metal/Makefile b/examples/example_sdl2_metal/Makefile
index 53c5f75db..57d267aae 100644
--- a/examples/example_sdl2_metal/Makefile
+++ b/examples/example_sdl2_metal/Makefile
@@ -9,7 +9,7 @@
EXE = example_sdl2_metal
IMGUI_DIR = ../..
SOURCES = main.mm
-SOURCES += $(IMGUI_DIR)/imgui.cpp $(IMGUI_DIR)/imgui_demo.cpp $(IMGUI_DIR)/imgui_draw.cpp $(IMGUI_DIR)/imgui_tables.cpp $(IMGUI_DIR)/imgui_widgets.cpp
+SOURCES += $(IMGUI_DIR)/imgui.cpp $(IMGUI_DIR)/imgui_demo.cpp $(IMGUI_DIR)/imgui_draw.cpp $(IMGUI_DIR)/imgui_stacklayout.cpp $(IMGUI_DIR)/imgui_tables.cpp $(IMGUI_DIR)/imgui_widgets.cpp
SOURCES += $(IMGUI_DIR)/backends/imgui_impl_sdl2.cpp $(IMGUI_DIR)/backends/imgui_impl_metal.mm
OBJS = $(addsuffix .o, $(basename $(notdir $(SOURCES))))
diff --git a/examples/example_sdl2_opengl2/Makefile b/examples/example_sdl2_opengl2/Makefile
index a85ced023..7bf9674cc 100644
--- a/examples/example_sdl2_opengl2/Makefile
+++ b/examples/example_sdl2_opengl2/Makefile
@@ -17,7 +17,7 @@
EXE = example_sdl2_opengl2
IMGUI_DIR = ../..
SOURCES = main.cpp
-SOURCES += $(IMGUI_DIR)/imgui.cpp $(IMGUI_DIR)/imgui_demo.cpp $(IMGUI_DIR)/imgui_draw.cpp $(IMGUI_DIR)/imgui_tables.cpp $(IMGUI_DIR)/imgui_widgets.cpp
+SOURCES += $(IMGUI_DIR)/imgui.cpp $(IMGUI_DIR)/imgui_demo.cpp $(IMGUI_DIR)/imgui_draw.cpp $(IMGUI_DIR)/imgui_stacklayout.cpp $(IMGUI_DIR)/imgui_tables.cpp $(IMGUI_DIR)/imgui_widgets.cpp
SOURCES += $(IMGUI_DIR)/backends/imgui_impl_sdl2.cpp $(IMGUI_DIR)/backends/imgui_impl_opengl2.cpp
OBJS = $(addsuffix .o, $(basename $(notdir $(SOURCES))))
UNAME_S := $(shell uname -s)
diff --git a/examples/example_sdl2_opengl2/example_sdl2_opengl2.vcxproj b/examples/example_sdl2_opengl2/example_sdl2_opengl2.vcxproj
index 35b7ed7df..a241fce7b 100644
--- a/examples/example_sdl2_opengl2/example_sdl2_opengl2.vcxproj
+++ b/examples/example_sdl2_opengl2/example_sdl2_opengl2.vcxproj
@@ -164,6 +164,7 @@
+
@@ -174,6 +175,8 @@
+
+
diff --git a/examples/example_sdl2_opengl2/example_sdl2_opengl2.vcxproj.filters b/examples/example_sdl2_opengl2/example_sdl2_opengl2.vcxproj.filters
index 752a1965d..c06d9bce8 100644
--- a/examples/example_sdl2_opengl2/example_sdl2_opengl2.vcxproj.filters
+++ b/examples/example_sdl2_opengl2/example_sdl2_opengl2.vcxproj.filters
@@ -22,6 +22,9 @@
sources
+
+ imgui
+
imgui
@@ -45,6 +48,12 @@
imgui
+
+ imgui
+
+
+ imgui
+
sources
diff --git a/examples/example_sdl2_opengl3/Makefile b/examples/example_sdl2_opengl3/Makefile
index 5b4f9419c..4bd9aceec 100644
--- a/examples/example_sdl2_opengl3/Makefile
+++ b/examples/example_sdl2_opengl3/Makefile
@@ -17,7 +17,7 @@
EXE = example_sdl2_opengl3
IMGUI_DIR = ../..
SOURCES = main.cpp
-SOURCES += $(IMGUI_DIR)/imgui.cpp $(IMGUI_DIR)/imgui_demo.cpp $(IMGUI_DIR)/imgui_draw.cpp $(IMGUI_DIR)/imgui_tables.cpp $(IMGUI_DIR)/imgui_widgets.cpp
+SOURCES += $(IMGUI_DIR)/imgui.cpp $(IMGUI_DIR)/imgui_demo.cpp $(IMGUI_DIR)/imgui_draw.cpp $(IMGUI_DIR)/imgui_stacklayout.cpp $(IMGUI_DIR)/imgui_tables.cpp $(IMGUI_DIR)/imgui_widgets.cpp
SOURCES += $(IMGUI_DIR)/backends/imgui_impl_sdl2.cpp $(IMGUI_DIR)/backends/imgui_impl_opengl3.cpp
OBJS = $(addsuffix .o, $(basename $(notdir $(SOURCES))))
UNAME_S := $(shell uname -s)
diff --git a/examples/example_sdl2_opengl3/Makefile.emscripten b/examples/example_sdl2_opengl3/Makefile.emscripten
index bc06adeb7..ea4708645 100644
--- a/examples/example_sdl2_opengl3/Makefile.emscripten
+++ b/examples/example_sdl2_opengl3/Makefile.emscripten
@@ -19,7 +19,7 @@ WEB_DIR = web
EXE = $(WEB_DIR)/index.html
IMGUI_DIR = ../..
SOURCES = main.cpp
-SOURCES += $(IMGUI_DIR)/imgui.cpp $(IMGUI_DIR)/imgui_demo.cpp $(IMGUI_DIR)/imgui_draw.cpp $(IMGUI_DIR)/imgui_tables.cpp $(IMGUI_DIR)/imgui_widgets.cpp
+SOURCES += $(IMGUI_DIR)/imgui.cpp $(IMGUI_DIR)/imgui_demo.cpp $(IMGUI_DIR)/imgui_draw.cpp $(IMGUI_DIR)/imgui_stacklayout.cpp $(IMGUI_DIR)/imgui_tables.cpp $(IMGUI_DIR)/imgui_widgets.cpp
SOURCES += $(IMGUI_DIR)/backends/imgui_impl_sdl2.cpp $(IMGUI_DIR)/backends/imgui_impl_opengl3.cpp
OBJS = $(addsuffix .o, $(basename $(notdir $(SOURCES))))
UNAME_S := $(shell uname -s)
diff --git a/examples/example_sdl2_opengl3/example_sdl2_opengl3.vcxproj b/examples/example_sdl2_opengl3/example_sdl2_opengl3.vcxproj
index b5a80197e..3d6849e9c 100644
--- a/examples/example_sdl2_opengl3/example_sdl2_opengl3.vcxproj
+++ b/examples/example_sdl2_opengl3/example_sdl2_opengl3.vcxproj
@@ -164,6 +164,7 @@
+
@@ -174,6 +175,8 @@
+
+
diff --git a/examples/example_sdl2_opengl3/example_sdl2_opengl3.vcxproj.filters b/examples/example_sdl2_opengl3/example_sdl2_opengl3.vcxproj.filters
index 846d55759..277bb6b12 100644
--- a/examples/example_sdl2_opengl3/example_sdl2_opengl3.vcxproj.filters
+++ b/examples/example_sdl2_opengl3/example_sdl2_opengl3.vcxproj.filters
@@ -28,6 +28,9 @@
sources
+
+ imgui
+
imgui
@@ -45,6 +48,12 @@
imgui
+
+ imgui
+
+
+ imgui
+
sources
diff --git a/examples/example_sdl2_sdlrenderer2/Makefile b/examples/example_sdl2_sdlrenderer2/Makefile
index 5820d9bc7..9080ab5d5 100644
--- a/examples/example_sdl2_sdlrenderer2/Makefile
+++ b/examples/example_sdl2_sdlrenderer2/Makefile
@@ -17,7 +17,7 @@
EXE = example_sdl2_sdlrenderer2
IMGUI_DIR = ../..
SOURCES = main.cpp
-SOURCES += $(IMGUI_DIR)/imgui.cpp $(IMGUI_DIR)/imgui_demo.cpp $(IMGUI_DIR)/imgui_draw.cpp $(IMGUI_DIR)/imgui_tables.cpp $(IMGUI_DIR)/imgui_widgets.cpp
+SOURCES += $(IMGUI_DIR)/imgui.cpp $(IMGUI_DIR)/imgui_demo.cpp $(IMGUI_DIR)/imgui_draw.cpp $(IMGUI_DIR)/imgui_stacklayout.cpp $(IMGUI_DIR)/imgui_tables.cpp $(IMGUI_DIR)/imgui_widgets.cpp
SOURCES += $(IMGUI_DIR)/backends/imgui_impl_sdl2.cpp $(IMGUI_DIR)/backends/imgui_impl_sdlrenderer2.cpp
OBJS = $(addsuffix .o, $(basename $(notdir $(SOURCES))))
UNAME_S := $(shell uname -s)
diff --git a/examples/example_sdl2_sdlrenderer2/example_sdl2_sdlrenderer2.vcxproj b/examples/example_sdl2_sdlrenderer2/example_sdl2_sdlrenderer2.vcxproj
index 9d7951be8..14881946d 100644
--- a/examples/example_sdl2_sdlrenderer2/example_sdl2_sdlrenderer2.vcxproj
+++ b/examples/example_sdl2_sdlrenderer2/example_sdl2_sdlrenderer2.vcxproj
@@ -165,6 +165,7 @@
+
@@ -175,6 +176,8 @@
+
+
diff --git a/examples/example_sdl2_sdlrenderer2/example_sdl2_sdlrenderer2.vcxproj.filters b/examples/example_sdl2_sdlrenderer2/example_sdl2_sdlrenderer2.vcxproj.filters
index 5c6da42e3..7ae21857f 100644
--- a/examples/example_sdl2_sdlrenderer2/example_sdl2_sdlrenderer2.vcxproj.filters
+++ b/examples/example_sdl2_sdlrenderer2/example_sdl2_sdlrenderer2.vcxproj.filters
@@ -22,6 +22,9 @@
sources
+
+ imgui
+
imgui
@@ -45,6 +48,12 @@
imgui
+
+ imgui
+
+
+ imgui
+
sources
diff --git a/examples/example_sdl2_vulkan/Makefile b/examples/example_sdl2_vulkan/Makefile
index e722ab035..37f9c7517 100644
--- a/examples/example_sdl2_vulkan/Makefile
+++ b/examples/example_sdl2_vulkan/Makefile
@@ -17,7 +17,7 @@
EXE = example_sdl2_vulkan
IMGUI_DIR = ../..
SOURCES = main.cpp
-SOURCES += $(IMGUI_DIR)/imgui.cpp $(IMGUI_DIR)/imgui_demo.cpp $(IMGUI_DIR)/imgui_draw.cpp $(IMGUI_DIR)/imgui_tables.cpp $(IMGUI_DIR)/imgui_widgets.cpp
+SOURCES += $(IMGUI_DIR)/imgui.cpp $(IMGUI_DIR)/imgui_demo.cpp $(IMGUI_DIR)/imgui_draw.cpp $(IMGUI_DIR)/imgui_stacklayout.cpp $(IMGUI_DIR)/imgui_tables.cpp $(IMGUI_DIR)/imgui_widgets.cpp
SOURCES += $(IMGUI_DIR)/backends/imgui_impl_sdl2.cpp $(IMGUI_DIR)/backends/imgui_impl_vulkan.cpp
OBJS = $(addsuffix .o, $(basename $(notdir $(SOURCES))))
UNAME_S := $(shell uname -s)
diff --git a/examples/example_sdl2_vulkan/example_sdl2_vulkan.vcxproj b/examples/example_sdl2_vulkan/example_sdl2_vulkan.vcxproj
index b2269bc9d..77ae5d5a4 100644
--- a/examples/example_sdl2_vulkan/example_sdl2_vulkan.vcxproj
+++ b/examples/example_sdl2_vulkan/example_sdl2_vulkan.vcxproj
@@ -168,6 +168,7 @@
+
@@ -178,6 +179,8 @@
+
+
diff --git a/examples/example_sdl2_vulkan/example_sdl2_vulkan.vcxproj.filters b/examples/example_sdl2_vulkan/example_sdl2_vulkan.vcxproj.filters
index ab4248515..2e09d8de2 100644
--- a/examples/example_sdl2_vulkan/example_sdl2_vulkan.vcxproj.filters
+++ b/examples/example_sdl2_vulkan/example_sdl2_vulkan.vcxproj.filters
@@ -31,6 +31,9 @@
imgui
+
+ imgui
+
imgui
@@ -45,6 +48,12 @@
imgui
+
+ imgui
+
+
+ imgui
+
sources
diff --git a/examples/example_sdl2_wgpu/CMakeLists.txt b/examples/example_sdl2_wgpu/CMakeLists.txt
index 0a8fed305..21a882fda 100644
--- a/examples/example_sdl2_wgpu/CMakeLists.txt
+++ b/examples/example_sdl2_wgpu/CMakeLists.txt
@@ -52,6 +52,7 @@ set(IMGUI_EXAMPLE_SOURCE_FILES
${IMGUI_DIR}/imgui.cpp
${IMGUI_DIR}/imgui_draw.cpp
${IMGUI_DIR}/imgui_demo.cpp
+ ${IMGUI_DIR}/imgui_stacklayout.cpp
${IMGUI_DIR}/imgui_tables.cpp
${IMGUI_DIR}/imgui_widgets.cpp
)
diff --git a/examples/example_sdl2_wgpu/Makefile.emscripten b/examples/example_sdl2_wgpu/Makefile.emscripten
index ebc7f97c9..9144aa550 100644
--- a/examples/example_sdl2_wgpu/Makefile.emscripten
+++ b/examples/example_sdl2_wgpu/Makefile.emscripten
@@ -20,7 +20,7 @@ EXE = $(WEB_DIR)/index.html
IMGUI_DIR = ../..
SOURCES = main.cpp
SOURCES += $(IMGUI_DIR)/backends/imgui_impl_sdl2.cpp $(IMGUI_DIR)/backends/imgui_impl_wgpu.cpp
-SOURCES += $(IMGUI_DIR)/imgui.cpp $(IMGUI_DIR)/imgui_demo.cpp $(IMGUI_DIR)/imgui_draw.cpp $(IMGUI_DIR)/imgui_tables.cpp $(IMGUI_DIR)/imgui_widgets.cpp
+SOURCES += $(IMGUI_DIR)/imgui.cpp $(IMGUI_DIR)/imgui_demo.cpp $(IMGUI_DIR)/imgui_draw.cpp $(IMGUI_DIR)/imgui_stacklayout.cpp $(IMGUI_DIR)/imgui_tables.cpp $(IMGUI_DIR)/imgui_widgets.cpp
OBJS = $(addsuffix .o, $(basename $(notdir $(SOURCES))))
UNAME_S := $(shell uname -s)
CPPFLAGS =
diff --git a/examples/example_sdl3_directx11/example_sdl3_directx11.vcxproj b/examples/example_sdl3_directx11/example_sdl3_directx11.vcxproj
index 057874196..6c73dbe35 100644
--- a/examples/example_sdl3_directx11/example_sdl3_directx11.vcxproj
+++ b/examples/example_sdl3_directx11/example_sdl3_directx11.vcxproj
@@ -165,6 +165,7 @@
+
@@ -175,6 +176,8 @@
+
+
diff --git a/examples/example_sdl3_directx11/example_sdl3_directx11.vcxproj.filters b/examples/example_sdl3_directx11/example_sdl3_directx11.vcxproj.filters
index 0579b7a64..a4359e35b 100644
--- a/examples/example_sdl3_directx11/example_sdl3_directx11.vcxproj.filters
+++ b/examples/example_sdl3_directx11/example_sdl3_directx11.vcxproj.filters
@@ -18,6 +18,12 @@
imgui
+
+ imgui
+
+
+ imgui
+
sources
@@ -38,6 +44,9 @@
imgui
+
+ imgui
+
imgui
diff --git a/examples/example_sdl3_metal/Makefile b/examples/example_sdl3_metal/Makefile
index 9093ae133..15ade8437 100644
--- a/examples/example_sdl3_metal/Makefile
+++ b/examples/example_sdl3_metal/Makefile
@@ -9,7 +9,7 @@
EXE = example_sdl3_metal
IMGUI_DIR = ../..
SOURCES = main.mm
-SOURCES += $(IMGUI_DIR)/imgui.cpp $(IMGUI_DIR)/imgui_demo.cpp $(IMGUI_DIR)/imgui_draw.cpp $(IMGUI_DIR)/imgui_tables.cpp $(IMGUI_DIR)/imgui_widgets.cpp
+SOURCES += $(IMGUI_DIR)/imgui.cpp $(IMGUI_DIR)/imgui_demo.cpp $(IMGUI_DIR)/imgui_draw.cpp $(IMGUI_DIR)/imgui_stacklayout.cpp $(IMGUI_DIR)/imgui_tables.cpp $(IMGUI_DIR)/imgui_widgets.cpp
SOURCES += $(IMGUI_DIR)/backends/imgui_impl_sdl3.cpp $(IMGUI_DIR)/backends/imgui_impl_metal.mm
OBJS = $(addsuffix .o, $(basename $(notdir $(SOURCES))))
diff --git a/examples/example_sdl3_metal4/Makefile b/examples/example_sdl3_metal4/Makefile
index 55c83416c..21f102bef 100644
--- a/examples/example_sdl3_metal4/Makefile
+++ b/examples/example_sdl3_metal4/Makefile
@@ -9,7 +9,7 @@
EXE = example_sdl3_metal4
IMGUI_DIR = ../..
SOURCES = main.mm
-SOURCES += $(IMGUI_DIR)/imgui.cpp $(IMGUI_DIR)/imgui_demo.cpp $(IMGUI_DIR)/imgui_draw.cpp $(IMGUI_DIR)/imgui_tables.cpp $(IMGUI_DIR)/imgui_widgets.cpp
+SOURCES += $(IMGUI_DIR)/imgui.cpp $(IMGUI_DIR)/imgui_demo.cpp $(IMGUI_DIR)/imgui_draw.cpp $(IMGUI_DIR)/imgui_stacklayout.cpp $(IMGUI_DIR)/imgui_tables.cpp $(IMGUI_DIR)/imgui_widgets.cpp
SOURCES += $(IMGUI_DIR)/backends/imgui_impl_sdl3.cpp $(IMGUI_DIR)/backends/imgui_impl_metal4.mm
OBJS = $(addsuffix .o, $(basename $(notdir $(SOURCES))))
diff --git a/examples/example_sdl3_opengl3/Makefile b/examples/example_sdl3_opengl3/Makefile
index d9c6eac9e..eb3bcd9fb 100644
--- a/examples/example_sdl3_opengl3/Makefile
+++ b/examples/example_sdl3_opengl3/Makefile
@@ -10,7 +10,7 @@
EXE = example_sdl3_opengl3
IMGUI_DIR = ../..
SOURCES = main.cpp
-SOURCES += $(IMGUI_DIR)/imgui.cpp $(IMGUI_DIR)/imgui_demo.cpp $(IMGUI_DIR)/imgui_draw.cpp $(IMGUI_DIR)/imgui_tables.cpp $(IMGUI_DIR)/imgui_widgets.cpp
+SOURCES += $(IMGUI_DIR)/imgui.cpp $(IMGUI_DIR)/imgui_demo.cpp $(IMGUI_DIR)/imgui_draw.cpp $(IMGUI_DIR)/imgui_stacklayout.cpp $(IMGUI_DIR)/imgui_tables.cpp $(IMGUI_DIR)/imgui_widgets.cpp
SOURCES += $(IMGUI_DIR)/backends/imgui_impl_sdl3.cpp $(IMGUI_DIR)/backends/imgui_impl_opengl3.cpp
OBJS = $(addsuffix .o, $(basename $(notdir $(SOURCES))))
UNAME_S := $(shell uname -s)
diff --git a/examples/example_sdl3_opengl3/Makefile.emscripten b/examples/example_sdl3_opengl3/Makefile.emscripten
index ce873ed1a..ae927447f 100644
--- a/examples/example_sdl3_opengl3/Makefile.emscripten
+++ b/examples/example_sdl3_opengl3/Makefile.emscripten
@@ -23,7 +23,7 @@ WEB_DIR = web
EXE = $(WEB_DIR)/index.html
IMGUI_DIR = ../..
SOURCES = main.cpp
-SOURCES += $(IMGUI_DIR)/imgui.cpp $(IMGUI_DIR)/imgui_demo.cpp $(IMGUI_DIR)/imgui_draw.cpp $(IMGUI_DIR)/imgui_tables.cpp $(IMGUI_DIR)/imgui_widgets.cpp
+SOURCES += $(IMGUI_DIR)/imgui.cpp $(IMGUI_DIR)/imgui_demo.cpp $(IMGUI_DIR)/imgui_draw.cpp $(IMGUI_DIR)/imgui_stacklayout.cpp $(IMGUI_DIR)/imgui_tables.cpp $(IMGUI_DIR)/imgui_widgets.cpp
SOURCES += $(IMGUI_DIR)/backends/imgui_impl_sdl3.cpp $(IMGUI_DIR)/backends/imgui_impl_opengl3.cpp
OBJS = $(addsuffix .o, $(basename $(notdir $(SOURCES))))
UNAME_S := $(shell uname -s)
diff --git a/examples/example_sdl3_opengl3/example_sdl3_opengl3.vcxproj b/examples/example_sdl3_opengl3/example_sdl3_opengl3.vcxproj
index dbe1fa915..f35f33c95 100644
--- a/examples/example_sdl3_opengl3/example_sdl3_opengl3.vcxproj
+++ b/examples/example_sdl3_opengl3/example_sdl3_opengl3.vcxproj
@@ -164,6 +164,7 @@
+
@@ -174,6 +175,8 @@
+
+
diff --git a/examples/example_sdl3_opengl3/example_sdl3_opengl3.vcxproj.filters b/examples/example_sdl3_opengl3/example_sdl3_opengl3.vcxproj.filters
index f365473c4..79f38f4eb 100644
--- a/examples/example_sdl3_opengl3/example_sdl3_opengl3.vcxproj.filters
+++ b/examples/example_sdl3_opengl3/example_sdl3_opengl3.vcxproj.filters
@@ -28,6 +28,9 @@
sources
+
+ imgui
+
imgui
@@ -45,6 +48,12 @@
imgui
+
+ imgui
+
+
+ imgui
+
sources
diff --git a/examples/example_sdl3_sdlgpu3/Makefile b/examples/example_sdl3_sdlgpu3/Makefile
index c3159d888..4f7d7d1ce 100644
--- a/examples/example_sdl3_sdlgpu3/Makefile
+++ b/examples/example_sdl3_sdlgpu3/Makefile
@@ -10,7 +10,7 @@
EXE = example_sdl3_sdlgpu3
IMGUI_DIR = ../..
SOURCES = main.cpp
-SOURCES += $(IMGUI_DIR)/imgui.cpp $(IMGUI_DIR)/imgui_demo.cpp $(IMGUI_DIR)/imgui_draw.cpp $(IMGUI_DIR)/imgui_tables.cpp $(IMGUI_DIR)/imgui_widgets.cpp
+SOURCES += $(IMGUI_DIR)/imgui.cpp $(IMGUI_DIR)/imgui_demo.cpp $(IMGUI_DIR)/imgui_draw.cpp $(IMGUI_DIR)/imgui_stacklayout.cpp $(IMGUI_DIR)/imgui_tables.cpp $(IMGUI_DIR)/imgui_widgets.cpp
SOURCES += $(IMGUI_DIR)/backends/imgui_impl_sdl3.cpp $(IMGUI_DIR)/backends/imgui_impl_sdlgpu3.cpp
OBJS = $(addsuffix .o, $(basename $(notdir $(SOURCES))))
UNAME_S := $(shell uname -s)
diff --git a/examples/example_sdl3_sdlgpu3/example_sdl3_sdlgpu3.vcxproj b/examples/example_sdl3_sdlgpu3/example_sdl3_sdlgpu3.vcxproj
index bd83258d8..7e9826f2b 100644
--- a/examples/example_sdl3_sdlgpu3/example_sdl3_sdlgpu3.vcxproj
+++ b/examples/example_sdl3_sdlgpu3/example_sdl3_sdlgpu3.vcxproj
@@ -169,6 +169,7 @@
+
@@ -180,6 +181,8 @@
+
+
diff --git a/examples/example_sdl3_sdlgpu3/example_sdl3_sdlgpu3.vcxproj.filters b/examples/example_sdl3_sdlgpu3/example_sdl3_sdlgpu3.vcxproj.filters
index 4710b550c..ad292af81 100644
--- a/examples/example_sdl3_sdlgpu3/example_sdl3_sdlgpu3.vcxproj.filters
+++ b/examples/example_sdl3_sdlgpu3/example_sdl3_sdlgpu3.vcxproj.filters
@@ -19,6 +19,9 @@
imgui
+
+ imgui
+
imgui
@@ -45,6 +48,12 @@
imgui
+
+ imgui
+
+
+ imgui
+
diff --git a/examples/example_sdl3_sdlrenderer3/Makefile b/examples/example_sdl3_sdlrenderer3/Makefile
index c278f7830..8eab06e9f 100644
--- a/examples/example_sdl3_sdlrenderer3/Makefile
+++ b/examples/example_sdl3_sdlrenderer3/Makefile
@@ -10,7 +10,7 @@
EXE = example_sdl3_sdlrenderer3
IMGUI_DIR = ../..
SOURCES = main.cpp
-SOURCES += $(IMGUI_DIR)/imgui.cpp $(IMGUI_DIR)/imgui_demo.cpp $(IMGUI_DIR)/imgui_draw.cpp $(IMGUI_DIR)/imgui_tables.cpp $(IMGUI_DIR)/imgui_widgets.cpp
+SOURCES += $(IMGUI_DIR)/imgui.cpp $(IMGUI_DIR)/imgui_demo.cpp $(IMGUI_DIR)/imgui_draw.cpp $(IMGUI_DIR)/imgui_stacklayout.cpp $(IMGUI_DIR)/imgui_tables.cpp $(IMGUI_DIR)/imgui_widgets.cpp
SOURCES += $(IMGUI_DIR)/backends/imgui_impl_sdl3.cpp $(IMGUI_DIR)/backends/imgui_impl_sdlrenderer3.cpp
OBJS = $(addsuffix .o, $(basename $(notdir $(SOURCES))))
UNAME_S := $(shell uname -s)
diff --git a/examples/example_sdl3_sdlrenderer3/example_sdl3_sdlrenderer3.vcxproj b/examples/example_sdl3_sdlrenderer3/example_sdl3_sdlrenderer3.vcxproj
index 35fc962ad..b4c58aebe 100644
--- a/examples/example_sdl3_sdlrenderer3/example_sdl3_sdlrenderer3.vcxproj
+++ b/examples/example_sdl3_sdlrenderer3/example_sdl3_sdlrenderer3.vcxproj
@@ -165,6 +165,7 @@
+
@@ -175,6 +176,8 @@
+
+
diff --git a/examples/example_sdl3_sdlrenderer3/example_sdl3_sdlrenderer3.vcxproj.filters b/examples/example_sdl3_sdlrenderer3/example_sdl3_sdlrenderer3.vcxproj.filters
index c41210d67..3fb37d3c8 100644
--- a/examples/example_sdl3_sdlrenderer3/example_sdl3_sdlrenderer3.vcxproj.filters
+++ b/examples/example_sdl3_sdlrenderer3/example_sdl3_sdlrenderer3.vcxproj.filters
@@ -25,6 +25,9 @@
sources
+
+ imgui
+
imgui
@@ -45,6 +48,12 @@
imgui
+
+ imgui
+
+
+ imgui
+
sources
diff --git a/examples/example_sdl3_vulkan/Makefile b/examples/example_sdl3_vulkan/Makefile
index e1956ff67..35fd10b49 100644
--- a/examples/example_sdl3_vulkan/Makefile
+++ b/examples/example_sdl3_vulkan/Makefile
@@ -12,7 +12,7 @@
EXE = example_sdl3_vulkan
IMGUI_DIR = ../..
SOURCES = main.cpp
-SOURCES += $(IMGUI_DIR)/imgui.cpp $(IMGUI_DIR)/imgui_demo.cpp $(IMGUI_DIR)/imgui_draw.cpp $(IMGUI_DIR)/imgui_tables.cpp $(IMGUI_DIR)/imgui_widgets.cpp
+SOURCES += $(IMGUI_DIR)/imgui.cpp $(IMGUI_DIR)/imgui_demo.cpp $(IMGUI_DIR)/imgui_draw.cpp $(IMGUI_DIR)/imgui_stacklayout.cpp $(IMGUI_DIR)/imgui_tables.cpp $(IMGUI_DIR)/imgui_widgets.cpp
SOURCES += $(IMGUI_DIR)/backends/imgui_impl_sdl3.cpp $(IMGUI_DIR)/backends/imgui_impl_vulkan.cpp
OBJS = $(addsuffix .o, $(basename $(notdir $(SOURCES))))
UNAME_S := $(shell uname -s)
diff --git a/examples/example_sdl3_vulkan/example_sdl3_vulkan.vcxproj b/examples/example_sdl3_vulkan/example_sdl3_vulkan.vcxproj
index c3a200cf5..3d9431f66 100644
--- a/examples/example_sdl3_vulkan/example_sdl3_vulkan.vcxproj
+++ b/examples/example_sdl3_vulkan/example_sdl3_vulkan.vcxproj
@@ -168,6 +168,7 @@
+
@@ -178,6 +179,8 @@
+
+
diff --git a/examples/example_sdl3_vulkan/example_sdl3_vulkan.vcxproj.filters b/examples/example_sdl3_vulkan/example_sdl3_vulkan.vcxproj.filters
index 46ebb5829..7df46f162 100644
--- a/examples/example_sdl3_vulkan/example_sdl3_vulkan.vcxproj.filters
+++ b/examples/example_sdl3_vulkan/example_sdl3_vulkan.vcxproj.filters
@@ -31,6 +31,9 @@
imgui
+
+ imgui
+
imgui
@@ -45,6 +48,12 @@
imgui
+
+ imgui
+
+
+ imgui
+
sources
diff --git a/examples/example_sdl3_wgpu/CMakeLists.txt b/examples/example_sdl3_wgpu/CMakeLists.txt
index b05dcd459..7589ba7a9 100644
--- a/examples/example_sdl3_wgpu/CMakeLists.txt
+++ b/examples/example_sdl3_wgpu/CMakeLists.txt
@@ -52,6 +52,7 @@ set(IMGUI_EXAMPLE_SOURCE_FILES
${IMGUI_DIR}/imgui.cpp
${IMGUI_DIR}/imgui_draw.cpp
${IMGUI_DIR}/imgui_demo.cpp
+ ${IMGUI_DIR}/imgui_stacklayout.cpp
${IMGUI_DIR}/imgui_tables.cpp
${IMGUI_DIR}/imgui_widgets.cpp
)
diff --git a/examples/example_sdl3_wgpu/Makefile.emscripten b/examples/example_sdl3_wgpu/Makefile.emscripten
index c84acc77f..77a79800a 100644
--- a/examples/example_sdl3_wgpu/Makefile.emscripten
+++ b/examples/example_sdl3_wgpu/Makefile.emscripten
@@ -20,7 +20,7 @@ EXE = $(WEB_DIR)/index.html
IMGUI_DIR = ../..
SOURCES = main.cpp
SOURCES += $(IMGUI_DIR)/backends/imgui_impl_sdl3.cpp $(IMGUI_DIR)/backends/imgui_impl_wgpu.cpp
-SOURCES += $(IMGUI_DIR)/imgui.cpp $(IMGUI_DIR)/imgui_demo.cpp $(IMGUI_DIR)/imgui_draw.cpp $(IMGUI_DIR)/imgui_tables.cpp $(IMGUI_DIR)/imgui_widgets.cpp
+SOURCES += $(IMGUI_DIR)/imgui.cpp $(IMGUI_DIR)/imgui_demo.cpp $(IMGUI_DIR)/imgui_draw.cpp $(IMGUI_DIR)/imgui_stacklayout.cpp $(IMGUI_DIR)/imgui_tables.cpp $(IMGUI_DIR)/imgui_widgets.cpp
OBJS = $(addsuffix .o, $(basename $(notdir $(SOURCES))))
UNAME_S := $(shell uname -s)
CPPFLAGS =
diff --git a/examples/example_win32_directx10/example_win32_directx10.vcxproj b/examples/example_win32_directx10/example_win32_directx10.vcxproj
index add37ed97..2316a6d81 100644
--- a/examples/example_win32_directx10/example_win32_directx10.vcxproj
+++ b/examples/example_win32_directx10/example_win32_directx10.vcxproj
@@ -154,6 +154,8 @@
+
+
@@ -161,6 +163,7 @@
+
diff --git a/examples/example_win32_directx10/example_win32_directx10.vcxproj.filters b/examples/example_win32_directx10/example_win32_directx10.vcxproj.filters
index 33ab99b51..fb449f27b 100644
--- a/examples/example_win32_directx10/example_win32_directx10.vcxproj.filters
+++ b/examples/example_win32_directx10/example_win32_directx10.vcxproj.filters
@@ -18,6 +18,12 @@
imgui
+
+ imgui
+
+
+ imgui
+
sources
@@ -44,6 +50,9 @@
sources
+
+ imgui
+
imgui
diff --git a/examples/example_win32_directx11/example_win32_directx11.vcxproj b/examples/example_win32_directx11/example_win32_directx11.vcxproj
index ed0b509a8..53d5ec862 100644
--- a/examples/example_win32_directx11/example_win32_directx11.vcxproj
+++ b/examples/example_win32_directx11/example_win32_directx11.vcxproj
@@ -154,6 +154,8 @@
+
+
@@ -161,6 +163,7 @@
+
diff --git a/examples/example_win32_directx11/example_win32_directx11.vcxproj.filters b/examples/example_win32_directx11/example_win32_directx11.vcxproj.filters
index 63032a6aa..040fb9683 100644
--- a/examples/example_win32_directx11/example_win32_directx11.vcxproj.filters
+++ b/examples/example_win32_directx11/example_win32_directx11.vcxproj.filters
@@ -18,6 +18,12 @@
imgui
+
+ imgui
+
+
+ imgui
+
sources
@@ -47,6 +53,9 @@
sources
+
+ imgui
+
imgui
diff --git a/examples/example_win32_directx12/example_win32_directx12.vcxproj b/examples/example_win32_directx12/example_win32_directx12.vcxproj
index 27b501d85..4479d0d78 100644
--- a/examples/example_win32_directx12/example_win32_directx12.vcxproj
+++ b/examples/example_win32_directx12/example_win32_directx12.vcxproj
@@ -156,6 +156,8 @@
+
+
@@ -163,6 +165,7 @@
+
diff --git a/examples/example_win32_directx12/example_win32_directx12.vcxproj.filters b/examples/example_win32_directx12/example_win32_directx12.vcxproj.filters
index 23a99526f..8d887c775 100644
--- a/examples/example_win32_directx12/example_win32_directx12.vcxproj.filters
+++ b/examples/example_win32_directx12/example_win32_directx12.vcxproj.filters
@@ -18,6 +18,12 @@
imgui
+
+ imgui
+
+
+ imgui
+
sources
@@ -44,6 +50,9 @@
sources
+
+ imgui
+
imgui
diff --git a/examples/example_win32_directx9/example_win32_directx9.vcxproj b/examples/example_win32_directx9/example_win32_directx9.vcxproj
index 84e16c9c6..66219ec2c 100644
--- a/examples/example_win32_directx9/example_win32_directx9.vcxproj
+++ b/examples/example_win32_directx9/example_win32_directx9.vcxproj
@@ -154,6 +154,7 @@
+
@@ -164,6 +165,8 @@
+
+
diff --git a/examples/example_win32_directx9/example_win32_directx9.vcxproj.filters b/examples/example_win32_directx9/example_win32_directx9.vcxproj.filters
index 5ed89d6fd..c19999fbc 100644
--- a/examples/example_win32_directx9/example_win32_directx9.vcxproj.filters
+++ b/examples/example_win32_directx9/example_win32_directx9.vcxproj.filters
@@ -28,6 +28,9 @@
sources
+
+ imgui
+
imgui
@@ -45,6 +48,12 @@
imgui
+
+ imgui
+
+
+ imgui
+
sources
diff --git a/examples/example_win32_opengl3/example_win32_opengl3.vcxproj b/examples/example_win32_opengl3/example_win32_opengl3.vcxproj
index 2ffb7d413..b8ab2c48f 100644
--- a/examples/example_win32_opengl3/example_win32_opengl3.vcxproj
+++ b/examples/example_win32_opengl3/example_win32_opengl3.vcxproj
@@ -154,6 +154,7 @@
+
@@ -164,6 +165,8 @@
+
+
diff --git a/examples/example_win32_opengl3/example_win32_opengl3.vcxproj.filters b/examples/example_win32_opengl3/example_win32_opengl3.vcxproj.filters
index 47ed299bc..ababe07a0 100644
--- a/examples/example_win32_opengl3/example_win32_opengl3.vcxproj.filters
+++ b/examples/example_win32_opengl3/example_win32_opengl3.vcxproj.filters
@@ -28,6 +28,9 @@
sources
+
+ imgui
+
imgui
@@ -45,6 +48,12 @@
imgui
+
+ imgui
+
+
+ imgui
+
sources
diff --git a/examples/example_win32_vulkan/example_win32_vulkan.vcxproj b/examples/example_win32_vulkan/example_win32_vulkan.vcxproj
index bede521e2..14db55cb1 100644
--- a/examples/example_win32_vulkan/example_win32_vulkan.vcxproj
+++ b/examples/example_win32_vulkan/example_win32_vulkan.vcxproj
@@ -157,6 +157,8 @@
+
+
@@ -164,6 +166,7 @@
+
diff --git a/examples/example_win32_vulkan/example_win32_vulkan.vcxproj.filters b/examples/example_win32_vulkan/example_win32_vulkan.vcxproj.filters
index c91a95810..3d2d9835e 100644
--- a/examples/example_win32_vulkan/example_win32_vulkan.vcxproj.filters
+++ b/examples/example_win32_vulkan/example_win32_vulkan.vcxproj.filters
@@ -18,6 +18,12 @@
imgui
+
+ imgui
+
+
+ imgui
+
sources
@@ -47,6 +53,9 @@
sources
+
+ imgui
+
imgui
diff --git a/imgui.cpp b/imgui.cpp
index 910c34e9b..1428c3510 100644
--- a/imgui.cpp
+++ b/imgui.cpp
@@ -1581,6 +1581,7 @@ ImGuiStyle::ImGuiStyle()
ScrollbarPadding = 2.0f; // Padding of scrollbar grab within its frame (same for both axes)
GrabMinSize = 12.0f; // Minimum width/height of a grab box for slider/scrollbar
GrabRounding = 0.0f; // Radius of grabs corners rounding. Set to 0.0f to have rectangular slider grabs.
+ LayoutAlign = 0.5f; // Element alignment inside horizontal and vertical layouts (0.0f - left/top, 1.0f - right/bottom, 0.5f - center).
LogSliderDeadzone = 4.0f; // The size in pixels of the dead-zone around zero on logarithmic sliders that cross zero.
ImageRounding = 0.0f; // Rounding of Image() calls.
ImageBorderSize = 0.0f; // Thickness of border around Image() calls.
@@ -3812,6 +3813,7 @@ static const ImGuiStyleVarInfo GStyleVarsInfo[] =
{ 1, ImGuiDataType_Float, (ImU32)offsetof(ImGuiStyle, SeparatorTextBorderSize)}, // ImGuiStyleVar_SeparatorTextBorderSize
{ 2, ImGuiDataType_Float, (ImU32)offsetof(ImGuiStyle, SeparatorTextAlign) }, // ImGuiStyleVar_SeparatorTextAlign
{ 2, ImGuiDataType_Float, (ImU32)offsetof(ImGuiStyle, SeparatorTextPadding) }, // ImGuiStyleVar_SeparatorTextPadding
+ { 1, ImGuiDataType_Float, (ImU32)offsetof(ImGuiStyle, LayoutAlign) }, // ImGuiStyleVar_LayoutAlign
};
const ImGuiStyleVarInfo* ImGui::GetStyleVarInfo(ImGuiStyleVar idx)
@@ -11357,6 +11359,9 @@ void ImGui::ErrorRecoveryTryToRecoverWindowState(const ImGuiErrorRecoveryStat
IM_ASSERT_USER_ERROR(0, "Missing EndMultiSelect()");
EndMultiSelect();
}
+#ifdef IMGUI_HAS_STACK_LAYOUT
+ ImGuiStackLayout::ErrorRecoveryTryToRecoverWindowState(state_in);
+#endif
if (window->DC.MenuBarAppending) //-V1044
{
IM_ASSERT_USER_ERROR(0, "Missing EndMenuBar()");
diff --git a/imgui.h b/imgui.h
index df2d42675..e55049cec 100644
--- a/imgui.h
+++ b/imgui.h
@@ -33,6 +33,7 @@
#define IMGUI_VERSION_NUM 19300
#define IMGUI_HAS_TABLE // Added BeginTable() - from IMGUI_VERSION_NUM >= 18000
#define IMGUI_HAS_TEXTURES // Added ImGuiBackendFlags_RendererHasTextures - from IMGUI_VERSION_NUM >= 19198
+#define IMGUI_HAS_STACK_LAYOUT // Stack-Layout PR #846
/*
@@ -1901,6 +1902,7 @@ enum ImGuiStyleVar_
ImGuiStyleVar_SeparatorTextBorderSize, // float SeparatorTextBorderSize
ImGuiStyleVar_SeparatorTextAlign, // ImVec2 SeparatorTextAlign
ImGuiStyleVar_SeparatorTextPadding, // ImVec2 SeparatorTextPadding
+ ImGuiStyleVar_LayoutAlign, // float LayoutAlign
ImGuiStyleVar_COUNT
};
@@ -2360,6 +2362,7 @@ struct ImGuiStyle
float ScrollbarPadding; // Padding of scrollbar grab within its frame (same for both axes).
float GrabMinSize; // Minimum width/height of a grab box for slider/scrollbar.
float GrabRounding; // Radius of grabs corners rounding. Set to 0.0f to have rectangular slider grabs.
+ float LayoutAlign; // Element alignment inside horizontal and vertical layouts (0.0f - left/top, 1.0f - right/bottom, 0.5f - center).
float LogSliderDeadzone; // The size in pixels of the dead-zone around zero on logarithmic sliders that cross zero.
float ImageRounding; // Rounding of Image() calls.
float ImageBorderSize; // Thickness of border around Image() calls.
@@ -4393,6 +4396,10 @@ typedef ImFontAtlasRect ImFontAtlasCustomRect;
#pragma warning (pop)
#endif
+#ifdef IMGUI_HAS_STACK_LAYOUT
+#include "imgui_stacklayout.h"
+#endif
+
// Include imgui_user.h at the end of imgui.h
// May be convenient for some users to only explicitly include vanilla imgui.h and have extra stuff included.
#ifdef IMGUI_INCLUDE_IMGUI_USER_H
diff --git a/imgui_demo.cpp b/imgui_demo.cpp
index 13734d316..ffc84d1c7 100644
--- a/imgui_demo.cpp
+++ b/imgui_demo.cpp
@@ -5520,6 +5520,88 @@ static void DemoWindowLayout()
ImGui::TreePop();
}
+
+#ifdef IMGUI_HAS_STACK_LAYOUT
+ IMGUI_DEMO_MARKER("Layout/Stack Layout");
+ if (ImGui::TreeNode("Stack Layout"))
+ {
+ static bool widget_a = true, widget_b = true, widget_c = true;
+ static bool spring_a = true, spring_ab = true, spring_bc = true, spring_c = true;
+ static bool minimize_width = false, minimize_height = true;
+ static bool horizontal = true, draw_springs = true;
+ static ImVec2 item_spacing = ImGui::GetStyle().ItemSpacing;
+ static float a_c_spring_weight = 0.0f;
+ static float ab_spring_weight = 0.5f;
+ static float alignment = 0.5f;
+
+ ImGui::Checkbox("Widget A", &widget_a); ImGui::SameLine();
+ ImGui::Checkbox("Widget B", &widget_b); ImGui::SameLine();
+ ImGui::Checkbox("Widget C", &widget_c);
+ ImGui::Checkbox("Spring A", &spring_a); ImGui::SameLine();
+ ImGui::Checkbox("Spring AB", &spring_ab); ImGui::SameLine();
+ ImGui::Checkbox("Spring BC", &spring_bc); ImGui::SameLine();
+ ImGui::Checkbox("Spring C", &spring_c);
+ ImGui::Checkbox("Horizontal", &horizontal); ImGui::SameLine();
+ ImGui::Checkbox("Minimize Width", &minimize_width); ImGui::SameLine();
+ ImGui::Checkbox("Minimize Height", &minimize_height);
+ ImGui::Checkbox("Draw Springs", &draw_springs); ImGui::SameLine();
+ ImGui::TextUnformatted(" "); ImGui::SameLine();
+ ImGui::ColorButton("- Spring", ImColor(80, 20, 80), ImGuiColorEditFlags_NoTooltip | ImGuiColorEditFlags_NoPicker); ImGui::SameLine();
+ ImGui::TextUnformatted("Spring"); ImGui::SameLine();
+ ImGui::TextUnformatted(" "); ImGui::SameLine();
+ ImGui::ColorButton("- Spacing", ImColor(80, 20, 20), ImGuiColorEditFlags_NoTooltip | ImGuiColorEditFlags_NoPicker); ImGui::SameLine();
+ ImGui::TextUnformatted("Item Spacing");
+ ImGui::DragFloat("Item Spacing", horizontal ? &item_spacing.x : &item_spacing.y, 0.1f, 0.0f, 50.0f);
+ ImGui::DragFloat("A & C Spring Weight", &a_c_spring_weight, 0.002f, 0.0f, 1.0f);
+ ImGui::DragFloat("AB Spring Weight", &ab_spring_weight, 0.002f, 0.0f, 1.0f);
+ if (ImGui::IsItemHovered()) ImGui::SetTooltip("BC Spring Weight = 1 - AB Spring Weight");
+ ImGui::DragFloat("Minor Axis Alignment", &alignment, 0.002f, 0.0f, 1.0f);
+ if (ImGui::IsItemHovered()) ImGui::SetTooltip("This is vertical alignment for horizontal layouts and horizontal alignment for vertical layouts.");
+ ImGui::Text("Layout widgets:");
+ ImGui::Text("| Spring A | Widget A | Spring AB | Widget B | Spring BC | Widget C | Spring C |");
+
+ ImGui::Spacing();
+
+ ImVec2 widget_size;
+ widget_size.x = floorf(ImGui::GetContentRegionAvail().x / 4);
+ widget_size.y = horizontal ? floorf(widget_size.x / 3) : widget_size.x;
+
+ ImVec2 small_widget_size = widget_size;
+ if (horizontal)
+ small_widget_size.y = floorf(small_widget_size.y / 2);
+ else
+ small_widget_size.x = floorf(small_widget_size.x / 2);
+
+ ImVec2 layout_size = ImVec2(widget_size.x * 4, widget_size.y * 4);
+ if (minimize_width) layout_size.x = 0.0f;
+ if (minimize_height) layout_size.y = 0.0f;
+
+ // Minor axis alignment can be set by style or directly in BeginHorizontal/BeginVertical
+ // Example:
+ // ImGui::PushStyleVar(ImGuiStyleVar_LayoutAlign, alignment);
+
+ ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(floorf(item_spacing.x), floorf(item_spacing.y)));
+
+ // The layout draws its springs: their sizes are known once the layout ends.
+ ImGui::SetNextLayoutDebugFlags(draw_springs ? ImGuiLayoutDebugFlags_DrawSprings : ImGuiLayoutDebugFlags_None);
+ if (horizontal) { ImGui::BeginHorizontal("h1", layout_size, alignment); } else { ImGui::BeginVertical("v1", layout_size, alignment); }
+ if (spring_a) { ImGui::Spring(a_c_spring_weight); }
+ if (widget_a) { ImGui::Button("Widget A", widget_size); }
+ if (spring_ab) { ImGui::Spring(ab_spring_weight); }
+ if (widget_b) { ImGui::Button("Widget B", small_widget_size); }
+ if (spring_bc) { ImGui::Spring(1.0f - ab_spring_weight); }
+ if (widget_c) { ImGui::Button("Widget C", widget_size); }
+ if (spring_c) { ImGui::Spring(a_c_spring_weight); }
+ if (horizontal) { ImGui::EndHorizontal(); } else { ImGui::EndVertical(); }
+
+ ImGui::PopStyleVar();
+
+ ImDrawList* draw_list = ImGui::GetWindowDrawList();
+ draw_list->AddRect(ImGui::GetItemRectMin(), ImGui::GetItemRectMax(), ImGui::GetColorU32(ImGuiCol_Border));
+
+ ImGui::TreePop();
+ }
+#endif // IMGUI_HAS_STACK_LAYOUT
}
//-----------------------------------------------------------------------------
@@ -8799,6 +8881,10 @@ void ImGui::ShowStyleEditor(ImGuiStyle* ref)
SameLine(); HelpMarker("Alignment applies when a button is larger than its text content.");
SliderFloat2("SelectableTextAlign", (float*)&style.SelectableTextAlign, 0.0f, 1.0f, "%.2f");
SameLine(); HelpMarker("Alignment applies when a selectable is larger than its text content.");
+#ifdef IMGUI_HAS_STACK_LAYOUT
+ SliderFloat("LayoutAlign", &style.LayoutAlign, 0.0f, 1.0f, "%.2f");
+ SameLine(); HelpMarker("Alignment of items on the other axis of BeginHorizontal()/BeginVertical() layouts, when they are given no alignment.");
+#endif
SliderFloat("SeparatorSize", &style.SeparatorSize, 0.0f, 10.0f, "%.0f");
SliderFloat("SeparatorTextBorderSize", &style.SeparatorTextBorderSize, 0.0f, 10.0f, "%.0f");
SliderFloat2("SeparatorTextAlign", (float*)&style.SeparatorTextAlign, 0.0f, 1.0f, "%.2f");
diff --git a/imgui_internal.h b/imgui_internal.h
index 2932cb53a..273b4cab6 100644
--- a/imgui_internal.h
+++ b/imgui_internal.h
@@ -11,6 +11,7 @@ Index of this file:
// [SECTION] Forward declarations
// [SECTION] Context pointer
// [SECTION] STB libraries includes
+// [SECTION] Stack Layout includes
// [SECTION] Macros
// [SECTION] Generic helpers
// [SECTION] ImDrawList support
@@ -229,6 +230,14 @@ typedef ImU16 ImGuiTableDrawChannelIdx;
extern IMGUI_API ImGuiContext* GImGui; // Current implicit context pointer
#endif
+//-------------------------------------------------------------------------
+// [SECTION] Stack Layout includes
+//-------------------------------------------------------------------------
+
+#ifdef IMGUI_HAS_STACK_LAYOUT
+# include "imgui_stacklayout_internal.h"
+#endif
+
//-----------------------------------------------------------------------------
// [SECTION] Macros
//-----------------------------------------------------------------------------
diff --git a/imgui_stacklayout.cpp b/imgui_stacklayout.cpp
new file mode 100644
index 000000000..3793fa525
--- /dev/null
+++ b/imgui_stacklayout.cpp
@@ -0,0 +1,1382 @@
+// dear imgui: stack layouts
+// (stack layout code)
+
+/*
+
+Index of this file:
+
+// [SECTION] Commentary
+// [SECTION] Header mess
+// [SECTION] Stack layout: Forward declarations
+// [SECTION] Stack layout: flags, enums, data structures
+// [SECTION] Stack Layout: Context forward declarations
+// [SECTION] Stack Layout: Internal code forward declarations
+// [SECTION] Stack Layout: Context
+// [SECTION] Stack Layout: Internal code
+// [SECTION] Stack Layout: Internal API
+// [SECTION] Stack Layout: Public API
+
+*/
+
+// Navigating this file:
+// - In Visual Studio IDE: CTRL+comma ("Edit.NavigateTo") can follow symbols in comments, whereas CTRL+F12 ("Edit.GoToImplementation") cannot.
+// - With Visual Assist installed: ALT+G ("VAssistX.GoToImplementation") can also follow symbols in comments.
+
+//-----------------------------------------------------------------------------
+// [SECTION] Commentary
+//-----------------------------------------------------------------------------
+
+//-----------------------------------------------------------------------------
+// Typical call flow: (root level is generally public API):
+//-----------------------------------------------------------------------------
+//
+// - BeginHorizontal/BeginVertical() user begin into a layout
+// - [...] user emit contents
+// - | Spring() - separate widget groups in layout
+// - | SuspendLayout() - stop any layout operations
+// - | ResumeLayout() - resume layout operations
+//-----------------------------------------------------------------------------
+// - EndHorizontal/EndVertical() user ends the layout
+//-----------------------------------------------------------------------------
+
+
+//-----------------------------------------------------------------------------
+// [SECTION] Header mess
+//-----------------------------------------------------------------------------
+
+#if defined(_MSC_VER) && !defined(_CRT_SECURE_NO_WARNINGS)
+#define _CRT_SECURE_NO_WARNINGS
+#endif
+
+#ifndef IMGUI_DEFINE_MATH_OPERATORS
+#define IMGUI_DEFINE_MATH_OPERATORS
+#endif
+
+#include "imgui.h"
+#ifndef IMGUI_DISABLE
+#include "imgui_internal.h"
+
+// Clang/GCC warnings with -Weverything
+#if defined(__clang__)
+#if __has_warning("-Wunknown-warning-option")
+#pragma clang diagnostic ignored "-Wunknown-warning-option" // warning: unknown warning group 'xxx' // not all warnings are known by all Clang versions and they tend to be rename-happy.. so ignoring warnings triggers new warnings on some configuration. Great!
+#endif
+#pragma clang diagnostic ignored "-Wunknown-pragmas" // warning: unknown warning group 'xxx'
+#pragma clang diagnostic ignored "-Wold-style-cast" // warning: use of old-style cast // yes, they are more terse.
+#pragma clang diagnostic ignored "-Wfloat-equal" // warning: comparing floating point with == or != is unsafe // storing and comparing against same constants (typically 0.0f) is ok.
+#pragma clang diagnostic ignored "-Wsign-conversion" // warning: implicit conversion changes signedness
+#pragma clang diagnostic ignored "-Wunsafe-buffer-usage" // warning: 'xxx' is an unsafe pointer used for buffer access
+#elif defined(__GNUC__)
+#pragma GCC diagnostic ignored "-Wpragmas" // warning: unknown option after '#pragma GCC diagnostic' kind
+#pragma GCC diagnostic ignored "-Wfloat-equal" // warning: comparing floating-point with '==' or '!=' is unsafe
+#pragma GCC diagnostic ignored "-Wconversion" // warning: conversion to 'xxxx' from 'xxxx' may change value
+#pragma GCC diagnostic ignored "-Wsign-conversion" // warning: conversion to 'xxxx' from 'xxxx' may change the sign of the result
+#endif
+
+namespace ImGuiStackLayout
+{
+
+//-----------------------------------------------------------------------------
+// [SECTION] Stack layout: Forward declarations
+//-----------------------------------------------------------------------------
+
+// Use your programming IDE "Go to definition" facility on the names of the center columns to find the actual flags/enum lists.
+typedef int ImGuiLayoutItemType; // -> enum ImGuiLayoutItemType_ // Enum: Item or Spring
+
+
+//-----------------------------------------------------------------------------
+// [SECTION] Stack layout: flags, enums, data structures
+//-----------------------------------------------------------------------------
+
+enum ImGuiLayoutItemType_
+{
+ ImGuiLayoutItemType_Item,
+ ImGuiLayoutItemType_Spring
+};
+
+// sizeof() == 48
+struct ImGuiLayoutItem
+{
+ ImGuiLayoutItemType Type; // Type of an item
+ ImRect MeasuredBounds;
+
+ float SpringWeight; // Weight of a spring
+ float SpringSpacing; // Spring spacing
+ float SpringSize; // Calculated spring size
+
+ float CurrentAlign;
+ float CurrentAlignOffset;
+
+ int VertexIndexBegin;
+ int VertexIndexEnd;
+
+ ImGuiLayoutItem(ImGuiLayoutItemType type)
+ {
+ Type = type;
+ MeasuredBounds = ImRect(0, 0, 0, 0); // FIXME: @thedmd are you sure the default ImRect value FLT_MAX,FLT_MAX,-FLT_MAX,-FLT_MAX aren't enough here?
+ SpringWeight = 1.0f;
+ SpringSpacing = -1.0f;
+ SpringSize = 0.0f;
+ CurrentAlign = 0.0f;
+ CurrentAlignOffset = 0.0f;
+ VertexIndexBegin = VertexIndexEnd = 0;
+ }
+};
+
+struct ImGuiLayout
+{
+ ImGuiID Id;
+ ImGuiLayoutType Type;
+ int LastFrameUsed;
+ float LastTimeUsed;
+ int InstanceCount; // Further uses of the ID in the current frame.
+ int IDStackSize; // Size of the ID stack before BeginLayout() pushed the ID.
+ int GroupStackSize; // Size of the group stack when BeginLayout() was called.
+ ImVec2 Size; // Size passed to BeginLayout
+ ImVec2 CurrentSize; // Bounds of layout known at the beginning the frame.
+ ImVec2 MinimumSize; // Minimum possible size when springs are collapsed.
+ ImVec2 MeasuredSize; // Measured size with springs expanded.
+
+ ImVector Items;
+ int CurrentItemIndex;
+ int ParentItemIndex;
+ ImGuiLayout* Parent;
+ ImGuiLayout* FirstChild;
+ ImGuiLayout* NextSibling;
+ float Align; // Current item alignment.
+ ImVec2 StartPos; // Initial cursor position when BeginLayout is called.
+ ImVec2 StartCursorMaxPos; // Maximum cursor position when BeginLayout is called.
+
+ // Line state of the enclosing flow, restored by EndLayout() as EndGroup() does.
+ ImVec2 BackupCursorPosPrevLine;
+ ImVec1 BackupIndent;
+ ImVec2 BackupCurrLineSize;
+ float BackupCurrLineTextBaseOffset;
+ bool BackupIsSameLine;
+ ImGuiLayoutType BackupLayoutType;
+
+ // Last item when the current layout item began, to tell whether an item was submitted inside it.
+ ImGuiID ItemBeginLastItemId;
+ ImRect ItemBeginLastItemRect;
+
+ bool ClipRectPushed;
+
+ // Root layouts: how far corrections can move items, and the clip rect widened by it while items are submitted.
+ ImVec2 SpringSizeInTree; // Spring sizes of the layout and its nested layouts at the end of the previous frame, per axis.
+ bool WideClipRectPushed;
+ int WideClipRectCmdIndex;
+ ImVec4 WideClipRect;
+ ImVec4 NarrowClipRect;
+ ImGuiLayoutDebugFlags DebugFlags;
+
+ ImGuiLayout(ImGuiID id, ImGuiLayoutType type)
+ {
+ Id = id;
+ Type = type;
+ LastFrameUsed = -1;
+ LastTimeUsed = -1.0f;
+ InstanceCount = 0;
+ IDStackSize = 0;
+ GroupStackSize = 0;
+ Size = CurrentSize = MinimumSize = MeasuredSize = ImVec2(0, 0);
+ CurrentItemIndex = 0;
+ ParentItemIndex = 0;
+ Parent = FirstChild = NextSibling = NULL;
+ Align = -1.0f;
+ StartPos = ImVec2(0, 0);
+ StartCursorMaxPos = ImVec2(0, 0);
+ BackupCursorPosPrevLine = BackupCurrLineSize = ImVec2(0, 0);
+ BackupCurrLineTextBaseOffset = 0.0f;
+ BackupIsSameLine = false;
+ BackupLayoutType = ImGuiLayoutType_Vertical;
+ ItemBeginLastItemId = 0;
+ ClipRectPushed = false;
+ SpringSizeInTree = ImVec2(0, 0);
+ WideClipRectPushed = false;
+ WideClipRectCmdIndex = 0;
+ WideClipRect = NarrowClipRect = ImVec4(0, 0, 0, 0);
+ DebugFlags = ImGuiLayoutDebugFlags_None;
+ }
+};
+
+struct ImGuiLayoutSuspendBackup
+{
+ ImGuiLayoutType LayoutType;
+ ImVec2 CursorMaxPos;
+ int IDStackSize; // Size of the ID stack before SuspendLayout() pushed the current ID again.
+};
+
+struct ImGuiLayoutWindowState
+{
+ ImGuiWindow* Window;
+ ImGuiLayout* CurrentLayout;
+ ImVector LayoutStack;
+ ImVector SuspendStack;
+ ImGuiStorage Layouts;
+
+ ImGuiLayoutWindowState()
+ {
+ Window = NULL;
+ CurrentLayout = NULL;
+ }
+};
+
+struct ImGuiLayoutContextState
+{
+ ImGuiStorage WindowStates; // ImGuiLayoutWindowState* by window ID
+ ImGuiLayoutWindowState* LastWindowState;
+ ImGuiLayoutDebugFlags NextDebugFlags;
+
+ ImGuiLayoutContextState()
+ {
+ LastWindowState = NULL;
+ NextDebugFlags = ImGuiLayoutDebugFlags_None;
+ }
+};
+
+
+//-----------------------------------------------------------------------------
+// [SECTION] Stack Layout: Context forward declarations
+//-----------------------------------------------------------------------------
+
+// The state of a context is the UserData of its Shutdown hook, found by the hook owner.
+static ImGuiID GetHookOwnerID();
+static ImGuiLayoutContextState* FindContextState(ImGuiContext& g);
+static ImGuiLayoutContextState* GetContextState(ImGuiContext& g);
+static void NewFramePreHook(ImGuiContext* ctx, ImGuiContextHook* hook);
+static void ShutdownHook(ImGuiContext* ctx, ImGuiContextHook* hook);
+
+static ImGuiLayoutWindowState* GetCurrentWindowLayoutState();
+static void DestroyWindowLayoutState(ImGuiLayoutWindowState* window_state);
+
+
+//-----------------------------------------------------------------------------
+// [SECTION] Stack Layout: Internal code forward declarations
+//-----------------------------------------------------------------------------
+
+// Stack Layout
+static ImGuiLayout* FindLayout(ImGuiID id, ImGuiLayoutType type);
+static ImGuiLayout* CreateNewLayout(ImGuiID id, ImGuiLayoutType type, ImVec2 size);
+static void BeginLayout(ImGuiID id, ImGuiLayoutType type, ImVec2 size, float align);
+static void EndLayout(ImGuiLayoutWindowState* window_state);
+static ImVec2 CalculateLayoutSize(ImGuiLayout& layout, bool collapse_springs);
+static void PushLayout(ImGuiLayout* layout);
+static void PopLayout(ImGuiLayout* layout);
+static void BalanceLayoutSprings(ImGuiLayout& layout);
+static ImVec2 BalanceLayoutItemAlignment(ImGuiLayout& layout, ImGuiLayoutItem& item);
+static void BalanceLayoutItemsAlignment(ImGuiLayout& layout);
+static bool HasAnyNonZeroSpring(ImGuiLayout& layout);
+static void BalanceChildLayouts(ImGuiLayout& layout);
+static void BeginLayoutClipRect(ImGuiLayout& layout, bool measured);
+static void EndLayoutClipRect(ImGuiLayout& layout);
+static void BeginLayoutWideClipRect(ImGuiLayout& layout);
+static void EndLayoutWideClipRect(ImGuiLayout& layout);
+static ImVec2 CalculateSpringSizeInTree(const ImGuiLayout& layout);
+static ImGuiLayoutItem* GenerateLayoutItem(ImGuiLayout& layout, ImGuiLayoutItemType type);
+static float CalculateLayoutItemAlignmentOffset(ImGuiLayout& layout, ImGuiLayoutItem& item);
+static void TranslateLayoutItem(ImGuiLayoutItem& item, const ImVec2& offset);
+static void SignedIndent(float indent);
+static void MarkLayoutLastItem(ImGuiLayout& layout);
+static void BeginLayoutItem(ImGuiLayout& layout);
+static void EndLayoutItem(ImGuiLayout& layout);
+static void AddLayoutSpring(ImGuiLayout& layout, float weight, float spacing);
+static void DebugDrawLayout(const ImGuiLayout& layout);
+
+
+//-----------------------------------------------------------------------------
+// [SECTION] Stack Layout: Context
+//-----------------------------------------------------------------------------
+
+static ImGuiID GetHookOwnerID()
+{
+ static const ImGuiID owner_id = ImHashStr("ImGuiStackLayout");
+ return owner_id;
+}
+
+static ImGuiLayoutContextState* FindContextState(ImGuiContext& g)
+{
+ const ImGuiID owner_id = GetHookOwnerID();
+ for (ImGuiContextHook& hook : g.Hooks)
+ if (hook.Owner == owner_id && hook.Type == ImGuiContextHookType_Shutdown)
+ return (ImGuiLayoutContextState*)hook.UserData;
+ return NULL;
+}
+
+static ImGuiLayoutContextState* GetContextState(ImGuiContext& g)
+{
+ if (ImGuiLayoutContextState* state = FindContextState(g))
+ return state;
+
+ ImGuiLayoutContextState* state = IM_NEW(ImGuiLayoutContextState);
+
+ ImGuiContextHook hook;
+ hook.Owner = GetHookOwnerID();
+ hook.UserData = state;
+ hook.Type = ImGuiContextHookType_NewFramePre;
+ hook.Callback = NewFramePreHook;
+ ImGui::AddContextHook(&g, &hook);
+ hook.Type = ImGuiContextHookType_Shutdown;
+ hook.Callback = ShutdownHook;
+ ImGui::AddContextHook(&g, &hook);
+
+ return state;
+}
+
+static void NewFramePreHook(ImGuiContext* ctx, ImGuiContextHook* hook)
+{
+ ImGuiContext& g = *ctx;
+ ImGuiLayoutContextState* state = (ImGuiLayoutContextState*)hook->UserData;
+
+ // Same policy as windows and tables: free layouts unused for io.ConfigMemoryCompactTimer, all of a compacted window.
+ const bool gc_all = (g.GcCompactAll || g.IO.ConfigMemoryCompactTimer < 0.0f);
+ const float memory_compact_start_time = gc_all ? FLT_MAX : (float)g.Time - g.IO.ConfigMemoryCompactTimer;
+
+ ImVector& window_states = state->WindowStates.Data;
+ int window_states_kept = 0;
+ for (ImGuiStoragePair& window_pair : window_states)
+ {
+ ImGuiLayoutWindowState* window_state = (ImGuiLayoutWindowState*)window_pair.val_p;
+
+ // Error recovery in End() closes layouts left open, unless disabled.
+ if (window_state->LayoutStack.Size > 0)
+ {
+ IM_ASSERT_USER_ERROR(0, "Missing EndHorizontal(), EndVertical() or ResumeLayout() at the end of the frame!");
+ window_state->LayoutStack.resize(0);
+ window_state->SuspendStack.resize(0);
+ window_state->CurrentLayout = NULL;
+ }
+
+ if (window_state->Window->MemoryCompacted)
+ {
+ DestroyWindowLayoutState(window_state);
+ continue;
+ }
+
+ ImVector& layouts = window_state->Layouts.Data;
+ int layouts_kept = 0;
+ for (ImGuiStoragePair& layout_pair : layouts)
+ {
+ ImGuiLayout* layout = (ImGuiLayout*)layout_pair.val_p;
+ if (layout->LastFrameUsed != g.FrameCount && layout->LastTimeUsed < memory_compact_start_time)
+ IM_DELETE(layout);
+ else
+ layouts[layouts_kept++] = layout_pair;
+ }
+ layouts.resize(layouts_kept);
+
+ window_states[window_states_kept++] = window_pair;
+ }
+ window_states.resize(window_states_kept);
+ state->LastWindowState = NULL;
+}
+
+static void ShutdownHook(ImGuiContext* ctx, ImGuiContextHook* hook)
+{
+ IM_UNUSED(ctx);
+ ImGuiLayoutContextState* state = (ImGuiLayoutContextState*)hook->UserData;
+ for (ImGuiStoragePair& window_pair : state->WindowStates.Data)
+ DestroyWindowLayoutState((ImGuiLayoutWindowState*)window_pair.val_p);
+ IM_DELETE(state);
+ hook->UserData = NULL;
+}
+
+static ImGuiLayoutWindowState* GetCurrentWindowLayoutState()
+{
+ ImGuiContext& g = *GImGui;
+ ImGuiWindow* window = g.CurrentWindow;
+ ImGuiLayoutContextState* state = GetContextState(g);
+ if (state->LastWindowState != NULL && state->LastWindowState->Window == window)
+ return state->LastWindowState;
+
+ ImGuiLayoutWindowState* window_state = (ImGuiLayoutWindowState*)state->WindowStates.GetVoidPtr(window->ID);
+ if (window_state == NULL)
+ {
+ window_state = IM_NEW(ImGuiLayoutWindowState);
+ window_state->Window = window;
+ state->WindowStates.SetVoidPtr(window->ID, window_state);
+ }
+ state->LastWindowState = window_state;
+ return window_state;
+}
+
+static void DestroyWindowLayoutState(ImGuiLayoutWindowState* window_state)
+{
+ for (ImGuiStoragePair& layout_pair : window_state->Layouts.Data)
+ IM_DELETE((ImGuiLayout*)layout_pair.val_p);
+ IM_DELETE(window_state);
+}
+
+
+//-----------------------------------------------------------------------------
+// [SECTION] Stack Layout: Internal code
+//-----------------------------------------------------------------------------
+
+static ImGuiLayout* FindLayout(ImGuiID id, ImGuiLayoutType type)
+{
+ IM_ASSERT(type == ImGuiLayoutType_Horizontal || type == ImGuiLayoutType_Vertical);
+
+ ImGuiLayoutWindowState* window_state = GetCurrentWindowLayoutState();
+ ImGuiLayout* layout = (ImGuiLayout*)window_state->Layouts.GetVoidPtr(id);
+ if (!layout)
+ return NULL;
+
+ if (layout->Type != type)
+ {
+ layout->Type = type;
+ layout->MinimumSize = ImVec2(0.0f, 0.0f);
+ layout->Items.clear();
+ }
+
+ return layout;
+}
+
+static ImGuiLayout* CreateNewLayout(ImGuiID id, ImGuiLayoutType type, ImVec2 size)
+{
+ IM_ASSERT(type == ImGuiLayoutType_Horizontal || type == ImGuiLayoutType_Vertical);
+
+ ImGuiLayoutWindowState* window_state = GetCurrentWindowLayoutState();
+
+ ImGuiLayout* layout = IM_NEW(ImGuiLayout)(id, type);
+ layout->Size = size;
+
+ window_state->Layouts.SetVoidPtr(id, layout);
+
+ return layout;
+}
+
+static void BeginLayout(ImGuiID id, ImGuiLayoutType type, ImVec2 size, float align)
+{
+ ImGuiContext& g = *GImGui;
+ ImGuiWindow* window = g.CurrentWindow;
+
+ if (size.x < 0.0f || size.y < 0.0f)
+ size = ImGui::CalcItemSize(size, 0.0f, 0.0f);
+
+ const int id_stack_size = window->IDStack.Size;
+ ImGui::PushOverrideID(id);
+
+ // Find or create
+ ImGuiLayout* layout = FindLayout(id, type);
+ if (!layout)
+ layout = CreateNewLayout(id, type, size);
+
+ // Each further use of the ID in a frame gets a layout of its own, as table instances do.
+ if (layout->LastFrameUsed == g.FrameCount)
+ {
+ IM_ASSERT_USER_ERROR(0, "BeginHorizontal()/BeginVertical() with an ID already used in this frame! Use PushID() to make IDs unique.");
+ const int instance_no = ++layout->InstanceCount;
+ const ImGuiID instance_id = ImHashData(&instance_no, sizeof(instance_no), id);
+ ImGuiLayout* instance = FindLayout(instance_id, type);
+ layout = instance ? instance : CreateNewLayout(instance_id, type, size);
+ }
+ else
+ {
+ layout->InstanceCount = 0;
+ }
+
+ const bool measured = (layout->LastFrameUsed == g.FrameCount - 1);
+ layout->LastFrameUsed = g.FrameCount;
+ layout->LastTimeUsed = (float)g.Time;
+ layout->IDStackSize = id_stack_size;
+ layout->GroupStackSize = g.GroupStack.Size;
+
+ PushLayout(layout);
+
+ ImGuiLayoutContextState* context_state = GetContextState(g);
+ layout->DebugFlags = context_state->NextDebugFlags | (layout->Parent ? layout->Parent->DebugFlags : ImGuiLayoutDebugFlags_None);
+ context_state->NextDebugFlags = ImGuiLayoutDebugFlags_None;
+
+ if (layout->Size.x != size.x || layout->Size.y != size.y)
+ layout->Size = size;
+
+ if (align < 0.0f)
+ layout->Align = -1.0f;
+ else
+ layout->Align = ImClamp(align, 0.0f, 1.0f);
+
+ // Start capture
+ layout->CurrentItemIndex = 0;
+
+ layout->CurrentSize.x = layout->Size.x > 0.0f ? layout->Size.x : layout->MinimumSize.x;
+ layout->CurrentSize.y = layout->Size.y > 0.0f ? layout->Size.y : layout->MinimumSize.y;
+
+ // The layout is a block starting at the cursor, like a group: save the line it is on.
+ layout->StartPos = window->DC.CursorPos;
+ layout->StartCursorMaxPos = window->DC.CursorMaxPos;
+ layout->BackupCursorPosPrevLine = window->DC.CursorPosPrevLine;
+ layout->BackupIndent = window->DC.Indent;
+ layout->BackupCurrLineSize = window->DC.CurrLineSize;
+ layout->BackupCurrLineTextBaseOffset = window->DC.CurrLineTextBaseOffset;
+ layout->BackupIsSameLine = window->DC.IsSameLine;
+ layout->BackupLayoutType = window->DC.LayoutType;
+
+ // ItemSize() flows items along the layout axis. New lines start at the layout's left edge.
+ window->DC.LayoutType = type;
+ window->DC.Indent.x = layout->StartPos.x - window->Pos.x - window->DC.ColumnsOffset.x;
+ window->DC.CurrLineSize = ImVec2(0.0f, 0.0f);
+
+ if (layout->Parent == NULL)
+ BeginLayoutWideClipRect(*layout);
+ BeginLayoutClipRect(*layout, measured);
+
+ BeginLayoutItem(*layout);
+}
+
+static void EndLayout(ImGuiLayoutWindowState* window_state)
+{
+ ImGuiLayout* layout = window_state->CurrentLayout;
+ ImGuiWindow* window = window_state->Window;
+
+ EndLayoutItem(*layout);
+
+ if (layout->CurrentItemIndex < layout->Items.Size)
+ layout->Items.resize(layout->CurrentItemIndex);
+
+ PopLayout(layout);
+
+ const bool auto_width = layout->Size.x <= 0.0f;
+ const bool auto_height = layout->Size.y <= 0.0f;
+
+ ImVec2 new_size = layout->Size;
+ if (auto_width)
+ new_size.x = layout->CurrentSize.x;
+ if (auto_height)
+ new_size.y = layout->CurrentSize.y;
+
+ ImVec2 new_minimum_size = CalculateLayoutSize(*layout, true);
+
+ if (new_minimum_size.x != layout->MinimumSize.x || new_minimum_size.y != layout->MinimumSize.y)
+ {
+ layout->MinimumSize = new_minimum_size;
+
+ // Shrink
+ if (auto_width)
+ new_size.x = new_minimum_size.x;
+ if (auto_height)
+ new_size.y = new_minimum_size.y;
+ }
+
+ if (!auto_width)
+ new_size.x = layout->Size.x;
+ if (!auto_height)
+ new_size.y = layout->Size.y;
+
+ layout->CurrentSize = new_size;
+
+ ImVec2 measured_size = new_size;
+ // Inflate to parent size only when there are springs that need the free space.
+ if ((auto_width || auto_height) && layout->Parent && HasAnyNonZeroSpring(*layout))
+ {
+ if (layout->Type == ImGuiLayoutType_Horizontal && auto_width && layout->Parent->CurrentSize.x > 0)
+ layout->CurrentSize.x = layout->Parent->CurrentSize.x;
+ else if (layout->Type == ImGuiLayoutType_Vertical && auto_height && layout->Parent->CurrentSize.y > 0)
+ layout->CurrentSize.y = layout->Parent->CurrentSize.y;
+
+ BalanceLayoutSprings(*layout);
+
+ measured_size = layout->CurrentSize;
+ }
+
+ layout->CurrentSize = new_size;
+ layout->MeasuredSize = measured_size;
+
+ IM_ASSERT_USER_ERROR(window->IDStack.Size == layout->IDStackSize + 1, "Mismatching PushID()/PopID() inside a layout!");
+ while (window->IDStack.Size > layout->IDStackSize)
+ ImGui::PopID();
+
+ EndLayoutClipRect(*layout);
+ EndLayoutWideClipRect(*layout);
+
+ // Restore the enclosing line, then submit the layout as one item, as EndGroup() does.
+ window->DC.CursorPos = layout->StartPos;
+ window->DC.CursorPosPrevLine = layout->BackupCursorPosPrevLine;
+ window->DC.CursorMaxPos = layout->StartCursorMaxPos;
+ window->DC.Indent = layout->BackupIndent;
+ window->DC.CurrLineSize = layout->BackupCurrLineSize;
+ window->DC.CurrLineTextBaseOffset = layout->BackupCurrLineTextBaseOffset;
+ window->DC.IsSameLine = layout->BackupIsSameLine;
+ window->DC.LayoutType = layout->BackupLayoutType;
+ ImGui::ItemSize(new_size);
+ // The item rect includes the inflation to the parent, which GetItemRect*() users draw with, except inside a group
+ // opened in the parent: EndGroup() would include it, feeding the parent's size back into itself.
+ const bool in_group_of_parent = layout->Parent != NULL && layout->GroupStackSize > layout->Parent->GroupStackSize;
+ ImGui::ItemAdd(ImRect(layout->StartPos, layout->StartPos + (in_group_of_parent ? new_size : measured_size)), 0);
+
+ // The parent measures this layout by the size given to ItemSize(), without the inflation in the item rect.
+ if (window_state->CurrentLayout)
+ MarkLayoutLastItem(*window_state->CurrentLayout);
+
+ if (layout->Parent == NULL)
+ {
+ BalanceChildLayouts(*layout);
+ layout->SpringSizeInTree = CalculateSpringSizeInTree(*layout);
+ }
+
+ if (layout->DebugFlags != ImGuiLayoutDebugFlags_None)
+ DebugDrawLayout(*layout);
+
+ //window->DrawList->AddRect(layout->StartPos, layout->StartPos + measured_size, IM_COL32(0,255,0,255)); // [DEBUG]
+ //window->DrawList->AddRect(window->DC.LastItemRect.Min, window->DC.LastItemRect.Max, IM_COL32(255,255,0,255)); // [DEBUG]
+}
+
+static ImVec2 CalculateLayoutSize(ImGuiLayout& layout, bool collapse_springs)
+{
+ ImVec2 bounds = ImVec2(0.0f, 0.0f);
+
+ if (layout.Type == ImGuiLayoutType_Vertical)
+ {
+ for (int i = 0; i < layout.Items.Size; i++)
+ {
+ ImGuiLayoutItem& item = layout.Items[i];
+ ImVec2 item_size = item.MeasuredBounds.GetSize();
+
+ if (item.Type == ImGuiLayoutItemType_Item)
+ {
+ bounds.x = ImMax(bounds.x, item_size.x);
+ bounds.y += item_size.y;
+ }
+ else
+ {
+ bounds.y += ImFloor(item.SpringSpacing);
+
+ if (!collapse_springs)
+ bounds.y += item.SpringSize;
+ }
+ }
+ }
+ else
+ {
+ for (int i = 0; i < layout.Items.Size; i++)
+ {
+ ImGuiLayoutItem& item = layout.Items[i];
+ ImVec2 item_size = item.MeasuredBounds.GetSize();
+
+ if (item.Type == ImGuiLayoutItemType_Item)
+ {
+ bounds.x += item_size.x;
+ bounds.y = ImMax(bounds.y, item_size.y);
+ }
+ else
+ {
+ bounds.x += ImFloor(item.SpringSpacing);
+
+ if (!collapse_springs)
+ bounds.x += item.SpringSize;
+ }
+ }
+ }
+
+ return bounds;
+}
+
+static void PushLayout(ImGuiLayout* layout)
+{
+ ImGuiLayoutWindowState* window_state = GetCurrentWindowLayoutState();
+
+ if (layout)
+ {
+ layout->Parent = window_state->CurrentLayout;
+ if (layout->Parent != NULL)
+ layout->ParentItemIndex = layout->Parent->CurrentItemIndex;
+ if (window_state->CurrentLayout)
+ {
+ layout->NextSibling = window_state->CurrentLayout->FirstChild;
+ layout->FirstChild = NULL;
+ window_state->CurrentLayout->FirstChild = layout;
+ }
+ else
+ {
+ layout->NextSibling = NULL;
+ layout->FirstChild = NULL;
+ }
+ }
+
+ window_state->LayoutStack.push_back(layout);
+ window_state->CurrentLayout = layout;
+}
+
+static void PopLayout(ImGuiLayout* layout)
+{
+ ImGuiLayoutWindowState* window_state = GetCurrentWindowLayoutState();
+
+ IM_ASSERT(!window_state->LayoutStack.empty());
+ IM_ASSERT(window_state->LayoutStack.back() == layout);
+ IM_UNUSED(layout);
+
+ window_state->LayoutStack.pop_back();
+ window_state->CurrentLayout = window_state->LayoutStack.empty() ? NULL : window_state->LayoutStack.back();
+}
+
+static void BalanceLayoutSprings(ImGuiLayout& layout)
+{
+ // Accumulate amount of occupied space and springs weights
+ float total_spring_weight = 0.0f;
+
+ int last_spring_item_index = -1;
+ for (int i = 0; i < layout.Items.Size; i++)
+ {
+ ImGuiLayoutItem& item = layout.Items[i];
+ if (item.Type == ImGuiLayoutItemType_Spring)
+ {
+ total_spring_weight += item.SpringWeight;
+ last_spring_item_index = i;
+ }
+ }
+
+ // Determine occupied space and available space depending on layout type
+ const bool is_horizontal = (layout.Type == ImGuiLayoutType_Horizontal);
+ const bool is_auto_sized = ((is_horizontal ? layout.Size.x : layout.Size.y) <= 0.0f) && (layout.Parent == NULL);
+ const float occupied_space = is_horizontal ? layout.MinimumSize.x : layout.MinimumSize.y;
+ const float available_space = is_auto_sized ? occupied_space : (is_horizontal ? layout.CurrentSize.x : layout.CurrentSize.y);
+ const float free_space = ImMax(available_space - occupied_space, 0.0f);
+
+ // Springs that change size move the items after them, to avoid one frame visual bugs. Offsets accumulate, so each
+ // item is translated once.
+ ImVec2 offset = ImVec2(0.0f, 0.0f);
+ float span_start = 0.0f;
+ float current_weight = 0.0f;
+ for (int i = 0; i < layout.Items.Size; i++)
+ {
+ ImGuiLayoutItem& item = layout.Items[i];
+ if (item.Type != ImGuiLayoutItemType_Spring)
+ {
+ if (offset.x != 0.0f || offset.y != 0.0f)
+ {
+ TranslateLayoutItem(item, offset);
+ item.MeasuredBounds.Min += offset;
+ item.MeasuredBounds.Max += offset;
+ }
+ continue;
+ }
+
+ float last_spring_size = item.SpringSize;
+
+ if (free_space > 0.0f && total_spring_weight > 0.0f)
+ {
+ float next_weight = current_weight + item.SpringWeight;
+ float span_end = ImFloor((i == last_spring_item_index) ? free_space : (free_space * next_weight / total_spring_weight));
+ float spring_size = span_end - span_start;
+ item.SpringSize = spring_size;
+ span_start = span_end;
+ current_weight = next_weight;
+ }
+ else
+ {
+ item.SpringSize = 0.0f;
+ }
+
+ item.MeasuredBounds.Min += offset;
+ item.MeasuredBounds.Max += offset;
+ if (last_spring_size != item.SpringSize)
+ {
+ float difference = item.SpringSize - last_spring_size;
+ ImVec2 spring_offset = is_horizontal ? ImVec2(difference, 0.0f) : ImVec2(0.0f, difference);
+ item.MeasuredBounds.Max += spring_offset;
+ offset += spring_offset;
+ }
+ }
+}
+
+static ImVec2 BalanceLayoutItemAlignment(ImGuiLayout& layout, ImGuiLayoutItem& item)
+{
+ // Fixup item alignment if necessary.
+ ImVec2 position_correction = ImVec2(0.0f, 0.0f);
+ if (item.CurrentAlign > 0.0f)
+ {
+ float item_align_offset = CalculateLayoutItemAlignmentOffset(layout, item);
+ if (item.CurrentAlignOffset != item_align_offset)
+ {
+ float offset = item_align_offset - item.CurrentAlignOffset;
+
+ if (layout.Type == ImGuiLayoutType_Horizontal)
+ position_correction.y = offset;
+ else
+ position_correction.x = offset;
+
+ TranslateLayoutItem(item, position_correction);
+
+ item.CurrentAlignOffset = item_align_offset;
+ }
+ }
+
+ return position_correction;
+}
+
+static void BalanceLayoutItemsAlignment(ImGuiLayout& layout)
+{
+ for (int i = 0; i < layout.Items.Size; ++i)
+ {
+ ImGuiLayoutItem& item = layout.Items[i];
+ BalanceLayoutItemAlignment(layout, item);
+ }
+}
+
+static bool HasAnyNonZeroSpring(ImGuiLayout& layout)
+{
+ for (int i = 0; i < layout.Items.Size; ++i)
+ {
+ ImGuiLayoutItem& item = layout.Items[i];
+ if (item.Type != ImGuiLayoutItemType_Spring)
+ continue;
+ if (item.SpringWeight > 0)
+ return true;
+ }
+ return false;
+}
+
+static void BalanceChildLayouts(ImGuiLayout& layout)
+{
+ for (ImGuiLayout* child = layout.FirstChild; child != NULL; child = child->NextSibling)
+ {
+ //ImVec2 child_layout_size = child->CurrentSize;
+
+ // Propagate layout size down to child layouts.
+ //
+ // TODO: Distribution assume inner layout is only
+ // element inside parent item and assigns
+ // all available space to it.
+ //
+ // Investigate how to split space between
+ // adjacent layouts.
+ //
+ // Investigate how to measure non-layout items
+ // to treat them as fixed size blocks.
+ //
+ if (child->Type == ImGuiLayoutType_Horizontal && child->Size.x <= 0.0f)
+ child->CurrentSize.x = layout.CurrentSize.x;
+ else if (child->Type == ImGuiLayoutType_Vertical && child->Size.y <= 0.0f)
+ child->CurrentSize.y = layout.CurrentSize.y;
+
+ BalanceChildLayouts(*child);
+
+ //child->CurrentSize = child_layout_size;
+
+ if (HasAnyNonZeroSpring(*child))
+ {
+ // Expand item measured bounds to make alignment correct.
+ ImGuiLayoutItem& item = layout.Items[child->ParentItemIndex];
+
+ if (child->Type == ImGuiLayoutType_Horizontal && child->Size.x <= 0.0f)
+ item.MeasuredBounds.Max.x = ImMax(item.MeasuredBounds.Max.x, item.MeasuredBounds.Min.x + layout.CurrentSize.x);
+ else if (child->Type == ImGuiLayoutType_Vertical && child->Size.y <= 0.0f)
+ item.MeasuredBounds.Max.y = ImMax(item.MeasuredBounds.Max.y, item.MeasuredBounds.Min.y + layout.CurrentSize.y);
+ }
+ }
+
+ BalanceLayoutSprings(layout);
+ BalanceLayoutItemsAlignment(layout);
+}
+
+// Only fixed-size axes clip, and only when the contents measured in the previous frame overflow them.
+static void BeginLayoutClipRect(ImGuiLayout& layout, bool measured)
+{
+ const bool clip_x = layout.Size.x > 0.0f && (!measured || layout.MinimumSize.x > layout.Size.x);
+ const bool clip_y = layout.Size.y > 0.0f && (!measured || layout.MinimumSize.y > layout.Size.y);
+ layout.ClipRectPushed = clip_x || clip_y;
+ if (!layout.ClipRectPushed)
+ return;
+
+ ImVec2 clip_rect_min(clip_x ? layout.StartPos.x : -FLT_MAX, clip_y ? layout.StartPos.y : -FLT_MAX);
+ ImVec2 clip_rect_max(clip_x ? layout.StartPos.x + layout.Size.x : FLT_MAX, clip_y ? layout.StartPos.y + layout.Size.y : FLT_MAX);
+ ImGui::PushClipRect(clip_rect_min, clip_rect_max, true);
+}
+
+static void EndLayoutClipRect(ImGuiLayout& layout)
+{
+ if (layout.ClipRectPushed)
+ ImGui::PopClipRect();
+}
+
+// Until the root layout corrects them, items can land too far by up to the spring sizes of the tree in the previous
+// frame. The clip rect is widened by that much toward the far side meanwhile, so that ItemAdd() and text rendering do
+// not cull them. Not toward the near side: hover tests use it too, and items scrolled under the title bar would take
+// its clicks.
+static void BeginLayoutWideClipRect(ImGuiLayout& layout)
+{
+ layout.WideClipRectPushed = layout.SpringSizeInTree.x > 0.0f || layout.SpringSizeInTree.y > 0.0f;
+ if (!layout.WideClipRectPushed)
+ return;
+
+ ImDrawList* draw_list = ImGui::GetWindowDrawList();
+ const ImVec2 margin = layout.SpringSizeInTree;
+ layout.NarrowClipRect = draw_list->_CmdHeader.ClipRect;
+ ImGui::PushClipRect(ImVec2(layout.NarrowClipRect.x, layout.NarrowClipRect.y), ImVec2(layout.NarrowClipRect.z + margin.x, layout.NarrowClipRect.w + margin.y), false);
+ layout.WideClipRect = draw_list->_CmdHeader.ClipRect;
+ layout.WideClipRectCmdIndex = draw_list->CmdBuffer.Size - 1;
+}
+
+// Commands drawn under the wide clip rect get the original one back, then merge where it made them split.
+static void EndLayoutWideClipRect(ImGuiLayout& layout)
+{
+ if (!layout.WideClipRectPushed)
+ return;
+ ImGui::PopClipRect();
+
+ ImDrawList* draw_list = ImGui::GetWindowDrawList();
+ const ImVec4 wide = layout.WideClipRect;
+ const ImVec4 narrow = layout.NarrowClipRect;
+ for (int n = layout.WideClipRectCmdIndex; n < draw_list->CmdBuffer.Size; n++)
+ {
+ // Clip rects pushed without intersecting (e.g. full screen ones) are not inside the wide one: they stay.
+ ImVec4& clip_rect = draw_list->CmdBuffer[n].ClipRect;
+ if (clip_rect.x < wide.x || clip_rect.y < wide.y || clip_rect.z > wide.z || clip_rect.w > wide.w)
+ continue;
+ clip_rect.x = ImClamp(clip_rect.x, narrow.x, narrow.z);
+ clip_rect.y = ImClamp(clip_rect.y, narrow.y, narrow.w);
+ clip_rect.z = ImClamp(clip_rect.z, clip_rect.x, narrow.z);
+ clip_rect.w = ImClamp(clip_rect.w, clip_rect.y, narrow.w);
+ }
+
+ // Same header comparison as ImDrawList::_TryMergeDrawCmds(): clip rect, texture and vertex offset.
+ const size_t header_size = offsetof(ImDrawCmd, VtxOffset) + sizeof(unsigned int);
+ int dst = ImMax(layout.WideClipRectCmdIndex - 1, 0);
+ for (int src = dst + 1; src < draw_list->CmdBuffer.Size; src++)
+ {
+ ImDrawCmd& prev_cmd = draw_list->CmdBuffer[dst];
+ ImDrawCmd& cmd = draw_list->CmdBuffer[src];
+ if (memcmp(&prev_cmd, &cmd, header_size) == 0 && prev_cmd.IdxOffset + prev_cmd.ElemCount == cmd.IdxOffset && prev_cmd.UserCallback == NULL && cmd.UserCallback == NULL)
+ prev_cmd.ElemCount += cmd.ElemCount;
+ else
+ draw_list->CmdBuffer[++dst] = cmd;
+ }
+ draw_list->CmdBuffer.resize(dst + 1);
+}
+
+static ImVec2 CalculateSpringSizeInTree(const ImGuiLayout& layout)
+{
+ ImVec2 size(0.0f, 0.0f);
+ const int axis = (layout.Type == ImGuiLayoutType_Horizontal) ? 0 : 1;
+ for (const ImGuiLayoutItem& item : layout.Items)
+ if (item.Type == ImGuiLayoutItemType_Spring)
+ size[axis] += item.SpringSize;
+ for (const ImGuiLayout* child = layout.FirstChild; child != NULL; child = child->NextSibling)
+ size += CalculateSpringSizeInTree(*child);
+ return size;
+}
+
+static ImGuiLayoutItem* GenerateLayoutItem(ImGuiLayout& layout, ImGuiLayoutItemType type)
+{
+ IM_ASSERT(layout.CurrentItemIndex <= layout.Items.Size);
+
+ if (layout.CurrentItemIndex < layout.Items.Size)
+ {
+ ImGuiLayoutItem& item = layout.Items[layout.CurrentItemIndex];
+ if (item.Type != type)
+ item = ImGuiLayoutItem(type);
+ }
+ else
+ {
+ layout.Items.push_back(ImGuiLayoutItem(type));
+ }
+
+ return &layout.Items[layout.CurrentItemIndex];
+}
+
+// Calculate how many pixels from top/left layout edge item need to be moved to match
+// layout alignment.
+static float CalculateLayoutItemAlignmentOffset(ImGuiLayout& layout, ImGuiLayoutItem& item)
+{
+ if (item.CurrentAlign <= 0.0f)
+ return 0.0f;
+
+ ImVec2 item_size = item.MeasuredBounds.GetSize();
+
+ float layout_extent = (layout.Type == ImGuiLayoutType_Horizontal) ? layout.CurrentSize.y : layout.CurrentSize.x;
+ float item_extent = (layout.Type == ImGuiLayoutType_Horizontal) ? item_size.y : item_size.x;
+
+ if (item_extent <= 0/* || layout_extent <= item_extent*/)
+ return 0.0f;
+
+ float align_offset = ImFloor(item.CurrentAlign * (layout_extent - item_extent));
+
+ return align_offset;
+}
+
+static void TranslateLayoutItem(ImGuiLayoutItem& item, const ImVec2& offset)
+{
+ if ((offset.x == 0.0f && offset.y == 0.0f) || (item.VertexIndexBegin == item.VertexIndexEnd))
+ return;
+
+ //IMGUI_DEBUG_LOG("TranslateLayoutItem by %f,%f\n", offset.x, offset.y);
+ ImDrawList* draw_list = ImGui::GetWindowDrawList();
+
+ ImDrawVert* begin = draw_list->VtxBuffer.Data + item.VertexIndexBegin;
+ ImDrawVert* end = draw_list->VtxBuffer.Data + item.VertexIndexEnd;
+
+ for (ImDrawVert* vtx = begin; vtx < end; ++vtx)
+ {
+ vtx->pos.x += offset.x;
+ vtx->pos.y += offset.y;
+ }
+}
+
+static void SignedIndent(float indent)
+{
+ if (indent > 0.0f)
+ ImGui::Indent(indent);
+ else if (indent < 0.0f)
+ ImGui::Unindent(-indent);
+}
+
+// EndLayoutItem() includes the last item rect only if an item was submitted after this.
+static void MarkLayoutLastItem(ImGuiLayout& layout)
+{
+ ImGuiContext& g = *GImGui;
+ layout.ItemBeginLastItemId = g.LastItemData.ID;
+ layout.ItemBeginLastItemRect = g.LastItemData.Rect;
+}
+
+static void BeginLayoutItem(ImGuiLayout& layout)
+{
+ ImGuiContext& g = *GImGui;
+ ImGuiWindow* window = g.CurrentWindow;
+ ImGuiLayoutItem& item = *GenerateLayoutItem(layout, ImGuiLayoutItemType_Item);
+
+ item.CurrentAlign = layout.Align;
+ if (item.CurrentAlign < 0.0f)
+ item.CurrentAlign = ImClamp(g.Style.LayoutAlign, 0.0f, 1.0f);
+
+ // Align item according to data from previous frame.
+ // If layout changes in current frame alignment will
+ // be corrected in EndLayout() to it visualy coherent.
+ item.CurrentAlignOffset = CalculateLayoutItemAlignmentOffset(layout, item);
+ if (layout.Type == ImGuiLayoutType_Horizontal)
+ {
+ window->DC.CursorPos.y = layout.StartPos.y + item.CurrentAlignOffset;
+ }
+ else if (item.CurrentAlign > 0.0f)
+ {
+ float new_position = window->DC.CursorPos.x + item.CurrentAlignOffset;
+
+ // Make placement behave like in horizontal case when next
+ // widget is placed at very same Y position. This indent
+ // make sure for vertical layout placed widgets has same X position.
+ SignedIndent(item.CurrentAlignOffset);
+
+ window->DC.CursorPos.x = new_position;
+ }
+
+ // Each item starts its own line and is measured like a group, from what its contents extend CursorMaxPos to.
+ window->DC.CurrLineSize = ImVec2(0.0f, 0.0f);
+ window->DC.IsSameLine = false;
+ window->DC.CursorMaxPos = window->DC.CursorPos;
+ MarkLayoutLastItem(layout);
+
+ item.MeasuredBounds.Min = item.MeasuredBounds.Max = window->DC.CursorPos;
+ item.VertexIndexBegin = item.VertexIndexEnd = window->DrawList->VtxBuffer.Size;
+}
+
+static void EndLayoutItem(ImGuiLayout& layout)
+{
+ ImGuiContext& g = *GImGui;
+ ImGuiWindow* window = g.CurrentWindow;
+ IM_ASSERT(layout.CurrentItemIndex < layout.Items.Size);
+
+ ImGuiLayoutItem& item = layout.Items[layout.CurrentItemIndex];
+
+ // Like EndGroup(), include the last item submitted inside, for e.g. EndTable() undershooting with CursorMaxPos.
+ item.MeasuredBounds.Max = ImMax(item.MeasuredBounds.Max, window->DC.CursorMaxPos);
+ if (g.LastItemData.ID != layout.ItemBeginLastItemId || memcmp(&g.LastItemData.Rect, &layout.ItemBeginLastItemRect, sizeof(ImRect)) != 0)
+ item.MeasuredBounds.Max = ImMax(item.MeasuredBounds.Max, g.LastItemData.Rect.Max);
+
+ ImDrawList* draw_list = window->DrawList;
+ item.VertexIndexEnd = draw_list->VtxBuffer.Size;
+
+ if (item.CurrentAlign > 0.0f && layout.Type == ImGuiLayoutType_Vertical)
+ SignedIndent(-item.CurrentAlignOffset);
+
+ // Fixup item alignment in case item size changed in current frame.
+ ImVec2 position_correction = BalanceLayoutItemAlignment(layout, item);
+
+ item.MeasuredBounds.Min += position_correction;
+ item.MeasuredBounds.Max += position_correction;
+
+ if (layout.Type == ImGuiLayoutType_Horizontal)
+ window->DC.CursorPos.y = layout.StartPos.y;
+ else
+ window->DC.CursorPos.x = layout.StartPos.x;
+
+ layout.CurrentItemIndex++;
+}
+
+static void AddLayoutSpring(ImGuiLayout& layout, float weight, float spacing)
+{
+ ImGuiContext& g = *GImGui;
+ ImGuiWindow* window = g.CurrentWindow;
+
+ EndLayoutItem(layout);
+
+ // Undo item padding, spring should consume all space between items.
+ ImGuiLayoutItem* previous_item = &layout.Items[layout.CurrentItemIndex - 1];
+ if (layout.Type == ImGuiLayoutType_Horizontal)
+ window->DC.CursorPos.x = previous_item->MeasuredBounds.Max.x;
+ else
+ window->DC.CursorPos.y = previous_item->MeasuredBounds.Max.y;
+ window->DC.IsSameLine = false;
+
+ previous_item = NULL; // may be invalid after call to GenerateLayoutItem()
+
+ ImGuiLayoutItem* spring_item = GenerateLayoutItem(layout, ImGuiLayoutItemType_Spring);
+
+ spring_item->MeasuredBounds.Min = spring_item->MeasuredBounds.Max = window->DC.CursorPos;
+
+ if (weight < 0.0f)
+ weight = 0.0f;
+
+ if (spring_item->SpringWeight != weight)
+ spring_item->SpringWeight = weight;
+
+ if (spacing < 0.0f)
+ {
+ ImVec2 style_spacing = g.Style.ItemSpacing;
+ if (layout.Type == ImGuiLayoutType_Horizontal)
+ spacing = style_spacing.x;
+ else
+ spacing = style_spacing.y;
+ }
+
+ if (spring_item->SpringSpacing != spacing)
+ spring_item->SpringSpacing = spacing;
+
+ // Submitted even when empty, so that GetItemRect*() and IsItem*() after Spring() refer to the spring.
+ ImVec2 spring_size, spring_spacing;
+ if (layout.Type == ImGuiLayoutType_Horizontal)
+ {
+ spring_spacing = ImVec2(0.0f, g.Style.ItemSpacing.y);
+ spring_size = ImVec2(spacing + spring_item->SpringSize, layout.CurrentSize.y);
+ }
+ else
+ {
+ spring_spacing = ImVec2(g.Style.ItemSpacing.x, 0.0f);
+ spring_size = ImVec2(layout.CurrentSize.x, spacing + spring_item->SpringSize);
+ }
+
+ ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImFloor(spring_spacing));
+ ImGui::Dummy(ImFloor(spring_size));
+ ImGui::PopStyleVar();
+
+ spring_item->MeasuredBounds.Max = spring_item->MeasuredBounds.Min + ImFloor(spring_size);
+
+ layout.CurrentItemIndex++;
+
+ BeginLayoutItem(layout);
+}
+
+static void DebugDrawLayout(const ImGuiLayout& layout)
+{
+ ImDrawList* draw_list = ImGui::GetWindowDrawList();
+ const int axis = (layout.Type == ImGuiLayoutType_Horizontal) ? 0 : 1;
+ const ImRect layout_rect(layout.StartPos, layout.StartPos + layout.MeasuredSize);
+ for (const ImGuiLayoutItem& item : layout.Items)
+ {
+ if (item.Type == ImGuiLayoutItemType_Item)
+ {
+ if (layout.DebugFlags & ImGuiLayoutDebugFlags_DrawItems)
+ draw_list->AddRect(item.MeasuredBounds.Min, item.MeasuredBounds.Max, IM_COL32(255, 255, 0, 160));
+ continue;
+ }
+ if ((layout.DebugFlags & ImGuiLayoutDebugFlags_DrawSprings) == 0)
+ continue;
+
+ // Along the layout: the spring, then its spacing. Across it: the whole layout.
+ ImRect rect = item.MeasuredBounds;
+ rect.Min[axis ^ 1] = layout_rect.Min[axis ^ 1];
+ rect.Max[axis ^ 1] = layout_rect.Max[axis ^ 1];
+ const float length = rect.Max[axis] - rect.Min[axis];
+ if (length <= 0.0f)
+ continue;
+ const float spacing = ImMin(ImFloor(item.SpringSpacing), length);
+ ImRect spring_rect = rect, spacing_rect = rect;
+ spring_rect.Max[axis] = spacing_rect.Min[axis] = rect.Max[axis] - spacing;
+
+ draw_list->PushClipRect(rect.Min, rect.Max, true);
+ draw_list->AddRectFilled(spring_rect.Min, spring_rect.Max, IM_COL32(80, 20, 80, 255));
+ draw_list->AddRectFilled(spacing_rect.Min, spacing_rect.Max, IM_COL32(80, 20, 20, 255));
+
+ // Zig-zag along the middle of the spring.
+ const float zig_zag_size = 3.0f;
+ ImVec2 direction(0.0f, 0.0f);
+ direction[axis] = 1.0f;
+ ImVec2 normal(-direction.y, direction.x);
+ ImVec2 origin = ImFloor(rect.GetCenter());
+ origin[axis] = ImFloor(rect.Min[axis]);
+ origin += ImVec2(0.5f, 0.5f);
+ draw_list->PathLineTo(origin);
+ for (float x = zig_zag_size * 0.5f; x <= length - spacing; x += zig_zag_size)
+ {
+ draw_list->PathLineTo(origin + direction * x + normal * zig_zag_size);
+ normal = -normal;
+ }
+ draw_list->PathStroke(IM_COL32(255, 255, 255, 190), 1.0f);
+ draw_list->PopClipRect();
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// [SECTION] Stack Layout: Internal API
+//-----------------------------------------------------------------------------
+
+void ErrorRecoveryTryToRecoverWindowState(const ImGuiErrorRecoveryState* state_in)
+{
+ // Called for every window, so it creates no state.
+ ImGuiContext& g = *GImGui;
+ ImGuiLayoutContextState* context_state = FindContextState(g);
+ ImGuiLayoutWindowState* state = context_state ? (ImGuiLayoutWindowState*)context_state->WindowStates.GetVoidPtr(g.CurrentWindow->ID) : NULL;
+ if (state == NULL)
+ return;
+
+ // Layouts and suspensions each push onto the ID stack: those begun after state_in was stored are above its size.
+ while (state->LayoutStack.Size > 0) //-V1044
+ {
+ if (state->CurrentLayout == NULL)
+ {
+ if (state->SuspendStack.back().IDStackSize < state_in->SizeOfIDStack)
+ break;
+ IM_ASSERT_USER_ERROR(0, "Missing ResumeLayout()");
+ ImGui::ResumeLayout();
+ }
+ else
+ {
+ if (state->CurrentLayout->IDStackSize < state_in->SizeOfIDStack)
+ break;
+ if (state->CurrentLayout->Type == ImGuiLayoutType_Horizontal)
+ {
+ IM_ASSERT_USER_ERROR(0, "Missing EndHorizontal()");
+ ImGui::EndHorizontal();
+ }
+ else
+ {
+ IM_ASSERT_USER_ERROR(0, "Missing EndVertical()");
+ ImGui::EndVertical();
+ }
+ }
+ }
+}
+
+
+} // namespace ImGuiStackLayout
+
+//-----------------------------------------------------------------------------
+// [SECTION] Stack Layout: Public API
+//-----------------------------------------------------------------------------
+
+void ImGui::BeginHorizontal(const char* str_id, const ImVec2& size/* = ImVec2(0, 0)*/, float align/* = -1*/)
+{
+ ImGuiWindow* window = GetCurrentWindow();
+ ImGuiStackLayout::BeginLayout(window->GetID(str_id), ImGuiLayoutType_Horizontal, size, align);
+}
+
+void ImGui::BeginHorizontal(const void* ptr_id, const ImVec2& size/* = ImVec2(0, 0)*/, float align/* = -1*/)
+{
+ ImGuiWindow* window = GetCurrentWindow();
+ ImGuiStackLayout::BeginLayout(window->GetID(ptr_id), ImGuiLayoutType_Horizontal, size, align);
+}
+
+void ImGui::BeginHorizontal(int id, const ImVec2& size/* = ImVec2(0, 0)*/, float align/* = -1*/)
+{
+ ImGuiWindow* window = GetCurrentWindow();
+ ImGuiStackLayout::BeginLayout(window->GetID(id), ImGuiLayoutType_Horizontal, size, align);
+}
+
+void ImGui::EndHorizontal()
+{
+ ImGuiStackLayout::ImGuiLayoutWindowState* window_state = ImGuiStackLayout::GetCurrentWindowLayoutState();
+ IM_ASSERT_USER_ERROR_RET(window_state->CurrentLayout != NULL || window_state->LayoutStack.Size == 0, "Calling EndHorizontal() between SuspendLayout() and ResumeLayout()!");
+ IM_ASSERT_USER_ERROR_RET(window_state->CurrentLayout != NULL, "Calling EndHorizontal() too many times!");
+ IM_ASSERT_USER_ERROR(window_state->CurrentLayout->Type == ImGuiLayoutType_Horizontal, "Calling EndHorizontal() to end a vertical layout!");
+ ImGuiStackLayout::EndLayout(window_state);
+}
+
+void ImGui::BeginVertical(const char* str_id, const ImVec2& size/* = ImVec2(0, 0)*/, float align/* = -1*/)
+{
+ ImGuiWindow* window = GetCurrentWindow();
+ ImGuiStackLayout::BeginLayout(window->GetID(str_id), ImGuiLayoutType_Vertical, size, align);
+}
+
+void ImGui::BeginVertical(const void* ptr_id, const ImVec2& size/* = ImVec2(0, 0)*/, float align/* = -1*/)
+{
+ ImGuiWindow* window = GetCurrentWindow();
+ ImGuiStackLayout::BeginLayout(window->GetID(ptr_id), ImGuiLayoutType_Vertical, size, align);
+}
+
+void ImGui::BeginVertical(int id, const ImVec2& size/* = ImVec2(0, 0)*/, float align/* = -1*/)
+{
+ ImGuiWindow* window = GetCurrentWindow();
+ ImGuiStackLayout::BeginLayout(window->GetID(id), ImGuiLayoutType_Vertical, size, align);
+}
+
+void ImGui::EndVertical()
+{
+ ImGuiStackLayout::ImGuiLayoutWindowState* window_state = ImGuiStackLayout::GetCurrentWindowLayoutState();
+ IM_ASSERT_USER_ERROR_RET(window_state->CurrentLayout != NULL || window_state->LayoutStack.Size == 0, "Calling EndVertical() between SuspendLayout() and ResumeLayout()!");
+ IM_ASSERT_USER_ERROR_RET(window_state->CurrentLayout != NULL, "Calling EndVertical() too many times!");
+ IM_ASSERT_USER_ERROR(window_state->CurrentLayout->Type == ImGuiLayoutType_Vertical, "Calling EndVertical() to end a horizontal layout!");
+ ImGuiStackLayout::EndLayout(window_state);
+}
+
+// Inserts spring separator in layout
+// weight <= 0 : spring will always have zero size
+// weight > 0 : power of current spring
+// spacing < 0 : use default spacing if pos_x == 0, no spacing if pos_x != 0
+// spacing >= 0 : enforce spacing amount
+void ImGui::Spring(float weight/* = 1.0f*/, float spacing/* = -1.0f*/)
+{
+ ImGuiStackLayout::ImGuiLayoutWindowState* window_state = ImGuiStackLayout::GetCurrentWindowLayoutState();
+ IM_ASSERT_USER_ERROR_RET(window_state->CurrentLayout != NULL, "Calling Spring() outside of a layout, or between SuspendLayout() and ResumeLayout()!");
+
+ ImGuiStackLayout::AddLayoutSpring(*window_state->CurrentLayout, weight, spacing);
+}
+
+void ImGui::SuspendLayout()
+{
+ ImGuiWindow* window = GetCurrentWindow();
+ ImGuiStackLayout::ImGuiLayoutWindowState* window_state = ImGuiStackLayout::GetCurrentWindowLayoutState();
+
+ // Items in between flow as they would outside of the outermost layout, and are not measured by the layout.
+ // Pushing the current ID again leaves item IDs unchanged, and orders the suspension for error recovery.
+ ImGuiStackLayout::ImGuiLayoutSuspendBackup backup;
+ backup.LayoutType = window->DC.LayoutType;
+ backup.CursorMaxPos = window->DC.CursorMaxPos;
+ backup.IDStackSize = window->IDStack.Size;
+ window_state->SuspendStack.push_back(backup);
+ PushOverrideID(window->IDStack.back());
+ for (ImGuiStackLayout::ImGuiLayout* layout : window_state->LayoutStack)
+ {
+ if (layout != NULL)
+ {
+ window->DC.LayoutType = layout->BackupLayoutType;
+ break;
+ }
+ }
+
+ ImGuiStackLayout::PushLayout(NULL);
+}
+
+void ImGui::ResumeLayout()
+{
+ ImGuiWindow* window = GetCurrentWindow();
+ ImGuiStackLayout::ImGuiLayoutWindowState* window_state = ImGuiStackLayout::GetCurrentWindowLayoutState();
+ IM_ASSERT_USER_ERROR_RET(window_state->SuspendStack.Size > 0, "Calling ResumeLayout() without SuspendLayout()!");
+ IM_ASSERT_USER_ERROR_RET(window_state->CurrentLayout == NULL, "Missing EndHorizontal() or EndVertical() before ResumeLayout()!");
+ ImGuiStackLayout::PopLayout(NULL);
+
+ const ImGuiStackLayout::ImGuiLayoutSuspendBackup& backup = window_state->SuspendStack.back();
+ IM_ASSERT_USER_ERROR(window->IDStack.Size == backup.IDStackSize + 1, "Mismatching PushID()/PopID() between SuspendLayout() and ResumeLayout()!");
+ while (window->IDStack.Size > backup.IDStackSize)
+ PopID();
+ window->DC.LayoutType = backup.LayoutType;
+ window->DC.CursorMaxPos = backup.CursorMaxPos;
+ window_state->SuspendStack.pop_back();
+ if (window_state->CurrentLayout)
+ ImGuiStackLayout::MarkLayoutLastItem(*window_state->CurrentLayout);
+}
+
+void ImGui::SetNextLayoutDebugFlags(ImGuiLayoutDebugFlags flags)
+{
+ ImGuiStackLayout::GetContextState(*GImGui)->NextDebugFlags = flags;
+}
+
+//-----------------------------------------------------------------------------
+
+#endif // #ifndef IMGUI_DISABLE
diff --git a/imgui_stacklayout.h b/imgui_stacklayout.h
new file mode 100644
index 000000000..61f57e925
--- /dev/null
+++ b/imgui_stacklayout.h
@@ -0,0 +1,193 @@
+// dear imgui: stack layouts
+// (stack layout headers)
+
+/*
+
+Index of this file:
+// [SECTION] Stack Layout API
+
+*/
+
+/*
+
+CHANGELOG
+=========
+
+-----------------------------------------------------------------------
+ 2026/10/17 (Stack Layout v2.2, Dear ImGui 1.93.0)
+-----------------------------------------------------------------------
+
+Breaking Changes:
+
+- Layout: sizes follow CalcItemSize(): negative values are relative to the far edge of the content
+ region (-FLT_MIN fills it). They used to mean automatic, like 0.0f.
+- Layout: items flow with Dear ImGui's own layout type (window->DC.LayoutType), as in menu bars,
+ and layouts measure their items like groups. ItemSize() and ItemAdd() no longer call into
+ stack layouts. Inside horizontal layouts, Separator() draws a vertical separator,
+ MenuItem()/BeginMenu() render as in a menu bar, and NewLine() starts a new row.
+
+Other Changes:
+
+- Layout: fixed SameLine() inside horizontal layouts placing the next item over the previous
+ one. Widgets calling SameLine() (DragFloat3(), InputInt(), ColorEdit3(), ...) collapsed.
+- Layout: fixed BeginVertical() after SameLine() moving its contents down by the height of the
+ previous line, where the layout clip rect hid them.
+- Layout: fixed ImGuiListClipper inside BeginVertical() collapsing the scroll range of the
+ window: items are measured by how far they move the cursor, as in groups.
+- Layout: fixed tables without scrolling inside horizontal layouts laying out their cells
+ horizontally. This needs the fix to BeginTable() submitted to Dear ImGui with this release.
+- Layout: fixed a crash ending a layout begun while its parent was suspended, and on nested
+ SuspendLayout() calls.
+- Clipping: layouts no longer split draw commands into channels or clamp them to their measured
+ size. Fixed the nav cursor, outlines and other decorations drawn around items at the edge of a
+ layout being cut, draw calls no longer batching across layouts, and content moved by the root
+ layout being clipped for one frame. Fixed-size axes still clip contents that overflow them.
+- Nested layouts: fixed an automatic parent never shrinking when a nested layout with springs is
+ wrapped in BeginGroup()/EndGroup(). Inside such a group, the item rect of the nested layout
+ (GetItemRectMin()/GetItemRectMax() after EndHorizontal()/EndVertical()) is its own size rather
+ than the size it grows to in the parent.
+- Layout: items outside of stack layouts no longer cost a lookup of the layout state.
+- Context: layout state is kept per context and per window, instead of in a process-global map.
+ Fixed crashes and hooks piling up with one context per thread (thread-local GImGui), and
+ modules sharing a context (plugin DLLs, hot reload) each keeping their own layout state.
+- Context: the module that submits the first layout of a context registers its hooks. Keep it
+ loaded as long as the context lives.
+- Context: fixed layout state for IDs from changing data never being freed. Layouts unused for
+ io.ConfigMemoryCompactTimer are freed, as windows and tables are, and so are all layouts of a
+ window whose memory is compacted.
+- Context: fixed an allocation outliving DestroyContext().
+- Error Handling: layouts left open at the end of the frame while error recovery is disabled are
+ reported and discarded at the next frame.
+- Error Handling: fixed the same layout ID used twice in a frame hanging builds without asserts.
+ It is reported, and each further use gets a layout state of its own, as table instances do.
+- Error Handling: fixed ErrorRecoveryTryToRecoverState() closing layouts begun before
+ ErrorRecoveryStoreState(). SuspendLayout() pushes the current ID again, which leaves item IDs
+ unchanged and orders suspensions for recovery.
+- Error Handling: misuse is reported and recovered instead of asserting, then crashing:
+ Spring() outside of a layout, EndHorizontal()/EndVertical() without a layout, while suspended
+ or on the other type of layout, and ResumeLayout() without SuspendLayout().
+- Error Handling: unbalanced PushID()/PopID() inside a layout or a suspension is reported, and
+ the ID stack is restored when the layout ends or resumes.
+- Springs: corrections made within the frame translate the vertices of each item once, instead of
+ once per spring that changed size.
+- Springs: Spring() always submits an item, so GetItemRect*() and IsItem*() after it refer to the
+ spring. A spring with no size and no spacing used to leave the previous item there.
+- Springs: fixed items after an item that appears missing parts (e.g. their text) for one frame:
+ placed with the previous frame's spring sizes, they were culled outside of the clip rect before
+ the root layout moved them into view.
+- Debug: added SetNextLayoutDebugFlags() with ImGuiLayoutDebugFlags_DrawSprings and
+ ImGuiLayoutDebugFlags_DrawItems: the layout draws its springs or items where it placed them.
+- Docs: the ID scope of layouts is documented with BeginHorizontal()/BeginVertical(), with how to
+ open a popup inside a layout and begin it outside.
+- Examples: added imgui_stacklayout.cpp to the example projects (Visual Studio, Makefiles,
+ CMake, Xcode, QNX), which did not link without it.
+- Misc: added imgui_stacklayout.cpp to misc/single_file/imgui_single_file.h, so single-file
+ (unity) builds link.
+- CI: the test suite jobs add imgui_stacklayout.cpp to the project files of imgui_test_suite,
+ which do not list it.
+- Demo: added style.LayoutAlign to the style editor.
+- Demo: springs are drawn with ImGuiLayoutDebugFlags_DrawSprings. The demo drew them from
+ GetItemRect*() after Spring(), which held the previous item when a spring submitted none, and
+ sizes from the previous frame.
+- Misc: added IMGUI_STACK_LAYOUT_VERSION and IMGUI_STACK_LAYOUT_VERSION_NUM.
+- Misc: the headers of the stack layout files no longer quote a Dear ImGui version.
+- Misc: imgui_stacklayout.cpp ignores the same Clang/GCC warnings as Dear ImGui's sources. Builds
+ with -Weverything or -Wsign-conversion reported old-style casts, float comparisons and sign
+ conversions in it.
+- Internals: moved internal types and functions to namespace ImGuiStackLayout. They were in
+ the global and ImGui namespaces, where same-named user code or future Dear ImGui code clash.
+
+-----------------------------------------------------------------------
+ 2026/10/11 (Stack Layout v2.1, Dear ImGui 1.93.0 WIP)
+-----------------------------------------------------------------------
+
+Breaking Changes:
+
+- IDs: BeginHorizontal()/BeginVertical() scope their contents like PushID() with the same
+ identifier, as BeginTable() and TreeNode() do. Contents were already scoped, by the layout ID
+ hashed a second time: IDs of items submitted inside stack layouts change, and settings saved
+ under them (e.g. tables in imgui.ini) reset once.
+
+Other Changes:
+
+- Nested layouts: fixed content submitted after a nested layout not being displayed, and
+ content drawn by the parent before a nested layout ending up over it. Each layout now
+ clips and merges its draw commands when it ends. (thedmd/imgui#10, ocornut/imgui#846) [@pthom]
+- Nested layouts: fixed an enclosing BeginGroup()/EndGroup() growing but never shrinking:
+ an auto-sized nested layout grows to its parent's size only when it has springs.
+ (thedmd/imgui#9) [@pthom]
+- Horizontal layouts: fixed vertical drift of items with a fractional height.
+ (thedmd/imgui#9, ocornut/imgui#9333) [@pthom]
+- Style: fixed ImGuiStyleVar_LayoutAlign not matching its GStyleVarsInfo[] entry, which made
+ PushStyleVar() modify the wrong field, or assert, for it and for every style variable
+ declared after it. (thedmd/imgui#7) [@firesgc]
+- Layout: fixed SameLine() in menu bars and custom combo previews moving the next item one row
+ down and over the previous one. Outside of stack layouts, ItemSize() behaves as upstream.
+- Springs, alignment: fixed corrections made within the frame moving unrelated vertices in
+ windows with more than 64K vertices.
+- Error Handling: fixed asserting on a layout left open at the end of the frame (e.g. in a
+ window missing End()) before error recovery could close it.
+- Error Handling: fixed a crash recovering from SuspendLayout() without ResumeLayout().
+- Misc: fixed unused parameter/variable warnings. (thedmd/imgui#9) [@pthom]
+
+
+ACKNOWLEDGMENTS
+===============
+
+Thanks to everyone who reported issues and contributed fixes:
+- @pthom: nested layout, fractional height and warning fixes (thedmd/imgui#9, thedmd/imgui#10),
+ report of ocornut/imgui#9333.
+- @firesgc: ImGuiStyleVar_LayoutAlign fix (thedmd/imgui#7).
+- @wkster: report of content missing after a nested layout (ocornut/imgui#846).
+- @gnif: missing intptr_t include fix (thedmd/imgui#4).
+
+*/
+
+#pragma once
+
+#include "imgui.h"
+
+// Version of the stack layout code, independent of IMGUI_VERSION. X.Y is X * 10000 + Y * 100 in IMGUI_STACK_LAYOUT_VERSION_NUM.
+#define IMGUI_STACK_LAYOUT_VERSION "2.2"
+#define IMGUI_STACK_LAYOUT_VERSION_NUM 20200
+
+#ifndef IMGUI_DISABLE
+
+//-----------------------------------------------------------------------------
+// [SECTION] Stack Layout API
+//-----------------------------------------------------------------------------
+
+typedef int ImGuiLayoutDebugFlags; // -> enum ImGuiLayoutDebugFlags_ // Flags: for SetNextLayoutDebugFlags()
+
+// Flags for SetNextLayoutDebugFlags()
+enum ImGuiLayoutDebugFlags_
+{
+ ImGuiLayoutDebugFlags_None = 0,
+ ImGuiLayoutDebugFlags_DrawSprings = 1 << 0, // Draw springs and their spacing.
+ ImGuiLayoutDebugFlags_DrawItems = 1 << 1, // Draw the bounds of the items between springs.
+};
+
+namespace ImGui
+{
+ // Stack layouts: items flow along the layout, and springs share the free space by weight.
+ // - size: 0.0f = automatic, > 0.0f = fixed, < 0.0f = relative to the far edge of the content region, as in CalcItemSize() (-FLT_MIN fills it).
+ // - align: position of items on the other axis, from 0.0f (left/top) to 1.0f (right/bottom). < 0.0f uses style.LayoutAlign.
+ // - IDs: contents are scoped like PushID() with the same identifier. To reach an ID across the scope, take it outside,
+ // e.g. ImGuiID popup_id = GetID("popup") before BeginHorizontal(), OpenPopup(popup_id) inside, BeginPopup("popup") after EndHorizontal().
+ IMGUI_API void BeginHorizontal(const char* str_id, const ImVec2& size = ImVec2(0, 0), float align = -1.0f);
+ IMGUI_API void BeginHorizontal(const void* ptr_id, const ImVec2& size = ImVec2(0, 0), float align = -1.0f);
+ IMGUI_API void BeginHorizontal(int id, const ImVec2& size = ImVec2(0, 0), float align = -1);
+ IMGUI_API void EndHorizontal();
+ IMGUI_API void BeginVertical(const char* str_id, const ImVec2& size = ImVec2(0, 0), float align = -1.0f);
+ IMGUI_API void BeginVertical(const void* ptr_id, const ImVec2& size = ImVec2(0, 0), float align = -1.0f);
+ IMGUI_API void BeginVertical(int id, const ImVec2& size = ImVec2(0, 0), float align = -1);
+ IMGUI_API void EndVertical();
+ IMGUI_API void Spring(float weight = 1.0f, float spacing = -1.0f);
+ IMGUI_API void SuspendLayout();
+ IMGUI_API void ResumeLayout();
+ IMGUI_API void SetNextLayoutDebugFlags(ImGuiLayoutDebugFlags flags); // Draw the next layout and the layouts nested in it. Exact once the outermost layout ends, as their sizes settle there.
+
+} // namespace ImGui
+
+
+#endif // #ifndef IMGUI_DISABLE
diff --git a/imgui_stacklayout_internal.h b/imgui_stacklayout_internal.h
new file mode 100644
index 000000000..03df9ae2f
--- /dev/null
+++ b/imgui_stacklayout_internal.h
@@ -0,0 +1,28 @@
+// dear imgui: stack layouts
+// (stack layout internal headers)
+
+/*
+
+Index of this file:
+// [SECTION] Stack Layout Internal API
+
+*/
+
+#pragma once
+
+#include "imgui_internal.h"
+#include "imgui_stacklayout.h"
+
+#ifndef IMGUI_DISABLE
+
+//-----------------------------------------------------------------------------
+// [SECTION] Stack Layout Internal API
+//-----------------------------------------------------------------------------
+
+namespace ImGuiStackLayout
+{
+ IMGUI_API void ErrorRecoveryTryToRecoverWindowState(const ImGuiErrorRecoveryState* state_in);
+} // namespace ImGuiStackLayout
+
+
+#endif // #ifndef IMGUI_DISABLE
diff --git a/misc/single_file/imgui_single_file.h b/misc/single_file/imgui_single_file.h
index bea1cb6b6..5201b70e0 100644
--- a/misc/single_file/imgui_single_file.h
+++ b/misc/single_file/imgui_single_file.h
@@ -21,6 +21,7 @@
#include "../../imgui.cpp"
#include "../../imgui_demo.cpp"
#include "../../imgui_draw.cpp"
+#include "../../imgui_stacklayout.cpp"
#include "../../imgui_tables.cpp"
#include "../../imgui_widgets.cpp"
#ifdef IMGUI_ENABLE_FREETYPE