Last active
April 19, 2024 13:07
-
-
Save soraphis/7c98d1bb77ac9cc088a629335b342a90 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Collections.Generic; | |
using UnityEditor; | |
using UnityEditor.UIElements; | |
using UnityEngine; | |
using UnityEngine.UIElements; | |
[CustomEditor(typeof(SegmentedStuff))] | |
public class SegmentationDrawer : Editor | |
{ | |
private struct SerializedFloatArrayProperty | |
{ | |
public readonly SerializedProperty property; | |
public int arraySize => property.arraySize; | |
public SerializedFloatArrayProperty(SerializedProperty property) | |
{ | |
if(! property.isArray) throw new ArgumentException(); | |
this.property = property; | |
} | |
public void RemoveAt(int index) | |
{ | |
property.DeleteArrayElementAtIndex(index); | |
} | |
public void Insert(int index, float value) | |
{ | |
property.InsertArrayElementAtIndex(index); | |
property.GetArrayElementAtIndex(index).floatValue = value; | |
} | |
public float this[int index] | |
{ | |
get => property.GetArrayElementAtIndex(index).floatValue; | |
set => property.GetArrayElementAtIndex(index).floatValue = value; | |
} | |
} | |
private readonly List<Box> boxes = new List<Box>(); | |
private VisualElement root; | |
private SerializedFloatArrayProperty floatValues; | |
private void OnEnable() { | |
floatValues = new SerializedFloatArrayProperty(serializedObject.FindProperty("floatValues")); | |
float sum = 0.0f; | |
for (int i = 0; i < floatValues.arraySize; ++i) sum += floatValues[i]; | |
for (int i = 0; i < floatValues.arraySize; ++i) floatValues[i] /= sum; | |
} | |
private int separatorIndex; | |
private void AddSeparator(int index, VisualElement container) { | |
var separator = new Box(); | |
separator.AddToClassList("separator"); | |
void DragResize(MouseMoveEvent evt) { | |
var dx = evt.mouseDelta.x / container.contentRect.width; | |
var fx = Mathf.Min( floatValues[separatorIndex] + dx, 0); | |
fx = Mathf.Min(floatValues[separatorIndex+1] - dx, fx); | |
dx += fx * Mathf.Sign(dx); | |
floatValues[separatorIndex] += dx; | |
floatValues[separatorIndex+1] -= dx; | |
floatValues[separatorIndex] = Mathf.RoundToInt(floatValues[separatorIndex] * 1000) / 1000f; | |
floatValues[separatorIndex+1] = Mathf.RoundToInt(floatValues[separatorIndex+1] * 1000) / 1000f; | |
UpdateSizes(); | |
} | |
separator.RegisterCallback<MouseDownEvent>(evt => { | |
separatorIndex = index; | |
container.RegisterCallback<MouseMoveEvent>(DragResize); | |
}); | |
container.RegisterCallback<MouseUpEvent>(evt => { | |
separatorIndex = -1; | |
container.UnregisterCallback<MouseMoveEvent>(DragResize); | |
}); | |
container.RegisterCallback<MouseLeaveEvent>(evt => { | |
separatorIndex = -1; | |
container.UnregisterCallback<MouseMoveEvent>(DragResize); | |
}); | |
container.Add(separator); | |
} | |
private void UpdateSizes() { | |
float sum = 0.0f; | |
for (int i = 0; i < floatValues.arraySize; ++i) sum += floatValues[i]; | |
for (int i = 0; i < floatValues.arraySize; ++i) floatValues[i] /= sum; | |
if (boxes.Count != floatValues.arraySize) | |
{ | |
root.RemoveAt(0); | |
root.Insert(0, CreateContent()); | |
return; | |
} | |
for (var i = 0; i < boxes.Count; i++) { | |
boxes[i].style.flexGrow = floatValues[i]; | |
boxes[i].Q<Label>().text = $"{floatValues[i]:P}"; | |
} | |
if(serializedObject.targetObject != null) // can happen with multiple inspectors | |
serializedObject.ApplyModifiedProperties(); | |
} | |
VisualElement CreateContent() | |
{ | |
var container = new BindableElement(); | |
container.BindProperty(floatValues.property); | |
container.style.flexDirection = FlexDirection.Row; | |
boxes.Clear(); | |
for (int i = 0; i < floatValues.arraySize; ++i) { | |
var b = new Box(); | |
var l = new Label(string.Empty); | |
b.Add(l); | |
boxes.Add(b); | |
int j = i; | |
b.RegisterCallback<MouseDownEvent>(evt => { | |
if(evt.button != 0) return; | |
if (evt.shiftKey && !evt.ctrlKey) { | |
floatValues[j] /= 2; | |
floatValues.Insert(j, floatValues[j]); | |
root.RemoveAt(0); | |
root.Insert(0, CreateContent()); | |
} | |
if (!evt.shiftKey && evt.ctrlKey) { | |
if (floatValues.arraySize > 1) { | |
int n = j == 0 ? 1 : j - 1; | |
floatValues[n] += floatValues[j]; | |
floatValues.RemoveAt(j); | |
root.RemoveAt(0); | |
root.Insert(0, CreateContent()); | |
} | |
} | |
}); | |
} | |
UpdateSizes(); | |
container.Add(boxes[0]); | |
for (int i = 1; i < boxes.Count; ++i) { | |
AddSeparator(i - 1, container); | |
container.Add(boxes[i]); | |
} | |
return container; | |
} | |
public override VisualElement CreateInspectorGUI() | |
{ | |
root = new VisualElement(); | |
root.Bind(serializedObject); | |
root.styleSheets.Add(AssetDatabase.LoadAssetAtPath<StyleSheet>("Assets/_Gyms/SegmentationDrawer/Editor/SegmentationDrawerStyle.uss")); | |
root.Add(CreateContent()); | |
root.Add(new Label("Shift-Click to split segment in two")); | |
root.Add(new Label("Ctrl-Click to delete segment")); | |
var action = root.schedule.Execute(UpdateSizes); | |
action.Every(100); // ms | |
return root; | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using UnityEngine; | |
public class SegmentedStuff : MonoBehaviour { | |
public float[] floatValues = new []{1f, 1f, 1f}; // some default values, don't make it empty | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
.unity-box{ | |
height: 30; | |
flex-grow: 1; | |
flex-basis: 7; | |
justify-content: center; | |
} | |
.unity-box > Label{ | |
-unity-text-align: middle-center; | |
overflow: hidden; | |
font-size: 8; | |
} | |
.unity-box:hover{ | |
-unity-background-image-tint-color: #eeeeff; | |
} | |
.unity-box.separator{ | |
flex-grow: 0; | |
flex-basis: 7; | |
margin: 0 -3; | |
cursor: split-resize-left-right; | |
background-image: none; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment