Rasagar/Library/PackageCache/com.unity.terrain-tools/Editor/TerrainTools/Overlays/BrushAttributesOverlay.cs
2024-08-26 23:07:20 +03:00

1034 lines
43 KiB
C#

using UnityEditor.Overlays;
using UnityEditor.Toolbars;
using UnityEngine;
using UnityEngine.UIElements;
using UnityEditor.EditorTools;
using System;
using System.Reflection;
using System.Collections.Generic;
using System.Runtime.CompilerServices;
using Slider = UnityEngine.UIElements.Slider;
namespace UnityEditor.TerrainTools.UI
{
[Overlay(typeof(SceneView), "Brush Attributes", defaultDockPosition = DockPosition.Top, defaultDockZone = DockZone.TopToolbar)]
[Icon("Packages/com.unity.terrain-tools/Editor/Icons/TerrainOverlays/BrushSettingIcons/BrushAttributes.png")]
internal class BrushAttributesOverlay : ToolbarOverlay, ITransientOverlay
{
public bool visible
{
get
{
var currTool = BrushesOverlay.ActiveTerrainTool as TerrainPaintToolWithOverlaysBase;
if (currTool == null)
return false;
bool isTerrainToolPaintTool = currTool is ITerrainToolPaintTool;
return currTool.HasBrushAttributes && BrushesOverlay.IsSelectedObjectTerrain() && isTerrainToolPaintTool;
}
}
internal static BrushAttributesOverlay instance;
internal Dictionary<int, CondensedSlider> m_Attributes = new Dictionary<int, CondensedSlider>();
public static Layout activeToolbarLayout => instance.activeLayout;
public static string s_UssPath => "Styles/BrushPopup";
public static int popUpWidth = 200;
public static int popUpHeight = 50;
BrushAttributesOverlay() : base(
BrushOpacity.id,
BrushSize.id,
BrushRotation.id,
BrushSpacing.id,
BrushScattering.id)
{
if (instance != null)
{
instance.m_Attributes.Clear();
instance = null;
}
instance = this;
}
internal static void RegisterAttribute(CondensedSlider attr)
{
if (instance != null)
instance.m_Attributes.TryAdd(attr.contentLabel.GetHashCode(), attr);
}
internal static void RebuildContent()
{
if (instance != null)
{
foreach (var attr in instance.m_Attributes)
{
attr.Value.RebuildContent();
}
}
}
public static void AddBorder(EditorWindow window)
{
Color color = EditorGUIUtility.isProSkin
? new Color(0.44f, 0.44f, 0.44f, 1f)
: new Color(0.51f, 0.51f, 0.51f);
window.rootVisualElement.style.borderLeftWidth = (StyleFloat) 1f;
window.rootVisualElement.style.borderTopWidth = (StyleFloat) 1f;
window.rootVisualElement.style.borderRightWidth = (StyleFloat) 1f;
window.rootVisualElement.style.borderBottomWidth = (StyleFloat) 1f;
window.rootVisualElement.style.borderLeftColor = (StyleColor) color;
window.rootVisualElement.style.borderTopColor = (StyleColor) color;
window.rootVisualElement.style.borderRightColor = (StyleColor) color;
window.rootVisualElement.style.borderBottomColor = (StyleColor) color;
}
public static TerrainPaintToolWithOverlaysBase GetActiveOverlaysTool()
{
var tool = BrushesOverlay.ActiveTerrainTool as TerrainPaintToolWithOverlaysBase;
if (!tool) return null;
if (!Selection.activeGameObject) return null;
if (!tool.Terrain)
{
if (Selection.activeGameObject == null || Selection.activeGameObject.GetComponent<Terrain>() == null) return null; // check when loading and unloading packages
tool.Terrain = Selection.activeGameObject.GetComponent<Terrain>();
}
if (!tool.Terrain)
{
Debug.LogError("Tool does NOT have associated terrain");
return null;
}
return tool;
}
public static IBrushUIGroup GetCommonUI()
{
// get commonUI
var tool = GetActiveOverlaysTool();
if (!tool) return null;
Type type = tool.GetType();
MethodInfo func = type.GetMethod("get_m_commonUI");
if (func == null) return null; // avoid null errors
IBrushUIGroup commonUI = (IBrushUIGroup) func.Invoke(tool, null);
return commonUI;
}
}
// brush attributes (opacity, size, rotation, spacing, scattering) -------
// BRUSH OPACITY
[EditorToolbarElement(id, typeof(SceneView))]
internal class BrushOpacity : CondensedSliderDropdown
{
internal const string id = "Brushes/OpacityPackage";
private const string label = "Opacity";
private static float minValue
{
get
{
var commonUI = BrushAttributesOverlay.GetCommonUI();
if (commonUI == null) return 0f;
return commonUI.brushStrengthMin;
}
}
private static float maxValue
{
get
{
var commonUI = BrushAttributesOverlay.GetCommonUI();
if (commonUI == null) return 1f;
return commonUI.brushStrengthMax;
}
}
static Texture2D s_OpacityIcon;
static Texture2D Texture
{
get
{
if(s_OpacityIcon == null)
s_OpacityIcon = (Texture2D)AssetDatabase.LoadAssetAtPath("Packages/com.unity.terrain-tools/Editor/Icons/TerrainOverlays/BrushSettingIcons/Opacity.png", typeof(Texture2D));
return s_OpacityIcon;
}
}
public void UpdateOverlayDirection(Layout l)
{
DropdownUpdateDirection(BrushAttributesOverlay.activeToolbarLayout == Layout.VerticalToolbar ? SliderDirection.Vertical : SliderDirection.Horizontal, null, minValue, maxValue);
labelFormatting = (f, s, d) =>
{
if (direction == SliderDirection.Vertical)
return $"{f:F2}";
return $"{s} {f:F2}";
};
clicked += () => OpenPopup(CreatePopUp(), BrushAttributesOverlay.popUpWidth, BrushAttributesOverlay.popUpHeight);
UpdateValues();
}
public void UpdateOverlayDirection(bool collapsedChanged)
{
DropdownUpdateDirection(BrushAttributesOverlay.activeToolbarLayout == Layout.VerticalToolbar ? SliderDirection.Vertical : SliderDirection.Horizontal, null, minValue, maxValue);
labelFormatting = (f, s, d) =>
{
if (direction == SliderDirection.Vertical)
return $"{f:F2}";
return $"{s} {f:F2}";
};
clicked += () => OpenPopup(CreatePopUp(), BrushAttributesOverlay.popUpWidth, BrushAttributesOverlay.popUpHeight);
UpdateValues();
}
// On first install of the package, need to rebuild the attribute UI after
// assets have been loaded. So this function implements a reconstruction path, essentially all the same
// steps as if you step through all the constructors
internal override void RebuildContent()
{
RebuildContent(Texture, minValue, maxValue);
ConstructDropdown(null, BrushAttributesOverlay.instance.layout == Layout.VerticalToolbar ? SliderDirection.Vertical : SliderDirection.Horizontal);
UpdateOverlayDirection(true);
SetContentWidth();
UpdateValues();
}
public BrushOpacity()
: base(label, Texture, minValue, maxValue, null, BrushAttributesOverlay.instance.layout == Layout.VerticalToolbar ? SliderDirection.Vertical : SliderDirection.Horizontal)
{
BrushAttributesOverlay.RegisterAttribute(this);
labelFormatting = (f, s, d) =>
{
if (direction == SliderDirection.Vertical)
return $"{f:F2}";
return $"{s} {f:F2}";
};
void UpdateMin()
{
var commonUI = BrushAttributesOverlay.GetCommonUI();
if (commonUI == null) return;
SetLowValueWithoutNotify(commonUI.brushStrengthMin);
}
void UpdateMax()
{
var commonUI = BrushAttributesOverlay.GetCommonUI();
if (commonUI == null) return;
SetHighValueWithoutNotify(commonUI.brushStrengthMax);
}
UpdateOverlayDirection(true);
RegisterCallback<AttachToPanelEvent>(e =>
{
ToolManager.activeToolChanged += UpdateValues;
ToolManager.activeContextChanged += UpdateValues;
BrushAttributesOverlay.instance.layoutChanged += UpdateOverlayDirection;
BrushAttributesOverlay.instance.collapsedChanged += UpdateOverlayDirection;
BrushStrengthVariator.BrushStrengthChanged += UpdateValues;
BrushStrengthVariator.BrushStrengthMinChanged += UpdateMin;
BrushStrengthVariator.BrushStrengthMaxChanged += UpdateMax;
});
this.RegisterValueChangedCallback(e =>
{
var commonUI = BrushAttributesOverlay.GetCommonUI();
if (commonUI == null) return;
commonUI.brushStrength = e.newValue;
});
RegisterCallback<DetachFromPanelEvent>(e =>
{
ToolManager.activeToolChanged -= UpdateValues;
ToolManager.activeContextChanged -= UpdateValues;
BrushAttributesOverlay.instance.layoutChanged -= UpdateOverlayDirection;
BrushAttributesOverlay.instance.collapsedChanged -= UpdateOverlayDirection;
BrushStrengthVariator.BrushStrengthChanged -= UpdateValues;
BrushStrengthVariator.BrushStrengthMinChanged -= UpdateMin;
BrushStrengthVariator.BrushStrengthMaxChanged -= UpdateMax;
});
SetContentWidth();
clicked += () => OpenPopup(CreatePopUp(), BrushAttributesOverlay.popUpWidth, BrushAttributesOverlay.popUpHeight);
UpdateValues();
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private void SetContentWidth()
{
if (direction == SliderDirection.Horizontal)
contentWidth = 100;
}
private void UpdateValues()
{
var commonUI = BrushAttributesOverlay.GetCommonUI();
if (commonUI == null) return;
style.display = commonUI.hasBrushStrength ? DisplayStyle.Flex : DisplayStyle.None;
if (!commonUI.hasBrushStrength) return;
value = commonUI.brushStrengthVal;
}
private VisualElement CreatePopUp()
{
var opacityContainer = new VisualElement();
StyleSheet styleSheet = (StyleSheet)AssetDatabase.LoadAssetAtPath("Packages/com.unity.terrain-tools/Editor/Style/BrushPopup.uss", typeof(StyleSheet));
if (styleSheet) opacityContainer.styleSheets.Add(styleSheet);
// add min/max slider
var opacityMinMaxContainer = new VisualElement();
opacityMinMaxContainer.style.flexDirection = FlexDirection.Row;
opacityContainer.Add(opacityMinMaxContainer);
var opacityMinText = new TextElement();
opacityMinText.text = "Min";
opacityMinMaxContainer.Add(opacityMinText);
var opacityMinField = new FloatField();
opacityMinMaxContainer.Add(opacityMinField);
var opacityMaxText = new TextElement();
opacityMaxText.text = "Max";
opacityMinMaxContainer.Add(opacityMaxText);
var opacityMaxField = new FloatField();
opacityMinMaxContainer.Add(opacityMaxField);
// add jitter slider
var opacityJitterContainer = new VisualElement();
opacityJitterContainer.style.flexDirection = FlexDirection.Row;
opacityContainer.Add(opacityJitterContainer);
var jitter = new Slider("Jitter", 0f, 1f);
jitter.style.flexGrow = 1;
opacityJitterContainer.Add(jitter);
var opacityJitterTextField = new FloatField();
opacityJitterContainer.Add(opacityJitterTextField);
opacityMinField.RegisterValueChangedCallback(e =>
{
var commonUI = BrushAttributesOverlay.GetCommonUI();
if (commonUI == null) return;
commonUI.brushStrengthMin = e.newValue;
if (commonUI.brushStrengthMin > commonUI.brushStrengthMax)
{
commonUI.brushStrengthMax = e.newValue;
opacityMaxField.value = e.newValue;
SetHighValueWithoutNotify(e.newValue);
}
SetLowValueWithoutNotify(e.newValue);
});
opacityMaxField.RegisterValueChangedCallback(e =>
{
var commonUI = BrushAttributesOverlay.GetCommonUI();
if (commonUI == null) return;
commonUI.brushStrengthMax = e.newValue;
if (commonUI.brushStrengthMax < commonUI.brushStrengthMin)
{
commonUI.brushStrengthMin = e.newValue;
opacityMinField.value = e.newValue;
SetLowValueWithoutNotify(e.newValue);
}
SetHighValueWithoutNotify(e.newValue);
});
jitter.RegisterValueChangedCallback(e =>
{
var commonUI = BrushAttributesOverlay.GetCommonUI();
if (commonUI == null) return;
commonUI.brushStrengthJitter = e.newValue;
opacityJitterTextField.SetValueWithoutNotify(e.newValue);
});
opacityJitterTextField.RegisterValueChangedCallback(e =>
{
var commonUI = BrushAttributesOverlay.GetCommonUI();
if (commonUI == null) return;
commonUI.brushStrengthJitter = e.newValue;
jitter.SetValueWithoutNotify(e.newValue);
});
var commonUI = BrushAttributesOverlay.GetCommonUI();
if (commonUI == null) Debug.LogWarning("cannot display STRENGTH in BrushAttributesOverlay.CS in PACKAGE");
// NOTE: when I set values, I am setting them to commonUI.brushStrengthVal rather than commonUI.brushStrength
// this is because commonUI.brushStrengthVal gives the raw brush strength, where as commonUI.brushStrength uses
// a getter which calculates the jitter, which I don't want to display in the UI
// this is also true for size (commonUI.brushSizeVal) and rotation (commonUI.brushRotationVal)
opacityMinField.value = commonUI.brushStrengthMin;
opacityMaxField.value = commonUI.brushStrengthMax;
jitter.value = commonUI.brushStrengthJitter;
opacityJitterTextField.value = commonUI.brushStrengthJitter;
return opacityContainer;
}
private void OpenPopup(VisualElement popup, float width, float height)
{
var window = ScriptableObject.CreateInstance<EditorWindow>();
BrushAttributesOverlay.AddBorder(window);
window.rootVisualElement.Add(popup);
window.ShowAsDropDown(GUIUtility.GUIToScreenRect(worldBound), new Vector2(width, height));
}
}
// BRUSH SIZE
[EditorToolbarElement(id, typeof(SceneView))]
internal class BrushSize : CondensedSliderDropdown
{
internal const string id = "Brushes/SizePackage";
private const string label = "Size";
private static float minValue
{
get
{
var commonUI = BrushAttributesOverlay.GetCommonUI();
if (commonUI == null) return 0f;
return commonUI.brushSizeMin;
}
}
private static float maxValue
{
get
{
var commonUI = BrushAttributesOverlay.GetCommonUI();
if (commonUI == null) return 500f;
return commonUI.brushSizeMax;
}
}
static Texture2D s_SizeIcon;
static Texture2D Texture
{
get
{
if(s_SizeIcon == null)
s_SizeIcon = (Texture2D)AssetDatabase.LoadAssetAtPath("Packages/com.unity.terrain-tools/Editor/Icons/TerrainOverlays/BrushSettingIcons/Size.png", typeof(Texture2D));
return s_SizeIcon;
}
}
public void UpdateOverlayDirection(Layout l)
{
DropdownUpdateDirection(BrushAttributesOverlay.activeToolbarLayout == Layout.VerticalToolbar ? SliderDirection.Vertical : SliderDirection.Horizontal, null, minValue, maxValue);
labelFormatting = (f, s, d) =>
{
if (direction == SliderDirection.Vertical)
return $"{f:F2}";
return $"{s} {f:F2}";
};
clicked += () => OpenPopup(CreatePopUp(), BrushAttributesOverlay.popUpWidth, BrushAttributesOverlay.popUpHeight);
UpdateValues();
}
public void UpdateOverlayDirection(bool collapsedChanged)
{
DropdownUpdateDirection(BrushAttributesOverlay.activeToolbarLayout == Layout.VerticalToolbar ? SliderDirection.Vertical : SliderDirection.Horizontal, null, minValue, maxValue);
labelFormatting = (f, s, d) =>
{
if (direction == SliderDirection.Vertical)
return $"{f:F2}";
return $"{s} {f:F2}";
};
clicked += () => OpenPopup(CreatePopUp(), BrushAttributesOverlay.popUpWidth, BrushAttributesOverlay.popUpHeight);
UpdateValues();
}
// On first install of the package, need to rebuild the attribute UI after
// assets have been loaded. So this function implements a reconstruction path, essentially all the same
// steps as if you step through all the constructors
internal override void RebuildContent()
{
RebuildContent(Texture, minValue, maxValue);
ConstructDropdown(null, BrushAttributesOverlay.instance.layout == Layout.VerticalToolbar ? SliderDirection.Vertical : SliderDirection.Horizontal);
UpdateOverlayDirection(true);
SetContentWidth();
UpdateValues();
}
public BrushSize()
: base(label, Texture, minValue, maxValue, null, BrushAttributesOverlay.instance.layout == Layout.VerticalToolbar ? SliderDirection.Vertical : SliderDirection.Horizontal)
{
BrushAttributesOverlay.RegisterAttribute(this);
labelFormatting = (f, s, d) =>
{
if (direction == SliderDirection.Vertical)
return $"{f:F2}";
return $"{s} {f:F2}";
};
void UpdateMin()
{
var commonUI = BrushAttributesOverlay.GetCommonUI();
if (commonUI == null) return;
SetLowValueWithoutNotify(commonUI.brushSizeMin);
}
void UpdateMax()
{
var commonUI = BrushAttributesOverlay.GetCommonUI();
if (commonUI == null) return;
SetHighValueWithoutNotify(commonUI.brushSizeMax);
}
UpdateOverlayDirection(true);
RegisterCallback<AttachToPanelEvent>(e =>
{
ToolManager.activeToolChanged += UpdateValues;
ToolManager.activeContextChanged += UpdateValues;
BrushAttributesOverlay.instance.layoutChanged += UpdateOverlayDirection;
BrushAttributesOverlay.instance.collapsedChanged += UpdateOverlayDirection;
BrushSizeVariator.BrushSizeChanged += UpdateValues;
BrushSizeVariator.BrushSizeMinChanged += UpdateMin;
BrushSizeVariator.BrushSizeMaxChanged += UpdateMax;
});
this.RegisterValueChangedCallback(e =>
{
var commonUI = BrushAttributesOverlay.GetCommonUI();
if (commonUI == null) return;
commonUI.brushSize = e.newValue;
});
RegisterCallback<DetachFromPanelEvent>(e =>
{
ToolManager.activeToolChanged -= UpdateValues;
ToolManager.activeContextChanged -= UpdateValues;
BrushAttributesOverlay.instance.layoutChanged -= UpdateOverlayDirection;
BrushAttributesOverlay.instance.collapsedChanged -= UpdateOverlayDirection;
BrushSizeVariator.BrushSizeChanged -= UpdateValues;
BrushSizeVariator.BrushSizeMinChanged -= UpdateMin;
BrushSizeVariator.BrushSizeMaxChanged -= UpdateMax;
});
SetContentWidth();
clicked += () => OpenPopup(CreatePopUp(), BrushAttributesOverlay.popUpWidth, BrushAttributesOverlay.popUpHeight);
UpdateValues();
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
void SetContentWidth()
{
if (direction == SliderDirection.Horizontal)
contentWidth = 100;
}
private void UpdateValues()
{
var commonUI = BrushAttributesOverlay.GetCommonUI();
if (commonUI == null) return;
style.display = commonUI.hasBrushSize ? DisplayStyle.Flex : DisplayStyle.None;
if (!commonUI.hasBrushSize) return;
value = commonUI.brushSizeVal;
}
private VisualElement CreatePopUp()
{
var sizeContainer = new VisualElement();
StyleSheet styleSheet = (StyleSheet)AssetDatabase.LoadAssetAtPath("Packages/com.unity.terrain-tools/Editor/Style/BrushPopup.uss", typeof(StyleSheet));
if (styleSheet) sizeContainer.styleSheets.Add(styleSheet);
// add min/max slider
var sizeMinMaxContainer = new VisualElement();
sizeMinMaxContainer.style.flexDirection = FlexDirection.Row;
sizeContainer.Add(sizeMinMaxContainer);
var sizeMinText = new TextElement();
sizeMinText.text = "Min";
sizeMinMaxContainer.Add(sizeMinText);
var sizeMinField = new FloatField();
sizeMinMaxContainer.Add(sizeMinField);
var sizeMaxText = new TextElement();
sizeMaxText.text = "Max";
sizeMinMaxContainer.Add(sizeMaxText);
var sizeMaxField = new FloatField();
sizeMinMaxContainer.Add(sizeMaxField);
// add jitter slider
var sizeJitterContainer = new VisualElement();
sizeJitterContainer.style.flexDirection = FlexDirection.Row;
sizeContainer.Add(sizeJitterContainer);
var jitter = new Slider("Jitter", 0f, 1f);
jitter.style.flexGrow = 1;
sizeJitterContainer.Add(jitter);
var sizeJitterTextField = new FloatField();
sizeJitterContainer.Add(sizeJitterTextField);
sizeMinField.RegisterValueChangedCallback(e =>
{
var commonUI = BrushAttributesOverlay.GetCommonUI();
if (commonUI == null) return;
commonUI.brushSizeMin = e.newValue;
if (commonUI.brushSizeMin > commonUI.brushSizeMax)
{
commonUI.brushSizeMax = e.newValue;
sizeMaxField.value = e.newValue;
SetHighValueWithoutNotify(e.newValue);
}
SetLowValueWithoutNotify(e.newValue);
});
sizeMaxField.RegisterValueChangedCallback(e =>
{
var commonUI = BrushAttributesOverlay.GetCommonUI();
if (commonUI == null) return;
commonUI.brushSizeMax = e.newValue;
if (commonUI.brushSizeMax < commonUI.brushSizeMin)
{
commonUI.brushSizeMax = e.newValue;
sizeMinField.value = e.newValue;
SetLowValueWithoutNotify(e.newValue);
}
SetHighValueWithoutNotify(e.newValue);
});
jitter.RegisterValueChangedCallback(e =>
{
var commonUI = BrushAttributesOverlay.GetCommonUI();
if (commonUI == null) return;
commonUI.brushSizeJitter = e.newValue;
sizeJitterTextField.SetValueWithoutNotify(e.newValue);
});
sizeJitterTextField.RegisterValueChangedCallback(e =>
{
var commonUI = BrushAttributesOverlay.GetCommonUI();
if (commonUI == null) return;
commonUI.brushSizeJitter = e.newValue;
jitter.SetValueWithoutNotify(e.newValue);
});
var commonUI = BrushAttributesOverlay.GetCommonUI();
if (commonUI == null) Debug.LogWarning("cannot display SIZE in BrushAttributesOverlay.CS in PACKAGE");
sizeMinField.value = commonUI.brushSizeMin;
sizeMaxField.value = commonUI.brushSizeMax;
jitter.value = commonUI.brushSizeJitter;
sizeJitterTextField.value = commonUI.brushSizeJitter;
return sizeContainer;
}
private void OpenPopup(VisualElement popup, float width, float height)
{
var window = ScriptableObject.CreateInstance<EditorWindow>();
BrushAttributesOverlay.AddBorder(window);
window.rootVisualElement.Add(popup);
window.ShowAsDropDown(GUIUtility.GUIToScreenRect(worldBound), new Vector2(width, height));
}
}
// BRUSH ROTATION
[EditorToolbarElement(id, typeof(SceneView))]
internal class BrushRotation : CondensedSliderDropdown
{
internal const string id = "Brushes/RotationPackage";
private const string label = "Rotation";
private const float minValue = -180;
private const float maxValue = 180;
static Texture2D s_RotationIcon;
static Texture2D Texture
{
get
{
if(s_RotationIcon == null)
s_RotationIcon = (Texture2D)AssetDatabase.LoadAssetAtPath("Packages/com.unity.terrain-tools/Editor/Icons/TerrainOverlays/BrushSettingIcons/Rotation.png", typeof(Texture2D));
return s_RotationIcon;
}
}
public void UpdateOverlayDirection(Layout l)
{
DropdownUpdateDirection(BrushAttributesOverlay.activeToolbarLayout == Layout.VerticalToolbar ? SliderDirection.Vertical : SliderDirection.Horizontal, null, minValue, maxValue);
labelFormatting = (f, s, d) =>
{
if (direction == SliderDirection.Vertical)
return $"{f:F2}";
return $"{s} {f:F2}";
};
clicked += () => OpenPopup(CreatePopUp(), BrushAttributesOverlay.popUpWidth, BrushAttributesOverlay.popUpHeight);
UpdateValues();
}
public void UpdateOverlayDirection(bool collapsedChanged)
{
DropdownUpdateDirection(BrushAttributesOverlay.activeToolbarLayout == Layout.VerticalToolbar ? SliderDirection.Vertical : SliderDirection.Horizontal, null, minValue, maxValue);
labelFormatting = (f, s, d) =>
{
if (direction == SliderDirection.Vertical)
return $"{f:F2}";
return $"{s} {f:F2}";
};
clicked += () => OpenPopup(CreatePopUp(), BrushAttributesOverlay.popUpWidth, BrushAttributesOverlay.popUpHeight);
UpdateValues();
}
// On first install of the package, need to rebuild the attribute UI after
// assets have been loaded. So this function implements a reconstruction path, essentially all the same
// steps as if you step through all the constructors
internal override void RebuildContent()
{
RebuildContent(Texture, minValue, maxValue);
ConstructDropdown(null, BrushAttributesOverlay.instance.layout == Layout.VerticalToolbar ? SliderDirection.Vertical : SliderDirection.Horizontal);
UpdateOverlayDirection(true);
SetContentWidth();
UpdateValues();
}
public BrushRotation()
: base(label, Texture, minValue, maxValue, null, BrushAttributesOverlay.instance.layout == Layout.VerticalToolbar ? SliderDirection.Vertical : SliderDirection.Horizontal)
{
BrushAttributesOverlay.RegisterAttribute(this);
labelFormatting = (f, s, d) =>
{
if (direction == SliderDirection.Vertical)
return $"{f:F2}";
return $"{s} {f:F2}";
};
UpdateOverlayDirection(true);
RegisterCallback<AttachToPanelEvent>(e =>
{
ToolManager.activeToolChanged += UpdateValues;
ToolManager.activeContextChanged += UpdateValues;
BrushAttributesOverlay.instance.layoutChanged += UpdateOverlayDirection;
BrushAttributesOverlay.instance.collapsedChanged += UpdateOverlayDirection;
BrushRotationVariator.BrushRotationChanged += UpdateValues;
});
this.RegisterValueChangedCallback(e =>
{
var commonUI = BrushAttributesOverlay.GetCommonUI();
if (commonUI == null) return;
commonUI.brushRotation = e.newValue;
});
RegisterCallback<DetachFromPanelEvent>(e =>
{
ToolManager.activeToolChanged -= UpdateValues;
ToolManager.activeContextChanged -= UpdateValues;
BrushAttributesOverlay.instance.layoutChanged -= UpdateOverlayDirection;
BrushAttributesOverlay.instance.collapsedChanged -= UpdateOverlayDirection;
BrushRotationVariator.BrushRotationChanged -= UpdateValues;
});
SetContentWidth();
clicked += () => OpenPopup(CreatePopUp(), BrushAttributesOverlay.popUpWidth, BrushAttributesOverlay.popUpHeight);
UpdateValues();
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private void SetContentWidth()
{
if (direction == SliderDirection.Horizontal)
contentWidth = 120;
}
private void UpdateValues()
{
var commonUI = BrushAttributesOverlay.GetCommonUI();
if (commonUI == null) return;
style.display = commonUI.hasBrushRotation ? DisplayStyle.Flex : DisplayStyle.None;
if (!commonUI.hasBrushRotation) return;
value = commonUI.brushRotationVal;
}
private VisualElement CreatePopUp()
{
var rotationContainer = new VisualElement();
StyleSheet styleSheet = (StyleSheet)AssetDatabase.LoadAssetAtPath("Packages/com.unity.terrain-tools/Editor/Style/BrushPopup.uss", typeof(StyleSheet));
if (styleSheet) rotationContainer.styleSheets.Add(styleSheet);
// add jitter slider
var rotationJitterContainer = new VisualElement();
rotationJitterContainer.style.flexDirection = FlexDirection.Row;
rotationContainer.Add(rotationJitterContainer);
var jitter = new Slider("Jitter", 0f, 1f);
jitter.style.flexGrow = 1;
rotationJitterContainer.Add(jitter);
var rotationJitterTextField = new FloatField();
rotationJitterContainer.Add(rotationJitterTextField);
jitter.RegisterValueChangedCallback(e =>
{
var commonUI = BrushAttributesOverlay.GetCommonUI();
if (commonUI == null) return;
commonUI.brushRotationJitter = e.newValue;
rotationJitterTextField.SetValueWithoutNotify(e.newValue);
});
rotationJitterTextField.RegisterValueChangedCallback(e =>
{
var commonUI = BrushAttributesOverlay.GetCommonUI();
if (commonUI == null) return;
commonUI.brushRotationJitter = e.newValue;
jitter.SetValueWithoutNotify(e.newValue);
});
var commonUI = BrushAttributesOverlay.GetCommonUI();
if (commonUI == null) Debug.LogWarning("cannot display ROTATION in BrushAttributesOverlay.CS in PACKAGE");
jitter.value = commonUI.brushRotationJitter;
rotationJitterTextField.value = commonUI.brushRotationJitter;
return rotationContainer;
}
private void OpenPopup(VisualElement popup, float width, float height)
{
var window = ScriptableObject.CreateInstance<EditorWindow>();
BrushAttributesOverlay.AddBorder(window);
window.rootVisualElement.Add(popup);
window.ShowAsDropDown(GUIUtility.GUIToScreenRect(worldBound), new Vector2(width, height));
}
}
// BRUSH SPACING
[EditorToolbarElement(id, typeof(SceneView))]
internal class BrushSpacing : CondensedSlider
{
internal const string id = "Brushes/SpacingPackage";
private const string label = "Spacing";
private const float minValue = 0;
private const float maxValue = 100;
private const float offset = 100;
static Texture2D s_SpacingIcon;
static Texture2D Texture
{
get
{
if(s_SpacingIcon == null)
s_SpacingIcon = (Texture2D)AssetDatabase.LoadAssetAtPath("Packages/com.unity.terrain-tools/Editor/Icons/TerrainOverlays/BrushSettingIcons/Spacing.png", typeof(Texture2D));
return s_SpacingIcon;
}
}
public void UpdateOverlayDirection(Layout l)
{
UpdateDirection(BrushAttributesOverlay.activeToolbarLayout == Layout.VerticalToolbar ? SliderDirection.Vertical : SliderDirection.Horizontal, minValue, maxValue);
labelFormatting = (f, s, d) =>
{
if (direction == SliderDirection.Vertical)
return $"{f:F2}";
return $"{s} {f:F2}";
};
UpdateValues();
}
public void UpdateOverlayDirection(bool collapsedChanged)
{
UpdateDirection(BrushAttributesOverlay.activeToolbarLayout == Layout.VerticalToolbar ? SliderDirection.Vertical : SliderDirection.Horizontal, minValue, maxValue);
labelFormatting = (f, s, d) =>
{
if (direction == SliderDirection.Vertical)
return $"{f:F2}";
return $"{s} {f:F2}";
};
UpdateValues();
}
// On first install of the package, need to rebuild the attribute UI after
// assets have been loaded. So this function implements a reconstruction path, essentially all the same
// steps as if you step through all the constructors
internal override void RebuildContent()
{
RebuildContent(Texture, minValue, maxValue);
UpdateOverlayDirection(true);
SetContentWidth();
UpdateValues();
}
public BrushSpacing()
: base(label, Texture, minValue, maxValue, BrushAttributesOverlay.instance.layout == Layout.VerticalToolbar ? SliderDirection.Vertical : SliderDirection.Horizontal)
{
BrushAttributesOverlay.RegisterAttribute(this);
labelFormatting = (f, s, d) =>
{
if (direction == SliderDirection.Vertical)
return $"{f:F2}";
return $"{s} {f:F2}";
};
UpdateOverlayDirection(true);
RegisterCallback<AttachToPanelEvent>(e =>
{
ToolManager.activeToolChanged += UpdateValues;
ToolManager.activeContextChanged += UpdateValues;
BrushAttributesOverlay.instance.layoutChanged += UpdateOverlayDirection;
BrushAttributesOverlay.instance.collapsedChanged += UpdateOverlayDirection;
BrushSpacingVariator.BrushSpacingChanged += UpdateValues;
});
this.RegisterValueChangedCallback(e =>
{
var commonUI = BrushAttributesOverlay.GetCommonUI();
if (commonUI == null) return;
commonUI.brushSpacing = e.newValue / offset;
});
RegisterCallback<DetachFromPanelEvent>(e =>
{
ToolManager.activeToolChanged -= UpdateValues;
ToolManager.activeContextChanged -= UpdateValues;
BrushAttributesOverlay.instance.layoutChanged -= UpdateOverlayDirection;
BrushAttributesOverlay.instance.collapsedChanged -= UpdateOverlayDirection;
BrushSpacingVariator.BrushSpacingChanged -= UpdateValues;
});
SetContentWidth();
UpdateValues();
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private void SetContentWidth()
{
if (direction == SliderDirection.Horizontal)
contentWidth = 118;
}
private void UpdateValues()
{
var commonUI = BrushAttributesOverlay.GetCommonUI();
if (commonUI == null) return;
style.display = commonUI.hasBrushSpacing ? DisplayStyle.Flex : DisplayStyle.None;
if (!commonUI.hasBrushSpacing) return;
value = commonUI.brushSpacing * offset;
}
}
// BRUSH SCATTERING
[EditorToolbarElement(id, typeof(SceneView))]
internal class BrushScattering : CondensedSlider
{
internal const string id = "Brushes/ScatteringPackage";
private const string label = "Scattering";
private const float minValue = 0;
private const float maxValue = 100;
private const float offset = 100;
static Texture2D s_ScatteringIcon;
static Texture2D Texture
{
get
{
if (s_ScatteringIcon == null)
s_ScatteringIcon = (Texture2D)AssetDatabase.LoadAssetAtPath("Packages/com.unity.terrain-tools/Editor/Icons/TerrainOverlays/BrushSettingIcons/Scattering.png", typeof(Texture2D));
return s_ScatteringIcon;
}
}
public void UpdateOverlayDirection(Layout l)
{
UpdateDirection(BrushAttributesOverlay.activeToolbarLayout == Layout.VerticalToolbar ? SliderDirection.Vertical : SliderDirection.Horizontal, minValue, maxValue);
labelFormatting = (f, s, d) =>
{
if (direction == SliderDirection.Vertical)
return $"{f:F2}";
return $"{s} {f:F2}";
};
UpdateValues();
}
public void UpdateOverlayDirection(bool collapsedChanged)
{
UpdateDirection(BrushAttributesOverlay.activeToolbarLayout == Layout.VerticalToolbar ? SliderDirection.Vertical : SliderDirection.Horizontal, minValue, maxValue);
labelFormatting = (f, s, d) =>
{
if (direction == SliderDirection.Vertical)
return $"{f:F2}";
return $"{s} {f:F2}";
};
UpdateValues();
}
// On first install of the package, need to rebuild the attribute UI after
// assets have been loaded. So this function implements a reconstruction path, essentially all the same
// steps as if you step through all the constructors
internal override void RebuildContent()
{
RebuildContent(Texture, minValue, maxValue);
UpdateOverlayDirection(true);
SetContentWidth();
UpdateValues();
}
public BrushScattering()
: base(label, Texture, minValue, maxValue, BrushAttributesOverlay.instance.layout == Layout.VerticalToolbar ? SliderDirection.Vertical : SliderDirection.Horizontal)
{
BrushAttributesOverlay.RegisterAttribute(this);
labelFormatting = (f, s, d) =>
{
if (direction == SliderDirection.Vertical)
return $"{f:F2}";
return $"{s} {f:F2}";
};
UpdateOverlayDirection(true);
RegisterCallback<AttachToPanelEvent>(e =>
{
ToolManager.activeToolChanged += UpdateValues;
ToolManager.activeContextChanged += UpdateValues;
BrushAttributesOverlay.instance.layoutChanged += UpdateOverlayDirection;
BrushAttributesOverlay.instance.collapsedChanged += UpdateOverlayDirection;
BrushScatterVariator.BrushScatterChanged += UpdateValues;
});
this.RegisterValueChangedCallback(e =>
{
var commonUI = BrushAttributesOverlay.GetCommonUI();
if (commonUI == null) return;
commonUI.brushScatter = e.newValue / offset;
});
RegisterCallback<DetachFromPanelEvent>(e =>
{
ToolManager.activeToolChanged -= UpdateValues;
ToolManager.activeContextChanged -= UpdateValues;
BrushAttributesOverlay.instance.layoutChanged -= UpdateOverlayDirection;
BrushAttributesOverlay.instance.collapsedChanged -= UpdateOverlayDirection;
BrushScatterVariator.BrushScatterChanged -= UpdateValues;
});
SetContentWidth();
UpdateValues();
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private void SetContentWidth()
{
if (direction == SliderDirection.Horizontal)
contentWidth = 130;
}
private void UpdateValues()
{
var commonUI = BrushAttributesOverlay.GetCommonUI();
if (commonUI == null) return;
style.display = commonUI.hasBrushScatter ? DisplayStyle.Flex : DisplayStyle.None;
if (!commonUI.hasBrushScatter) return;
value = commonUI.brushScatter * offset;
}
}
}