public void AddTag(Type tagType, float startTime = 0f, float duration = -1f) { if (!Valid) { return; } if (duration < 0) { duration = DurationInSeconds - startTime; } int existing = tags.Count(t => t.Type == tagType && FloatComparer.AreEqual(t.startTime, startTime, FloatComparer.kEpsilon) && FloatComparer.AreEqual(t.duration, duration, FloatComparer.kEpsilon)); if (existing > 0) { return; } Undo.RecordObject(m_Asset, $"Add {TagAttribute.GetDescription(tagType)} tag"); TagAnnotation newTag = TagAnnotation.Create(tagType, startTime, duration); tags.Add(newTag); NotifyChanged(); }
public static TagAnnotation Create <T>(T payload, float startTime, float duration) where T : struct { TagAnnotation tag = Create(typeof(T), startTime, duration); tag.payload.SetValue(payload); return(tag); }
TaggedAnimationClip(AnimationClip animationClip, Asset asset, ETagImportOption tagImportOption) { m_Asset = asset; SetClip(animationClip); foreach (var method in Utility.GetExtensionMethods(GetType())) { method.Invoke(null, new object[] { this, tagImportOption }); } if (tagImportOption == ETagImportOption.AddDefaultTag) { object tag = DefaultTagAttribute.CreateDefaultTag(); if (tag != null) { TagAnnotation tagAnnotation = TagAnnotation.Create(tag.GetType(), 0.0f, DurationInSeconds); tagAnnotation.payload.SetValueObject(tag); AddTag(tagAnnotation); } } if (animationClip.isLooping) { TaggedPreBoundaryClip = this; TaggedPostBoundaryClip = this; } // Obsolete V1 variables m_PreBoundaryClip = null; m_PostBoundaryClip = null; }
public bool ReorderTagElement(ITimelineElement element, int direction) { if (direction == 0 || element == null) { return(false); } TagAnnotation tag = element.Object as TagAnnotation; if (tag == null) { return(false); } int currentIndex = m_TaggedClip.Tags.IndexOf(tag); int newIndex = currentIndex + direction; if (newIndex < 0 || newIndex > m_TaggedClip.Tags.Count - 1) { return(false); } Undo.RecordObject(m_TaggedClip.Asset, "Reorder Tag"); m_TaggedClip.Tags.Remove(tag); m_TaggedClip.Tags.Insert(newIndex, tag); Insert(newIndex, (element as VisualElement)); return(true); }
public void RemoveTag(TagAnnotation tag) { Undo.RecordObject(m_Asset, $"Remove {TagAttribute.GetDescription(tag.Type)} tag"); tags.RemoveAll(x => x == tag); tag.Dispose(); TagRemoved?.Invoke(tag); NotifyChanged(); }
public TagElement(Track track, TaggedAnimationClip clip, TagAnnotation tag) : base(track) { m_Tag = tag; focusable = true; AddToClassList("clipTagRoot"); m_ManipulateStartLabel = new Label(); m_ManipulateStartLabel.AddToClassList("tagManipulateStartLabel"); m_ManipulateStartLabel.AddToClassList("tagManipulateLabel"); m_ManipulateEndLabel = new Label(); m_ManipulateEndLabel.AddToClassList("tagManipulateEndLabel"); m_ManipulateEndLabel.AddToClassList("tagManipulateLabel"); m_BackgroundColor = AnnotationAttribute.GetColor(m_Tag.Type); var background = m_BackgroundColor; background.r *= k_BackgroundAlpha; background.g *= k_BackgroundAlpha; background.b *= k_BackgroundAlpha; style.backgroundColor = background; int hash = new Random(m_Tag.payload.GetHashedData()).Next(); Color colorFromValueHash = ColorUtility.FromHtmlString("#" + Convert.ToString(hash, 16)); Color borderColor = background; borderColor.r = (borderColor.r + colorFromValueHash.r) / 2; borderColor.g = (borderColor.g + colorFromValueHash.g) / 2; borderColor.b = (borderColor.b + colorFromValueHash.b) / 2; style.borderLeftColor = borderColor; style.borderBottomColor = borderColor; style.borderRightColor = borderColor; VisualElement startHandle = CreateHandle(TagManipulator.Mode.StartTime); startHandle.style.left = -4; Insert(0, startHandle); startHandle.Add(m_ManipulateStartLabel); m_LabelContainer.AddManipulator(new TagManipulator(this, TagManipulator.Mode.Body)); m_Label.text = string.IsNullOrEmpty(m_Tag.name) ? m_Tag.Name : m_Tag.name; VisualElement endHandle = CreateHandle(TagManipulator.Mode.Duration); endHandle.style.left = 4; Add(endHandle); endHandle.Add(m_ManipulateEndLabel); var contextMenuManipulator = new ContextualMenuManipulator(OpenTagRemoveMenu); this.AddManipulator(contextMenuManipulator); RegisterCallback <AttachToPanelEvent>(OnAttachToPanel); }
public void AddTag(TagAnnotation tag) { if (!Valid) { return; } Undo.RecordObject(m_Asset, $"Add {TagAttribute.GetDescription(tag.Type)} tag"); tags.Add(tag); TagAdded?.Invoke(tag); NotifyChanged(); }
bool IsTagAssociatedToMetric(TagAnnotation tag) { string tagName = TagAnnotation.GetTagTypeFullName(tag); foreach (Asset.Metric metric in asset.Metrics) { if (metric.TagTypes.Contains(tagName)) { return(true); } } return(false); }
bool DoesSegmentCoverMetric(Segment segment) { foreach (TagAnnotation tag in segment.tags) { string tagName = TagAnnotation.GetTagTypeFullName(tag); foreach (Asset.Metric metric in asset.Metrics) { if (metric.TagTypes.Contains(tagName)) { return(true); } } } return(false); }
public static string GetTagTypeFullName(TagAnnotation t) { if (t.payload == null || t.payload.Type == null) { return(null); } string name; if (k_TagTypeFullNameCache.TryGetValue(t.payload.Type, out name)) { return(name); } if (t.payload.Type != null && t.payload.ScriptableObject != null) { name = t.payload.Type.FullName; k_TagTypeFullNameCache[t.payload.Type] = name; return(name); } return($"{TagAttribute.k_UnknownTagType} - {t.payload.SimplifiedTypeName} "); }
public int GetMetricIndexCoveringTimeOnTag(TagAnnotation tag) { return(GetMetricIndexCoveringTimeOnTag(TagAnnotation.GetTagTypeFullName(tag))); }
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; }
void RemoveTag(TagAnnotation tag) { m_Clip.RemoveTag(tag); }
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(); }
public bool Equals(TagAnnotation other) { return(Type == other.Type && FloatComparer.AreEqual(startTime, other.startTime, FloatComparer.kEpsilon) && FloatComparer.AreEqual(duration, other.duration, FloatComparer.kEpsilon)); }