internal TagEditor(TagAnnotation tag, TaggedAnimationClip clip) { m_Tag = tag; m_Clip = clip; UIElementsUtils.CloneTemplateInto("Inspectors/TagEditor.uxml", this); UIElementsUtils.ApplyStyleSheet(AnnotationsEditor.k_AnnotationsEditorStyle, this); AddToClassList(AnnotationsEditor.k_AnnotationsContainer); AddToClassList("drawerElement"); var deleteButton = this.Q <Button>("deleteButton"); deleteButton.clickable.clicked += () => { RemoveTag(m_Tag); }; if (!tag.payload.ValidPayloadType) { Clear(); var unknownLabel = new Label { text = TagAttribute.k_UnknownTagType }; unknownLabel.AddToClassList(AnnotationsEditor.k_UnknownAnnotationType); Add(unknownLabel); return; } TextField tagType = this.Q <TextField>("tagType"); tagType.value = TagAttribute.GetDescription(m_Tag.Type); tagType.SetEnabled(false); Asset asset = m_Clip.Asset; TextField tagName = this.Q <TextField>("name"); tagName.value = m_Tag.name; tagName.RegisterValueChangedCallback(evt => { if (!evt.newValue.Equals(m_Tag.name, StringComparison.Ordinal)) { Undo.RecordObject(asset, "Change tag name"); m_Tag.name = evt.newValue; m_Tag.NotifyChanged(); asset.MarkDirty(); } }); TextField metricLabel = this.Q <TextField>("metricLabel"); var metric = asset.GetMetricForTagType(m_Tag.Type); if (metric != null) { metricLabel.value = metric.name; metricLabel.SetEnabled(false); } else { metricLabel.style.display = DisplayStyle.None; } TimeField stf = this.Q <TimeField>("startTime"); stf.Init(m_Clip, m_Tag.startTime); stf.TimeChanged += (newTime) => { if (!EqualityComparer <float> .Default.Equals(m_Tag.startTime, newTime)) { Undo.RecordObject(asset, "Change tag start time"); m_Tag.startTime = newTime; m_Tag.NotifyChanged(); asset.MarkDirty(); } }; TimeField dtf = this.Q <TimeField>("durationTime"); dtf.Init(m_Clip, m_Tag.duration); dtf.TimeChanged += (newTime) => { if (!EqualityComparer <float> .Default.Equals(m_Tag.duration, newTime)) { Undo.RecordObject(asset, "Change tag duration"); m_Tag.duration = newTime; m_Tag.NotifyChanged(); asset.MarkDirty(); } }; var so = m_Tag.payload.ScriptableObject; if (so != null) { m_PayloadInspector = UnityEditor.Editor.CreateEditor(so) as GenericStructInspector; m_PayloadInspector.StructModified += () => { m_Tag.payload.Serialize(); m_Tag.NotifyChanged(); m_Clip.Asset.MarkDirty(); }; VisualElement inspectorElement = m_PayloadInspector.CreateInspectorGUI() ?? new IMGUIContainer(m_PayloadInspector.OnInspectorGUI); var inspectorContainer = this.Q <VisualElement>("payloadInspector"); inspectorContainer.Add(inspectorElement); } RegisterCallback <DetachFromPanelEvent>(OnDetachFromPanel); m_Tag.Changed += Refresh; asset.AssetWasDeserialized += Refresh; }
protected override void OnMouseMoveEvent(MouseMoveEvent evt) { Timeline timeline = TagElement.Timeline; TaggedAnimationClip taggedAnimationClip = timeline.TaggedClip; if (!m_Active || !target.HasMouseCapture() || !taggedAnimationClip.Valid || EditorApplication.isPlaying) { return; } if (Math.Abs(m_MousePreviousPosition.x - evt.mousePosition.x) < k_MinDistanceForTagCreation) { if (Math.Abs(m_MouseDownPosition.y - evt.mousePosition.y) >= k_MinDistanceForTagCreation) { OnMouseMoveReorderEvent(evt); } return; } Vector2 position = evt.mousePosition; MouseDirection direction = GetMouseDirection(position); m_MousePreviousPosition = position; float framerate = taggedAnimationClip.SampleRate; TagAnnotation tag = TagElement.m_Tag; Asset asset = taggedAnimationClip.Asset; Mode mode = m_Mode; if (m_OverrideMode == Mode.None) { float mousePos = evt.mousePosition.x; float fromStart = Math.Abs(mousePos - TagElement.worldBound.x); float fromEnd = Math.Abs(mousePos - TagElement.worldBound.xMax); // If the tag element is this small it will be too difficult to accurately grab the center and even accurately pick either end // we'll figure out which side of the tag is closest and assume the user meant to click that side. if (TagElement.layout.width <= 14f) { if (fromStart <= fromEnd) { mode = Mode.StartTime; } else { mode = Mode.Duration; } m_OverrideMode = mode; } } else { mode = m_OverrideMode; } float newTime = float.NaN; float dragPosition = position.x; bool canPreview = timeline.CanPreview(); // when we're dragging the entire tag we need to snap the edges of the tag, not the mouse position so we'll handle that inside its switch case if (mode != Mode.Body) { if (m_Target.SnapValid(dragPosition)) { return; } TryToSnap(dragPosition, direction, taggedAnimationClip.SampleRate, out newTime, snapToPlayhead: !canPreview); } float previewTime = -1f; switch (mode) { case Mode.StartTime: float endTime = tag.startTime + tag.duration; Undo.RecordObject(asset, "Drag Tag start"); float delta = newTime - tag.startTime; if (tag.duration - delta < TagElement.MinTagDuration) { tag.startTime = endTime - TagElement.MinTagDuration; tag.duration = TagElement.MinTagDuration; } else { tag.startTime = newTime; tag.duration = endTime - tag.startTime; } TagElement.Timeline.ShowStartGuideline(tag.startTime); previewTime = newTime; break; case Mode.Duration: Undo.RecordObject(asset, "Drag Tag Duration"); float newDuration = newTime - tag.startTime; if (newDuration <= TagElement.MinTagDuration) { tag.duration = TagElement.MinTagDuration; } else { tag.duration = newDuration; } TagElement.Timeline.ShowEndGuideline(tag.EndTime); previewTime = tag.EndTime; break; case Mode.Body: Undo.RecordObject(asset, "Drag Tag"); newTime = m_Target.Timeline.WorldPositionToTime(position.x); if (TagElement.Timeline.TimelineUnits == TimelineViewMode.frames) { newTime = (float)TimelineUtility.RoundToFrame(newTime - m_TimeOffsetAtMouseDown, framerate); } else { newTime -= m_TimeOffsetAtMouseDown; } if (!m_Target.SnapValid(newTime) && !m_Target.SnapValid(newTime + tag.duration)) { float mouseOffset = TagElement.Timeline.TimeToWorldPos(newTime); if (!TryToSnap(mouseOffset, direction, taggedAnimationClip.SampleRate, out newTime, snapToPlayhead: !canPreview)) { float durationPos = TagElement.Timeline.TimeToWorldPos(newTime + tag.duration); //Try to snap via the end of the current tag if (TryToSnap(durationPos, direction, taggedAnimationClip.SampleRate, out float candidateEndTime, snapToPlayhead: !canPreview)) { newTime = candidateEndTime - tag.duration; } } tag.startTime = newTime; TagElement.Timeline.ShowGuidelines(tag.startTime, tag.EndTime); } previewTime = tag.EndTime; break; } if (canPreview && previewTime >= 0f) { TagElement.Timeline.SetActiveTime(previewTime); } tag.NotifyChanged(); TagElement.Timeline.SendTagModified(); evt.StopPropagation(); TagElement.ShowManipulationLabel(); }