Skip to content

Commit

Permalink
CMCL-1587: cleanup UX layout code. fix alignment for U6 (#989)
Browse files Browse the repository at this point in the history
* cleanup UX layout code. fix alignment for U6

* Update InspectorUtility.cs

* merge errors

* Update CinemachineSplineRollEditor.cs

* merge errors

* bugfixes

* Remove bindItem from BlenderSettingsEditor

* Update InspectorUtility.cs

* get rid of bindItem in SequencerEditor

* get rid of bindItem in StateDrivenCamera editor

* fix bindItem in CameraInspectorUtility

* add some missing draggers

* layout tweaking

* Simplify SplineDataInspectorUtility.CreateDataListField

* cleanup code for creating draggable properties

* remove bindItem from SplineRoll

* remove bindItem for SplineLookAtTargets

* minor layout tweaks

* Minor tweaks, LabeledRow refactor (one container less)

* More reduction of excess containers

* simplification

* Update CinemachineFollowZoom.cs

* Update InputAxisPropertyDrawer.cs

* fix upgrade message layout

* better handling of missing target warnings

* layout tweaks

* No SaveDuringPlay for PerlinNoise.m_NoiseOffset

* Add isDelayed on some fields

* Cleanup SaveDuringPlay for input axis controller

* Add some missing NoSaveDuringPlay
  • Loading branch information
glabute authored Jun 12, 2024
1 parent 3850fa0 commit 5be26c8
Show file tree
Hide file tree
Showing 53 changed files with 973 additions and 878 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
using System.Collections.Generic;
using UnityEngine.UIElements;
using UnityEditor.UIElements;
using System;

namespace Unity.Cinemachine.Editor
{
Expand Down Expand Up @@ -55,6 +56,7 @@ public override VisualElement CreateInspectorGUI()
// Gather the camera candidates
var availableCameras = new List<string>();
Dictionary<string, int> cameraIndexLookup = new();
Action onCamerasUpdated = null;
list.TrackAnyUserActivity(() =>
{
var allCameras = new List<CinemachineVirtualCameraBase>();
Expand All @@ -65,29 +67,47 @@ public override VisualElement CreateInspectorGUI()
for (int i = 0; i < allCameras.Count; ++i)
if (allCameras[i] != null && !availableCameras.Contains(allCameras[i].Name))
availableCameras.Add(allCameras[i].Name);
list.RefreshItems(); // rebuild the list
onCamerasUpdated?.Invoke();
});

list.makeItem = () => new BindableElement { style = { flexDirection = FlexDirection.Row }};
list.bindItem = (row, index) =>
list.makeItem = () =>
{
// Remove children - items get recycled
for (int i = row.childCount - 1; i >= 0; --i)
row.RemoveAt(i);

var def = new CinemachineBlenderSettings.CustomBlend();
var element = index < elements.arraySize ? elements.GetArrayElementAtIndex(index) : null;
if (!IsUnityNull(element))
var row = new BindableElement { style = { flexDirection = FlexDirection.Row }};
var from = row.AddChild(CreateCameraPopup(SerializedPropertyHelper.PropertyName(() => def.From)));
var to = row.AddChild(CreateCameraPopup(SerializedPropertyHelper.PropertyName(() => def.To)));
var blend = row.AddChild(new PropertyField(null, "") { bindingPath = SerializedPropertyHelper.PropertyName(() => def.Blend)});
FormatElement(false, from, to, blend);
return row;

// Local function
VisualElement CreateCameraPopup(string bindingPath)
{
var from = row.AddChild(CreateCameraPopup(element.FindPropertyRelative(() => def.From)));
var to = row.AddChild(CreateCameraPopup(element.FindPropertyRelative(() => def.To)));
var blend = row.AddChild(new PropertyField(element.FindPropertyRelative(() => def.Blend), ""));
FormatElement(false, from, to, blend);
var container = new VisualElement { style = { flexDirection = FlexDirection.Row, flexGrow = 1 }};
var textField = container.AddChild(new TextField { bindingPath = bindingPath, isDelayed = true, style = { flexGrow = 1, flexBasis = 20 }});

((BindableElement)row).BindProperty(element); // bind must be done at the end
var warning = container.AddChild(InspectorUtility.MiniHelpIcon($"No in-scene camera matches this name"));
textField.RegisterValueChangedCallback((evt) => OnCameraUpdated());
onCamerasUpdated += OnCameraUpdated;
void OnCameraUpdated()
{
warning.tooltip = $"No in-scene camera matches \"{textField.value}\"";
warning.SetVisible(availableCameras.FindIndex(x => x == textField.value) < 0);
};

var popup = container.AddChild(InspectorUtility.MiniDropdownButton(
"Choose from currently-available cameras", new ContextualMenuManipulator((evt) =>
{
for (int i = 0; i < availableCameras.Count; ++i)
evt.menu.AppendAction(availableCameras[i], (action) => textField.value = action.name);
})));
popup.style.marginRight = 5;
return container;
}
};

return ux;

// Local function
static void FormatElement(bool isHeader, VisualElement e1, VisualElement e2, VisualElement e3)
{
Expand All @@ -101,38 +121,6 @@ static void FormatElement(bool isHeader, VisualElement e1, VisualElement e2, Vis
e3.style.flexBasis = 1;
e3.style.flexGrow = 2;
}

// Local function
VisualElement CreateCameraPopup(SerializedProperty p)
{
var row = new VisualElement { style = { flexDirection = FlexDirection.Row, flexGrow = 1 }};
var textField = row.AddChild(new TextField { isDelayed = true, style = { flexGrow = 1, flexBasis = 20 }});
textField.BindProperty(p);
if (availableCameras.FindIndex(x => x == p.stringValue) < 0)
row.AddChild(InspectorUtility.MiniHelpIcon("No in-scene camera matches this name"));
var popup = row.AddChild(InspectorUtility.MiniDropdownButton(
"Choose from currently-available cameras", new ContextualMenuManipulator((evt) =>
{
for (int i = 0; i < availableCameras.Count; ++i)
evt.menu.AppendAction(availableCameras[i],
(action) =>
{
p.stringValue = action.name;
p.serializedObject.ApplyModifiedProperties();
});
})));
popup.style.marginRight = 5;
return row;
}

// Local function
static bool IsUnityNull(object obj)
{
// Checks whether an object is null or Unity pseudo-null
// without having to cast to UnityEngine.Object manually
return obj == null || ((obj is UnityEngine.Object) && ((UnityEngine.Object)obj) == null);
}
return ux;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -44,9 +44,12 @@ public override VisualElement CreateInspectorGUI()

var defaultTargetLabel = new ObjectField("");
defaultTargetLabel.SetEnabled(false);
var defaultTargetRow = ux.AddChild(new InspectorUtility.LabeledRow("Default Target", "", defaultTargetLabel));
defaultTargetRow.tooltip = "The default target is set in the parent object, and will be used if the Tracking Target is None";
var defaultTargetRow = ux.AddChild(new InspectorUtility.LabeledRow(
"Default Target", "The default target is set in the parent object, and will be used if the Tracking Target is None",
defaultTargetLabel));
defaultTargetRow.focusable = false;
defaultTargetLabel.style.marginLeft = 5;
defaultTargetLabel.style.marginRight = -2;
ux.Add(new PropertyField(serializedObject.FindProperty(() => Target.Target)));

ux.AddHeader("Global Settings");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,14 @@ public override VisualElement CreateInspectorGUI()
{
var ux = new VisualElement();

ux.Add(new HelpBox("This component is optional and can be removed if you don't need it. "
+ "The modifiers you add will override settings for the top and bottom portions "
+ "of the camera's vertical orbit.",
HelpBoxMessageType.Info));

var invalidSrcMsg = ux.AddChild(
new HelpBox("<b>This component will be ignored because no applicable target components are present.</b>\n\n"
+ "Applicable target components include: "
new HelpBox("<b>Component will be ignored because no modifiable targets are present.</b>\n\n"
+ "Modifiable target components include: "
+ InspectorUtility.GetAssignableBehaviourNames(
typeof(CinemachineFreeLookModifier.IModifierValueSource)),
HelpBoxMessageType.Warning));
Expand Down Expand Up @@ -110,7 +115,9 @@ public override VisualElement CreatePropertyGUI(SerializedProperty property)
warningSymbol.SetVisible(showWarning);
});

return new InspectorUtility.FoldoutWithOverlay(foldout, overlay, null);
var ux = new InspectorUtility.FoldoutWithOverlay(foldout, overlay, null);
ux.style.marginLeft = 12;
return ux;
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@ public override VisualElement CreateInspectorGUI()
{
var ux = new VisualElement();
this.AddMissingCmCameraHelpBox(ux);
ux.Add(new PropertyField(serializedObject.FindProperty(() => Target.TargetOffset)));
ux.Add(new PropertyField(serializedObject.FindProperty(() => Target.TrackerSettings)));
ux.Add(new PropertyField(serializedObject.FindProperty(() => Target.TargetOffset)));
ux.AddSpace();

var orbitModeProp = serializedObject.FindProperty(() => Target.OrbitStyle);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
using System.Collections.Generic;
using UnityEditor;
using UnityEditor.UIElements;
using UnityEngine;
Expand Down Expand Up @@ -41,7 +42,6 @@ public override VisualElement CreateInspectorGUI()

var list = container.AddChild(new ListView()
{
name = "InstructionList",
reorderable = true,
reorderMode = ListViewReorderMode.Animated,
showAddRemoveFooter = true,
Expand All @@ -53,77 +53,55 @@ public override VisualElement CreateInspectorGUI()
var instructions = serializedObject.FindProperty(() => Target.Instructions);
list.BindProperty(instructions);

list.makeItem = () => new BindableElement { style = { flexDirection = FlexDirection.Row }};
list.bindItem = (row, index) =>
// Available camera candidates
var availableCameras = new List<Object>();

list.makeItem = () =>
{
// Remove children - items get recycled
for (int i = row.childCount - 1; i >= 0; --i)
row.RemoveAt(i);
var row = new BindableElement { style = { flexDirection = FlexDirection.Row }};

var def = new CinemachineSequencerCamera.Instruction();
var element = instructions.GetArrayElementAtIndex(index);

var vcamSelProp = element.FindPropertyRelative(() => def.Camera);
var vcamSel = row.AddChild(new PopupField<Object> { name = $"vcamSelector{index}", choices = new() });
vcamSel.formatListItemCallback = (obj) => obj == null ? "(null)" : obj.name;
vcamSel.formatSelectedValueCallback = (obj) => obj == null ? "(null)" : obj.name;
vcamSel.TrackPropertyWithInitialCallback(instructions, (p) => UpdateCameraDropdowns());
var vcamSel = row.AddChild(new PopupField<Object>
{
bindingPath = SerializedPropertyHelper.PropertyName(() => def.Camera),
choices = availableCameras,
formatListItemCallback = (obj) => obj == null ? "(null)" : obj.name,
formatSelectedValueCallback = (obj) => obj == null ? "(null)" : obj.name
});

var blend = row.AddChild(new PropertyField(element.FindPropertyRelative(() => def.Blend), ""));
if (index == 0)
blend.name = "FirstItemBlend";
var hold = row.AddChild(
new InspectorUtility.CompactPropertyField(element.FindPropertyRelative(() => def.Hold), " "));
hold.RemoveFromClassList(InspectorUtility.kAlignFieldClass);
var blend = row.AddChild(new PropertyField(null, "") { bindingPath = SerializedPropertyHelper.PropertyName(() => def.Blend), name = "blendSelector" });
var hold = row.AddChild(InspectorUtility.CreateDraggableField(() => def.Hold, row.AddChild(new Label(" ")), out _));
hold.SafeSetIsDelayed();

FormatInstructionElement(false, vcamSel, blend, hold);

// Bind must be last
((BindableElement)row).BindProperty(element);
vcamSel.BindProperty(vcamSelProp);
return row;
};

container.AddSpace();
this.AddChildCameras(container, null);

container.TrackAnyUserActivity(() =>
{
if (Target == null)
if (Target == null || list.itemsSource == null)
return; // object deleted

var isMultiSelect = targets.Length > 1;
multiSelectMsg.SetVisible(isMultiSelect);
container.SetVisible(!isMultiSelect);

// Hide the first blend if not looped
list.Q<VisualElement>("FirstItemBlend")?.SetEnabled(Target.Loop);
var index = 0;
list.Query<VisualElement>().Where((e) => e.name == "blendSelector").ForEach((e)
=> e.style.visibility = (index++ == 0 && !Target.Loop) ? Visibility.Hidden : Visibility.Visible);

// Update the list items
UpdateCameraDropdowns();
// Gather the camera candidates
availableCameras.Clear();
availableCameras.AddRange(Target.ChildCameras);
});
this.AddExtensionsDropdown(ux);

return ux;

// Local function
void UpdateCameraDropdowns()
{
var children = Target.ChildCameras;
int index = 0;
var iter = list.itemsSource.GetEnumerator();
while (iter.MoveNext())
{
var vcamSel = list.Q<PopupField<Object>>($"vcamSelector{index}");
if (vcamSel != null)
{
vcamSel.choices.Clear();
for (int i = 0; i < children.Count; ++i)
vcamSel.choices.Add(children[i]);
}
++index;
}
}

// Local function
static void FormatInstructionElement(bool isHeader, VisualElement e1, VisualElement e2, VisualElement e3)
{
Expand All @@ -133,13 +111,13 @@ static void FormatInstructionElement(bool isHeader, VisualElement e1, VisualElem
e1.style.flexBasis = floatFieldWidth + InspectorUtility.SingleLineHeight;
e1.style.flexGrow = 1;

e2.style.flexBasis = floatFieldWidth;
e2.style.marginLeft = isHeader ? 4 * InspectorUtility.SingleLineHeight - 3 : 0;
e2.style.flexBasis = floatFieldWidth + InspectorUtility.SingleLineHeight;
e2.style.flexGrow = 1;

e3.style.marginRight = 4;
floatFieldWidth += isHeader ? InspectorUtility.SingleLineHeight/2 - 1 : 0;
e3.style.flexBasis = floatFieldWidth;
e3.style.flexGrow = 0;
e3.style.unityTextAlign = TextAnchor.MiddleRight;
}
}
}
Expand Down
Loading

0 comments on commit 5be26c8

Please sign in to comment.