public static PlacementValidity GetPlacementValidity(ITimelineItem item, IEnumerable <ITimelineItem> otherItems) { if (item.duration <= 0.0) { return(PlacementValidity.Valid); //items without any duration can always be placed } var sortedItems = otherItems.Where(i => i.duration > 0.0).OrderBy(c => c.start); var candidates = new List <ITimelineItem>(); foreach (var sortedItem in sortedItems) { if ((DiscreteTime)sortedItem.start >= (DiscreteTime)item.end) { // No need to process further break; } if ((DiscreteTime)sortedItem.end <= (DiscreteTime)item.start) { // Skip continue; } candidates.Add(sortedItem); } var discreteStart = (DiscreteTime)item.start; var discreteEnd = (DiscreteTime)item.end; // Note: Order of tests matters for (int i = 0, n = candidates.Count; i < n; i++) { var candidate = candidates[i]; var blendItem = item as IBlendable; if (blendItem != null && blendItem.supportsBlending) { if (EditModeUtils.Contains(candidate.start, candidate.end, item)) { return(PlacementValidity.InvalidIsWithin); } if (i < n - 1) { var nextCandidate = candidates[i + 1]; var discreteNextCandidateStart = (DiscreteTime)nextCandidate.start; var discreteCandidateEnd = (DiscreteTime)candidate.end; if (discreteCandidateEnd > discreteNextCandidateStart) { if (discreteStart >= discreteNextCandidateStart) { // Note: In case the placement is fully within a blend, // InvalidStartsInBlend MUST have priority return(PlacementValidity.InvalidStartsInBlend); } if (discreteEnd > discreteNextCandidateStart && discreteEnd <= discreteCandidateEnd) { return(PlacementValidity.InvalidEndsInBlend); } if (discreteStart < discreteNextCandidateStart && discreteEnd > discreteCandidateEnd) { return(PlacementValidity.InvalidContainsBlend); } } } if (EditModeUtils.Contains(item.start, item.end, candidate)) { return(PlacementValidity.InvalidContains); } } else { if (EditModeUtils.Overlaps(item, candidate.start, candidate.end) || EditModeUtils.Overlaps(candidate, item.start, item.end)) { return(PlacementValidity.InvalidOverlapWithNonBlendableClip); } } } return(PlacementValidity.Valid); }