Skip to content

Commit 2353766

Browse files
committed
- added SimpleListView.cs
- added StateButton.cs - added SavedToggleShaderProperty.cs - re-organized UIElements stuff into dedicated folder - added HandleBarPartial.uxml to visualize handle bars for any SimpleListView.cs
1 parent 1133bd2 commit 2353766

12 files changed

+388
-0
lines changed

Editor/UIElements.meta

Lines changed: 8 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
using System;
2+
using UnityEditor;
3+
using UnityEngine;
4+
using UnityEngine.UIElements;
5+
6+
namespace EditorUI {
7+
/// <summary>
8+
/// Helper class for managing a toggleable shader property with saved state.
9+
/// </summary>
10+
public class SavedToggleShaderProperty {
11+
/// <summary>
12+
/// Key in the EditorPrefs for storing the property state.
13+
/// </summary>
14+
private readonly string prefsKey;
15+
16+
/// <summary>
17+
/// Name of the shader variable.
18+
/// </summary>
19+
private readonly string variableName;
20+
21+
/// <summary>
22+
/// Display name of the toggle.
23+
/// </summary>
24+
private readonly string displayName;
25+
26+
/// <summary>
27+
/// Default state of the property.
28+
/// </summary>
29+
private readonly bool defaultState;
30+
31+
/// <summary>
32+
/// Flag indicating whether to negate the state of the property.
33+
/// </summary>
34+
private readonly bool negateState;
35+
36+
/// <summary>
37+
/// Gets or sets the current state of the property.
38+
/// </summary>
39+
public bool IsPropertyActive {
40+
get => EditorPrefs.GetBool(prefsKey, defaultState);
41+
set => EditorPrefs.SetBool(prefsKey, value);
42+
}
43+
44+
/// <summary>
45+
/// Constructor for SavedToggleShaderProperty.
46+
/// </summary>
47+
/// <param name="baseKey">Base key for the EditorPrefs.</param>
48+
/// <param name="variableName">Name of the shader variable.</param>
49+
/// <param name="displayName">Display name of the toggle.</param>
50+
/// <param name="defaultState">Default state of the property.</param>
51+
/// <param name="negateState">Flag indicating whether to negate the state of the property.</param>
52+
public SavedToggleShaderProperty(string baseKey, string variableName, string displayName, bool defaultState = true, bool negateState = false) {
53+
prefsKey = baseKey + "." + variableName;
54+
this.variableName = variableName;
55+
this.displayName = displayName;
56+
this.defaultState = defaultState;
57+
this.negateState = negateState;
58+
}
59+
60+
/// <summary>
61+
/// Creates a GUI element for the toggle property.
62+
/// </summary>
63+
/// <param name="root">Root VisualElement to attach the toggle to.</param>
64+
/// <param name="OnChange">Action to be invoked when the toggle value changes.</param>
65+
public void CreateGUI(VisualElement root, Action OnChange) {
66+
Toggle toggle = new Toggle(displayName) { value = IsPropertyActive };
67+
toggle.RegisterValueChangedCallback((evt) => {
68+
IsPropertyActive = evt.newValue;
69+
OnChange?.Invoke();
70+
});
71+
root.Add(toggle);
72+
}
73+
74+
/// <summary>
75+
/// Draws the toggle property in an Editor window.
76+
/// </summary>
77+
/// <param name="rect">Position and size of the GUI element.</param>
78+
/// <returns>True if the property value changed, false otherwise.</returns>
79+
public bool Draw(Rect rect) {
80+
EditorGUI.BeginChangeCheck();
81+
82+
bool newState = EditorGUI.Toggle(rect, displayName, IsPropertyActive);
83+
if (Event.current.type == EventType.MouseUp && rect.Contains(Event.current.mousePosition)) {
84+
newState = !IsPropertyActive;
85+
}
86+
87+
if (EditorGUI.EndChangeCheck() || newState != IsPropertyActive) {
88+
IsPropertyActive = newState;
89+
return true;
90+
}
91+
92+
return false;
93+
}
94+
95+
/// <summary>
96+
/// Sets the shader property in a MaterialPropertyBlock.
97+
/// </summary>
98+
/// <param name="propertyBlock">The MaterialPropertyBlock to set the property in.</param>
99+
public void SetProperty(MaterialPropertyBlock propertyBlock) {
100+
if (!negateState) {
101+
propertyBlock.SetFloat(variableName, IsPropertyActive ? 1 : 0);
102+
} else {
103+
propertyBlock.SetFloat(variableName, IsPropertyActive ? 0 : 1);
104+
}
105+
}
106+
}
107+
}

Editor/UIElements/SavedToggleShaderProperty.cs.meta

Lines changed: 11 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 137 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,137 @@
1+
using System;
2+
using UnityEditor;
3+
using UnityEngine.UIElements;
4+
5+
namespace EditorUI {
6+
/// <summary>
7+
/// Base class for a simple list view.
8+
/// </summary>
9+
public abstract class SimpleListView : ListView {
10+
/// <summary>
11+
/// Name of the item row container.
12+
/// </summary>
13+
private readonly string itemRowContainer = DEFAULT_ITEMROW_CONTAINER_NAME;
14+
15+
/// <summary>
16+
/// Default name for the item row container.
17+
/// </summary>
18+
private const string DEFAULT_ITEMROW_CONTAINER_NAME = nameof(SimpleListView) + "_" + nameof(itemRowContainer);
19+
20+
/// <summary>
21+
/// Constant value for the handle bars partial GUID.
22+
/// </summary>
23+
private const string HANDLE_BARS_PARTIAL_GUID = "cef02cc912d280d4cb3ea263d3012dc7";
24+
25+
/// <summary>
26+
/// Partial to identifiy a list view in ui elements
27+
/// </summary>
28+
private const string LISTVIEW_IDENTIFIER_PARTIAL = "unity-list-view__";
29+
30+
/// <summary>
31+
/// Event for when an item is added.
32+
/// </summary>
33+
public Action addClicked;
34+
35+
/// <summary>
36+
/// Event for when an item is removed.
37+
/// </summary>
38+
public Action removeClicked;
39+
40+
/// <summary>
41+
/// Event for creating a row in the list view.
42+
/// </summary>
43+
public Action<VisualElement> createRow;
44+
45+
/// <summary>
46+
/// Static variable for the handle bars partial.
47+
/// </summary>
48+
private static VisualTreeAsset _handleBarsPartial = null;
49+
50+
/// <summary>
51+
/// Property for accessing the handle bars partial.
52+
/// </summary>
53+
public static VisualTreeAsset HandleBarsPartial {
54+
get {
55+
if (_handleBarsPartial == null) {
56+
_handleBarsPartial = AssetDatabase.LoadAssetAtPath<VisualTreeAsset>(HANDLE_BARS_PARTIAL_GUID);
57+
}
58+
return _handleBarsPartial;
59+
}
60+
}
61+
62+
/// <summary>
63+
/// Constructor for SimpleListView.
64+
/// </summary>
65+
/// <param name="reorderable">Flag to enable or disable reordering of items.</param>
66+
/// <param name="showAddRemoveFooter">Flag to show or hide the add/remove footer.</param>
67+
/// <param name="itemRowContainer">Name of the item row container.</param>
68+
/// <param name="createRow">Action for creating a row in the list view.</param>
69+
/// <param name="addClicked">Action for handling the add button click event.</param>
70+
/// <param name="removeClicked">Action for handling the remove button click event.</param>
71+
/// <param name="doDefaultMake">Flag to indicate whether to use the default make item behavior.</param>
72+
public SimpleListView(bool reorderable = true, bool showAddRemoveFooter = true, string itemRowContainer = DEFAULT_ITEMROW_CONTAINER_NAME, Action<VisualElement> createRow = null, Action addClicked = null, Action removeClicked = null, bool doDefaultMake = false) {
73+
// Set flags
74+
this.reorderable = reorderable;
75+
this.showAddRemoveFooter = showAddRemoveFooter;
76+
this.itemRowContainer = itemRowContainer;
77+
78+
// Set up events
79+
this.addClicked = addClicked;
80+
this.removeClicked = removeClicked;
81+
this.createRow = createRow;
82+
83+
showBorder = true;
84+
if (!doDefaultMake) {
85+
makeItem = MakeItem;
86+
}
87+
selectionType = SelectionType.Single;
88+
reorderMode = ListViewReorderMode.Simple;
89+
showBoundCollectionSize = false;
90+
91+
// Your ListView needs to take all the remaining space
92+
style.flexGrow = 1;
93+
94+
// Overwrite default button behaviors due to bugs in ListView code
95+
schedule.Execute(() => {
96+
virtualizationMethod = CollectionVirtualizationMethod.DynamicHeight;
97+
Button removeButton = this.Q<Button>(LISTVIEW_IDENTIFIER_PARTIAL+"remove-button");
98+
removeButton.clickable = null;
99+
removeButton.clicked += RemoveClicked;
100+
Button addButton = this.Q<Button>(LISTVIEW_IDENTIFIER_PARTIAL+"add-button");
101+
addButton.clickable = null;
102+
addButton.clicked += AddClicked;
103+
});
104+
}
105+
106+
/// <summary>
107+
/// Method for creating a new item in the list view.
108+
/// </summary>
109+
/// <returns>The created item as a VisualElement.</returns>
110+
private VisualElement MakeItem() {
111+
VisualElement rowItem = new VisualElement();
112+
if (reorderable) {
113+
// Add handlebars with hand symbol to imply dragging support
114+
rowItem.Add(HandleBarsPartial.Instantiate()[0]);
115+
}
116+
rowItem.AddToClassList(itemRowContainer);
117+
createRow?.Invoke(rowItem);
118+
return rowItem;
119+
}
120+
121+
/// <summary>
122+
/// Method for handling the add button click event.
123+
/// </summary>
124+
protected virtual void AddClicked() {
125+
addClicked?.Invoke();
126+
ClearSelection();
127+
}
128+
129+
/// <summary>
130+
/// Method for handling the remove button click event.
131+
/// </summary>
132+
protected virtual void RemoveClicked() {
133+
removeClicked?.Invoke();
134+
ClearSelection();
135+
}
136+
}
137+
}

Editor/UIElements/SimpleListView.cs.meta

Lines changed: 11 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Editor/UIElements/StateButton.cs

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
using System;
2+
using UnityEditor;
3+
using UnityEngine.UIElements;
4+
5+
namespace EditorUI {
6+
/// <summary>
7+
/// Custom button with state functionality.
8+
/// </summary>
9+
public class StateButton : Button {
10+
/// <summary>
11+
/// Key for storing the state in the EditorPrefs.
12+
/// </summary>
13+
private string stateEditorPrefsKey;
14+
15+
/// <summary>
16+
/// Current state of the button.
17+
/// </summary>
18+
private bool state;
19+
20+
/// <summary>
21+
/// Action to be performed after the button is clicked.
22+
/// </summary>
23+
private Action afterClicked;
24+
25+
/// <summary>
26+
/// CSS class to apply when the button is active.
27+
/// </summary>
28+
private string buttonActiveClass;
29+
30+
/// <summary>
31+
/// Gets the current state of the button.
32+
/// </summary>
33+
public bool State => state;
34+
35+
/// <summary>
36+
/// Constructor for the StateButton class.
37+
/// </summary>
38+
/// <param name="stateEditorPrefsKey">Key for storing the state in the EditorPrefs.</param>
39+
/// <param name="buttonLabel">Label text of the button.</param>
40+
/// <param name="buttonActiveClass">CSS class to apply when the button is active.</param>
41+
/// <param name="afterClicked">Action to be performed after the button is clicked.</param>
42+
/// <param name="defaultStateValue">Default state value of the button.</param>
43+
public StateButton(string stateEditorPrefsKey, string buttonLabel, string buttonActiveClass, Action afterClicked = null, bool defaultStateValue = true) {
44+
this.stateEditorPrefsKey = stateEditorPrefsKey;
45+
this.afterClicked = afterClicked;
46+
this.buttonActiveClass = buttonActiveClass;
47+
48+
text = buttonLabel;
49+
clicked -= OnButtonClicked;
50+
clicked += OnButtonClicked;
51+
52+
OnButtonClickedBase(EditorPrefs.GetBool(stateEditorPrefsKey, defaultStateValue));
53+
}
54+
55+
/// <summary>
56+
/// Event handler for button click event.
57+
/// </summary>
58+
private void OnButtonClicked() {
59+
OnButtonClickedBase(!state);
60+
}
61+
62+
/// <summary>
63+
/// Sets the button state and updates its appearance.
64+
/// </summary>
65+
/// <param name="stateToSet">State value to set.</param>
66+
private void OnButtonClickedBase(bool stateToSet) {
67+
state = stateToSet;
68+
69+
if (state) {
70+
AddToClassList(buttonActiveClass);
71+
} else {
72+
RemoveFromClassList(buttonActiveClass);
73+
}
74+
75+
EditorPrefs.SetBool(stateEditorPrefsKey, state);
76+
afterClicked?.Invoke();
77+
}
78+
}
79+
}

Editor/UIElements/StateButton.cs.meta

Lines changed: 11 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
File renamed without changes.

Editor/UIElements/UXML.meta

Lines changed: 8 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)