diff --git a/Source/Editor/CustomEditors/Editors/ActorTransformEditor.cs b/Source/Editor/CustomEditors/Editors/ActorTransformEditor.cs index f65bb4b06..ac520fd7a 100644 --- a/Source/Editor/CustomEditors/Editors/ActorTransformEditor.cs +++ b/Source/Editor/CustomEditors/Editors/ActorTransformEditor.cs @@ -1,6 +1,7 @@ // Copyright (c) 2012-2023 Wojciech Figat. All rights reserved. using FlaxEngine; +using FlaxEngine.GUI; namespace FlaxEditor.CustomEditors.Editors { @@ -77,10 +78,33 @@ namespace FlaxEditor.CustomEditors.Editors /// public class ScaleEditor : Float3Editor { + + private Image _linkImage; + /// public override void Initialize(LayoutElementsContainer layout) { base.Initialize(layout); + + LinkValues = Editor.Instance.Windows.PropertiesWin.ScaleLinked; + + _linkImage = new Image + { + Parent = LinkedLabel, + Width = 18, + Height = 18, + Brush = LinkValues ? new SpriteBrush(Editor.Instance.Icons.Link32) : new SpriteBrush(), + AnchorPreset = AnchorPresets.TopLeft, + TooltipText = "Scale values are linked together.", + }; + _linkImage.LocalX += 40; + _linkImage.LocalY += 1; + + LinkedLabel.SetupContextMenu += (label, menu, editor) => + { + menu.AddSeparator(); + menu.AddButton(LinkValues ? "Unlink" : "Link", ToggleLink); + }; // Override colors var back = FlaxEngine.GUI.Style.Current.TextBoxBackground; @@ -92,6 +116,16 @@ namespace FlaxEditor.CustomEditors.Editors ZElement.ValueBox.BorderColor = Color.Lerp(AxisColorZ, back, grayOutFactor); ZElement.ValueBox.BorderSelectedColor = AxisColorZ; } + + /// + /// Toggles the linking functionality. + /// + public void ToggleLink() + { + LinkValues = !LinkValues; + Editor.Instance.Windows.PropertiesWin.ScaleLinked = LinkValues; + _linkImage.Brush = LinkValues ? new SpriteBrush(Editor.Instance.Icons.Link32) : new SpriteBrush(); + } } } } diff --git a/Source/Editor/CustomEditors/Editors/Vector3Editor.cs b/Source/Editor/CustomEditors/Editors/Vector3Editor.cs index 8ea21e988..ad67a4b13 100644 --- a/Source/Editor/CustomEditors/Editors/Vector3Editor.cs +++ b/Source/Editor/CustomEditors/Editors/Vector3Editor.cs @@ -44,6 +44,20 @@ namespace FlaxEditor.CustomEditors.Editors /// public override DisplayStyle Style => DisplayStyle.Inline; + /// + /// If true, when one value is changed, the other 2 will change as well. + /// + public bool LinkValues = false; + + private enum ValueChanged + { + X = 0, + Y = 1, + Z = 2 + } + + private ValueChanged _valueChanged; + /// public override void Initialize(LayoutElementsContainer layout) { @@ -63,28 +77,87 @@ namespace FlaxEditor.CustomEditors.Editors XElement = grid.FloatValue(); XElement.SetLimits(limit); - XElement.ValueBox.ValueChanged += OnValueChanged; + XElement.ValueBox.ValueChanged += OnXValueChanged; XElement.ValueBox.SlidingEnd += ClearToken; YElement = grid.FloatValue(); YElement.SetLimits(limit); - YElement.ValueBox.ValueChanged += OnValueChanged; + YElement.ValueBox.ValueChanged += OnYValueChanged; YElement.ValueBox.SlidingEnd += ClearToken; ZElement = grid.FloatValue(); ZElement.SetLimits(limit); - ZElement.ValueBox.ValueChanged += OnValueChanged; + ZElement.ValueBox.ValueChanged += OnZValueChanged; ZElement.ValueBox.SlidingEnd += ClearToken; } + private void OnXValueChanged() + { + if (IsSetBlocked) + return; + if (LinkValues) + _valueChanged = ValueChanged.X; + + OnValueChanged(); + } + + private void OnYValueChanged() + { + if (IsSetBlocked) + return; + if (LinkValues) + _valueChanged = ValueChanged.Y; + + OnValueChanged(); + } + + private void OnZValueChanged() + { + if (IsSetBlocked) + return; + if (LinkValues) + _valueChanged = ValueChanged.Z; + + OnValueChanged(); + } + private void OnValueChanged() { if (IsSetBlocked) return; + var xValue = XElement.ValueBox.Value; + var yValue = YElement.ValueBox.Value; + var zValue = ZElement.ValueBox.Value; + + if (LinkValues) + { + var valueChange = 0.0f; + switch (_valueChanged) + { + case ValueChanged.X: + valueChange = xValue - ((Float3)Values[0]).X; + yValue += valueChange; + zValue += valueChange; + break; + case ValueChanged.Y: + valueChange = yValue - ((Float3)Values[0]).Y; + xValue += valueChange; + zValue += valueChange; + break; + case ValueChanged.Z: + valueChange = zValue - ((Float3)Values[0]).Z; + xValue += valueChange; + yValue += valueChange; + break; + default: + break; + } + } + var isSliding = XElement.IsSliding || YElement.IsSliding || ZElement.IsSliding; var token = isSliding ? this : null; - var value = new Float3(XElement.ValueBox.Value, YElement.ValueBox.Value, ZElement.ValueBox.Value); + var value = new Float3(xValue, yValue, zValue); object v = Values[0]; if (v is Vector3) v = (Vector3)value; diff --git a/Source/Editor/Windows/PropertiesWindow.cs b/Source/Editor/Windows/PropertiesWindow.cs index 3c2d06852..601717f38 100644 --- a/Source/Editor/Windows/PropertiesWindow.cs +++ b/Source/Editor/Windows/PropertiesWindow.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.Linq; +using System.Xml; using FlaxEditor.CustomEditors; using FlaxEngine.GUI; @@ -16,11 +17,19 @@ namespace FlaxEditor.Windows { private IEnumerable undoRecordObjects; + /// + public override bool UseLayoutData => true; + /// /// The editor. /// public readonly CustomEditorPresenter Presenter; + /// + /// Indication of if the scale is locked. + /// + public bool ScaleLinked = false; + /// /// Initializes a new instance of the class. /// @@ -52,5 +61,18 @@ namespace FlaxEditor.Windows var objects = Editor.SceneEditing.Selection.ConvertAll(x => x.EditableObject).Distinct(); Presenter.Select(objects); } + + /// + public override void OnLayoutSerialize(XmlWriter writer) + { + writer.WriteAttributeString("ScaleLinked", ScaleLinked.ToString()); + } + + /// + public override void OnLayoutDeserialize(XmlElement node) + { + if (bool.TryParse(node.GetAttribute("ScaleLinked"), out bool value1)) + ScaleLinked = value1; + } } }