Skip to content

Commit 082499a

Browse files
Add Foldout Groups
1 parent e7431eb commit 082499a

File tree

5 files changed

+125
-12
lines changed

5 files changed

+125
-12
lines changed
58.3 KB
Loading

Editor/ShaderGraphEditor/OpenGraphGUIEditor.cs

Lines changed: 118 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -55,13 +55,18 @@ public class OpenGraphGUIEditor : ShaderGUI
5555
/// Amount of tab spacing for single line texture property.
5656
/// </summary>
5757
const float singleLineTexTabSpace = 2f;
58+
/// <summary>
59+
/// Amount of spacing above label properties.
60+
/// </summary>
61+
const float labelTopSpace = 4f;
5862

5963
const string centeredSpacingName = "[centered]";
6064
const string rightBoundSpacingName = "[rightbound]";
6165
const string maxFieldSpacingName = "[maxfield]";
6266
const string minFieldSpacingName = "[minfield]";
6367

6468
const string labelPrefix = "*";
69+
const string foldoutPrefix = "#";
6570
const string singleLineTexPrefix = "%";
6671
const string dependentVisibleTextPrefix = "^";
6772
const string linkedPropertyPrefix = "&";
@@ -83,11 +88,26 @@ class LinkedProperty
8388
private bool fieldCenteredMode = false;
8489
private bool fieldExpandedMode = false;
8590

91+
private bool hadOneFoldout = false;
92+
private bool currentlyInFoldout = false;
93+
private int currentFoldoutIndex = 0;
94+
private bool bottomOptionsFoldout = true;
95+
96+
/// <summary>
97+
/// Bool list for each foldout encountered. Supports up to 128 foldouts.
98+
/// </summary>
99+
private bool[] foldoutArray = new bool[128];
100+
86101
protected Dictionary<string, System.Action<MaterialEditor, MaterialProperty>> renderExtensions = null;
87102

88103
public OpenGraphGUIEditor()
89104
{
90105
renderExtensions = null;
106+
for(int i = 0; i < foldoutArray.Length; i++)
107+
{
108+
//Initialize foldouts to show by default
109+
foldoutArray[i] = true;
110+
}
91111
}
92112

93113
//BASE GUI STRUCTURE
@@ -104,6 +124,8 @@ public override void OnGUI(MaterialEditor materialEditor, MaterialProperty[] pro
104124

105125
fieldCenteredMode = false;
106126
fieldExpandedMode = false;
127+
hadOneFoldout = false;
128+
currentlyInFoldout = false;
107129
SetUtilityLabelWidth();
108130

109131
RenderPropertiesList(properties);
@@ -120,6 +142,9 @@ public override void OnGUI(MaterialEditor materialEditor, MaterialProperty[] pro
120142
/// <param name="properties"></param>
121143
void RenderPropertiesList(MaterialProperty[] properties)
122144
{
145+
//Track count of foldouts encountered
146+
int foldoutCount = 0;
147+
123148
//Track if the last property was non-texture type or
124149
//contained a non-null input texture
125150
bool lastWasPopulated = true;
@@ -147,8 +172,17 @@ void RenderPropertiesList(MaterialProperty[] properties)
147172

148173
currentLinkedProperties.Add(thisProp.displayName, link);
149174
}
175+
else if (thisProp.displayName.StartsWith(foldoutPrefix))
176+
{
177+
//This is a foldout property
178+
179+
foldoutCount++;
180+
}
150181
}
151182

183+
//Reset current foldout to 0
184+
currentFoldoutIndex = 0;
185+
152186
//Now iterate across the properties for real and render them
153187
for (int i = 0; i < properties.Length; i++)
154188
{
@@ -192,7 +226,7 @@ void RenderPropertiesList(MaterialProperty[] properties)
192226
//Use min field width and don't render this property
193227
SetFieldExpandedMode(false);
194228
}
195-
else if(currentLinkedProperties.ContainsKey(propName))
229+
else if(currentLinkedProperties.ContainsKey(propName) && DoRenderProp())
196230
{
197231
//This is a linked property, so check if it was rendered already
198232
var thisLinkedProp = currentLinkedProperties[propName];
@@ -210,7 +244,51 @@ void RenderPropertiesList(MaterialProperty[] properties)
210244
RenderVisibleProperty(thisLinkedProp.matProperty, propName, i);
211245
}
212246
}
213-
else if(propName.StartsWith(labelPrefix))
247+
else if (propName.StartsWith(foldoutPrefix))
248+
{
249+
//This is a foldout type, so create a new group
250+
251+
//Trim the foldout prefix
252+
propName = propName.Substring(foldoutPrefix.Length);
253+
if(propName.Trim().Length > 0)
254+
{
255+
//There is a foldout name to use
256+
257+
if(currentlyInFoldout)
258+
{
259+
//Stop the previous foldout
260+
EditorGUILayout.EndFoldoutHeaderGroup();
261+
}
262+
263+
//Update the current foldout index to the new value before setting it
264+
currentFoldoutIndex++;
265+
//This is done first so that later on, DoRenderProp() can tell if the last foldout is unfolded,
266+
//While still allowing this value to change when it encountered a new foldout.
267+
268+
//This actually means the first item (0) will be skipped
269+
//But that's okay because it is never referenced.
270+
271+
//Render the foldout
272+
foldoutArray[currentFoldoutIndex] = EditorGUILayout.BeginFoldoutHeaderGroup(foldoutArray[currentFoldoutIndex], propName);
273+
274+
//Finally, track that we encountered at least one foldout
275+
hadOneFoldout = true;
276+
//And tell the next properties that we are in a foldout
277+
currentlyInFoldout = true;
278+
279+
}
280+
else
281+
{
282+
//End the last foldout if there is one
283+
if(currentlyInFoldout)
284+
{
285+
EditorGUILayout.EndFoldoutHeaderGroup();
286+
currentlyInFoldout = false;
287+
}
288+
}
289+
290+
}
291+
else if(propName.StartsWith(labelPrefix) && DoRenderProp())
214292
{
215293
//This is a label type, so show a bold header instead of the property
216294

@@ -219,7 +297,7 @@ void RenderPropertiesList(MaterialProperty[] properties)
219297

220298
RenderLabelProperty(propName);
221299
}
222-
else if (propName.StartsWith(dependentVisibleTextPrefix))
300+
else if (propName.StartsWith(dependentVisibleTextPrefix) && DoRenderProp())
223301
{
224302
//It is dependent, so we will conditionally render it
225303

@@ -235,7 +313,7 @@ void RenderPropertiesList(MaterialProperty[] properties)
235313
//Don't render this property
236314
}
237315
}
238-
else
316+
else if (DoRenderProp())
239317
{
240318
//It's not dependent, so update populated state based on this
241319
if (thisProp.type == MaterialProperty.PropType.Texture)
@@ -260,11 +338,27 @@ void RenderPropertiesList(MaterialProperty[] properties)
260338
/// </summary>
261339
void RenderBottomOptions()
262340
{
263-
matEditor.RenderQueueField();
341+
//If we had one foldout earlier, draw this as it's own foldout group
342+
if(hadOneFoldout)
343+
{
344+
if(currentlyInFoldout)
345+
{
346+
EditorGUILayout.EndFoldoutHeaderGroup();
347+
}
348+
bottomOptionsFoldout = EditorGUILayout.BeginFoldoutHeaderGroup(bottomOptionsFoldout, "Advanced");
349+
}
350+
351+
//If we don't use the group OR we do & it's unfolded, show the options
352+
if(!hadOneFoldout || bottomOptionsFoldout)
353+
{
354+
matEditor.RenderQueueField();
264355

265-
matEditor.EnableInstancingField();
266-
matEditor.DoubleSidedGIField();
267-
matEditor.EmissionEnabledProperty();
356+
matEditor.EnableInstancingField();
357+
matEditor.DoubleSidedGIField();
358+
matEditor.EmissionEnabledProperty();
359+
//Lightmap Emission may be a built-in only concept(?)
360+
//matEditor.LightmapEmissionProperty();
361+
}
268362
}
269363

270364
//PROPERTY RENDERING
@@ -279,6 +373,7 @@ void RenderBottomOptions()
279373
/// <param name="index"></param>
280374
void RenderDependentVisibleProperty(MaterialProperty v, string labelName, int index)
281375
{
376+
282377
//Shift over by a small amount to show the dependency
283378
EditorGUILayout.BeginHorizontal();
284379

@@ -309,7 +404,7 @@ void RenderDependentVisibleProperty(MaterialProperty v, string labelName, int in
309404
void RenderVisibleProperty(MaterialProperty v, string labelName, int index)
310405
{
311406

312-
if(labelName.StartsWith(singleLineTexPrefix))
407+
if (labelName.StartsWith(singleLineTexPrefix))
313408
{
314409
if(v.type == MaterialProperty.PropType.Texture)
315410
{
@@ -360,6 +455,7 @@ void RenderVisibleProperty(MaterialProperty v, string labelName, int index)
360455
/// <param name="v"></param>
361456
void RenderDefaultPropertyView(MaterialProperty v, string customName = "")
362457
{
458+
363459
string finalName = (customName == "") ? v.displayName : customName;
364460

365461
switch(v.type)
@@ -394,9 +490,22 @@ void RenderDefaultPropertyView(MaterialProperty v, string customName = "")
394490
/// <param name="propName"></param>
395491
void RenderLabelProperty(string propName)
396492
{
493+
EditorGUILayout.Space(labelTopSpace);
397494
EditorGUILayout.LabelField(propName, EditorStyles.boldLabel);
398495
}
399496

497+
//QUERY
498+
499+
/// <summary>
500+
/// Check if we should render the current prop
501+
/// based on foldout status.
502+
/// </summary>
503+
/// <returns></returns>
504+
bool DoRenderProp()
505+
{
506+
return (!currentlyInFoldout || foldoutArray[currentFoldoutIndex]);
507+
}
508+
400509
//EDITOR GUI
401510

402511
/// <summary>

README.md

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ The default Inspector view for ShaderGraph-based materials can be somewhat bland
99

1010
## Why use OpenGraphGUI?
1111

12-
**OpenGraphGUI** lets you customize the appearance of your material properties right from ShaderGraph. Simply prefix your property names in the Shader's Blackboard with certain special characters, and any material using that Shader will display the custom GUI.
12+
**OpenGraphGUI** lets you customize the appearance of your material properties right from ShaderGraph. Simply prefix your property names in the Shader's Blackboard with certain special characters, and any material using that Shader will display the custom GUI. This is a lightweight and easy to use script that provides more control over the design of your Shaders.
1313

1414
<img width = "700" src="Documentation~/DocAssets/AllTagsScreen.jpg">
1515

@@ -37,6 +37,10 @@ Use a property called **\[Centered\]** to adjust the spacing of the Inspector fi
3737

3838
<img width = "500" src="Documentation~/DocAssets/FieldWidthScreenshot.jpg">
3939

40+
**New!** Use the **hashtag symbol (#)** as a prefix for one of your properties and you will create a Foldout Group with your property name as the title. Create up to 128 unique foldout groups by creating new foldout properties in sequence without having to tag the end of each group. If you do wish to close the previous Foldout Group, simply create a property that consists of only a **hashtag symbol (#)** without any name. The following properties will exist outside of the last group.
41+
42+
<img width = "550" src="Documentation~/DocAssets/FoldoutGroupsScreenshot.jpg">
43+
4044
### Property Rendering Features
4145

4246
Prefix a texture property with the **percent symbol (%)** and it will show as a single line texture property instead of the big thumbnail version. Single line textures are commonly used in the built-in materials and offer a cleaner look that takes up less space in your Inspector.

Samples~/DrawPropertyExtension/OpenGraphPropertyExtension.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ public class RPOpenGraphGUIExtension : RPOpenGraphGUI
1818
/// There is one property which we can override to add our extension.
1919
/// This is done from within the constructor to improve performance.
2020
/// </summary>
21-
public RPOpenGraphGUIExtension()
21+
public RPOpenGraphGUIExtension() : base()
2222
{
2323
//First initialize the property
2424
renderExtensions = new Dictionary<string, System.Action<MaterialEditor, MaterialProperty>>();

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "com.robproductions.opengraphgui",
3-
"version": "1.1.0",
3+
"version": "1.2.0",
44
"displayName": "Open Graph GUI",
55
"description": "An open-source generic Shader GUI for use with URP ShaderGraphs. This package aims to help developers clean up the look of their Material properties while maintaining the built-in style.",
66
"unity": "2020.3",

0 commit comments

Comments
 (0)