@@ -32,8 +32,12 @@ public enum SelectableFlags
3232
3333 private static readonly Dictionary < string , bool > treeViewStates = [ ] ;
3434
35+ private static readonly Dictionary < string , bool > collapsingHeaderStates = [ ] ;
36+
3537 private static readonly HashSet < int > usedTreeViewStates = [ ] ;
3638
39+ private static readonly HashSet < int > usedCollapsingHeaderStates = [ ] ;
40+
3741 private static readonly List < Action > endFrameCallbacks = [ ] ;
3842
3943 private static string MakeIdentifier ( string identifier , string key ) => $ "{ identifier } ##{ key } ";
@@ -123,12 +127,29 @@ internal static void OnFrameStart()
123127
124128 treeViewStates . Remove ( key ) ;
125129 }
130+
131+ keys = collapsingHeaderStates . Keys . ToArray ( ) ;
132+
133+ foreach ( var key in keys )
134+ {
135+ if ( usedCollapsingHeaderStates . Contains ( key . GetHashCode ( ) ) )
136+ {
137+ continue ;
138+ }
139+
140+ collapsingHeaderStates . Remove ( key ) ;
141+ }
126142 }
127143
128144 if ( usedTreeViewStates . Count > 0 )
129145 {
130146 usedTreeViewStates . Clear ( ) ;
131147 }
148+
149+ if ( usedCollapsingHeaderStates . Count > 0 )
150+ {
151+ usedCollapsingHeaderStates . Clear ( ) ;
152+ }
132153 }
133154
134155 internal static void OnFrameEnd ( )
@@ -1357,7 +1378,6 @@ public static void TreeNodeIcon(Texture icon, Color color, string label, string
13571378 /// <param name="leaf">Whether it's a leaf (doesn't open on click, no arrow)</param>
13581379 /// <param name="openHandler">A handler for when it is open</param>
13591380 /// <param name="clickHandler">A handler for when it is clicked</param>
1360- /// <param name="openHandler">A handler for when it is open</param>
13611381 /// <param name="prefixHandler">A handler to run regardless of the node being open</param>
13621382 /// <remarks>Click Handler will trigger when the left or right mouse button is clicked</remarks>
13631383 public static void TreeNodeIcon ( Texture icon , string label , string key , bool leaf , ref bool open , Action openHandler , Action clickHandler ,
@@ -1885,4 +1905,124 @@ public static void Table(string key, int rows, int columns, bool showHeader, Act
18851905 ImGui . EndTable ( ) ;
18861906 }
18871907 }
1908+
1909+ /// <summary>
1910+ /// Create a collapsing header
1911+ /// </summary>
1912+ /// <param name="label">The label for the header</param>
1913+ /// <param name="key">The header's unique ID</param>
1914+ /// <param name="showCloseButton">Whether we should show a close button</param>
1915+ /// <param name="handler">A callback when the header is expanded</param>
1916+ /// <param name="closed">A callback when the header's close button is clicked</param>
1917+ /// <param name="defaultOpen">Whether the tree should be open by default</param>
1918+ public static void CollapsingHeader ( string label , string key , bool showCloseButton , Action handler ,
1919+ Action closed , bool defaultOpen = false )
1920+ {
1921+ var flags = ImGuiTreeNodeFlags . OpenOnArrow | ImGuiTreeNodeFlags . OpenOnDoubleClick ;
1922+
1923+ if ( defaultOpen )
1924+ {
1925+ flags |= ImGuiTreeNodeFlags . DefaultOpen ;
1926+ }
1927+
1928+ var visible = showCloseButton ;
1929+ bool open ;
1930+
1931+ if ( showCloseButton )
1932+ {
1933+ open = ImGui . CollapsingHeader ( MakeIdentifier ( label , key ) , ref visible , flags ) ;
1934+ }
1935+ else
1936+ {
1937+ open = ImGui . CollapsingHeader ( MakeIdentifier ( label , key ) , flags ) ;
1938+ }
1939+
1940+ var stateKey = $ "{ label } -{ key } ";
1941+
1942+ if ( collapsingHeaderStates . TryGetValue ( stateKey , out var isOpen ) == false )
1943+ {
1944+ isOpen = false ;
1945+
1946+ collapsingHeaderStates . Add ( stateKey , isOpen ) ;
1947+ }
1948+
1949+ usedCollapsingHeaderStates . Add ( stateKey . GetHashCode ( ) ) ;
1950+
1951+ if ( isOpen != open )
1952+ {
1953+ collapsingHeaderStates . AddOrSetKey ( stateKey , open ) ;
1954+ }
1955+
1956+ isOpen = open ;
1957+
1958+ if ( open )
1959+ {
1960+ ExecuteHandler ( handler , key ) ;
1961+ }
1962+
1963+ if ( showCloseButton && visible == false )
1964+ {
1965+ ExecuteHandler ( closed , $ "{ key } closed") ;
1966+ }
1967+ }
1968+
1969+ /// <summary>
1970+ /// Create a collapsing header
1971+ /// </summary>
1972+ /// <param name="label">The label for the header</param>
1973+ /// <param name="key">The header's unique ID</param>
1974+ /// <param name="open">Whether the header is open</param>
1975+ /// <param name="showCloseButton">Whether we should show a close button</param>
1976+ /// <param name="handler">A callback when the header is expanded</param>
1977+ /// <param name="closed">A callback when the header's close button is clicked</param>
1978+ /// <param name="defaultOpen">Whether the tree should be open by default</param>
1979+ public static void CollapsingHeader ( string label , string key , ref bool open , bool showCloseButton , Action handler ,
1980+ Action closed , bool defaultOpen = false )
1981+ {
1982+ var flags = ImGuiTreeNodeFlags . OpenOnArrow | ImGuiTreeNodeFlags . OpenOnDoubleClick ;
1983+
1984+ if ( defaultOpen )
1985+ {
1986+ flags |= ImGuiTreeNodeFlags . DefaultOpen ;
1987+ }
1988+
1989+ var visible = showCloseButton ;
1990+
1991+ if ( showCloseButton )
1992+ {
1993+ open = ImGui . CollapsingHeader ( MakeIdentifier ( label , key ) , ref visible , flags ) ;
1994+ }
1995+ else
1996+ {
1997+ open = ImGui . CollapsingHeader ( MakeIdentifier ( label , key ) , flags ) ;
1998+ }
1999+
2000+ var stateKey = $ "{ label } -{ key } ";
2001+
2002+ if ( collapsingHeaderStates . TryGetValue ( stateKey , out var isOpen ) == false )
2003+ {
2004+ isOpen = false ;
2005+
2006+ collapsingHeaderStates . Add ( stateKey , isOpen ) ;
2007+ }
2008+
2009+ usedCollapsingHeaderStates . Add ( stateKey . GetHashCode ( ) ) ;
2010+
2011+ if ( isOpen != open )
2012+ {
2013+ collapsingHeaderStates . AddOrSetKey ( stateKey , open ) ;
2014+ }
2015+
2016+ isOpen = open ;
2017+
2018+ if ( open )
2019+ {
2020+ ExecuteHandler ( handler , key ) ;
2021+ }
2022+
2023+ if ( showCloseButton && visible == false )
2024+ {
2025+ ExecuteHandler ( closed , $ "{ key } closed") ;
2026+ }
2027+ }
18882028}
0 commit comments