internal void HandleItemManipulation(TimeLineItemControl ctrl, TimeLineItemChangedEventArgs e) { Boolean doStretch = false; TimeSpan deltaT = e.DeltaTime; TimeSpan zeroT = new TimeSpan(); int direction = deltaT.CompareTo(zeroT); if (direction == 0) return;//shouldn't happen TimeLineItemControl previous = null; TimeLineItemControl after = null; int afterIndex = -1; int previousIndex = -1; after = GetTimeLineItemControlStartingAfter(ctrl.StartTime, ref afterIndex); previous = GetTimeLineItemControlStartingBefore(ctrl.StartTime, ref previousIndex); if (after != null) after.ReadyToDraw = false; if (ctrl != null) ctrl.ReadyToDraw = false; Double useDeltaX = e.DeltaX; Double cLeft = 0; Double cWidth = 0; Double cEnd = 0; ctrl.GetPlacementInfo(ref cLeft, ref cWidth, ref cEnd); switch (e.Action) { case TimeLineAction.Move: #region move Double chainGap = Double.MaxValue; if (direction > 0) { //find chain connecteds that are after this one //delta each one in that chain that we are pushing List<TimeLineItemControl> afterChain = GetTimeLineForwardChain(ctrl, afterIndex, ref chainGap); if (chainGap < useDeltaX) useDeltaX = chainGap; foreach (var ti in afterChain) { ti.MoveMe(useDeltaX); } //find the size of our chain so we bring it into view var first = afterChain[0]; var last = afterChain[afterChain.Count - 1]; BringChainIntoView(first, last, direction); } if (direction < 0) { Boolean previousBackToStart = false; List<TimeLineItemControl> previousChain = GetTimeLineBackwardsChain(ctrl, previousIndex, ref previousBackToStart, ref chainGap); if (-chainGap > useDeltaX) { useDeltaX = chainGap; } if (!previousBackToStart) { foreach (var ti in previousChain) { ti.MoveMe(useDeltaX); } } var first = previousChain[0];//previousChain[previousChain.Count - 1]; var last = previousChain[previousChain.Count - 1]; BringChainIntoView(last, first, direction); } #endregion break; case TimeLineAction.StretchStart: switch (e.Mode) { #region stretchstart case TimeLineManipulationMode.Linked: #region linked Double gap = Double.MaxValue; if (previous != null) { Double pLeft = 0; Double pWidth = 0; Double pEnd = 0; previous.GetPlacementInfo(ref pLeft, ref pWidth, ref pEnd); gap = cLeft - pEnd; } if (direction < 0 && Math.Abs(gap) < Math.Abs(useDeltaX) && Math.Abs(gap) > _bumpThreshold)//if we are negative and not linked, but about to bump useDeltaX = -gap; if (Math.Abs(gap) < _bumpThreshold) {//we are linked if (ctrl.CanDelta(0, useDeltaX) && previous.CanDelta(1, useDeltaX)) { ctrl.MoveStartTime(useDeltaX); previous.MoveEndTime(useDeltaX); } } else if (ctrl.CanDelta(0, useDeltaX)) { ctrl.MoveStartTime(useDeltaX); } break; #endregion case TimeLineManipulationMode.Free: #region free gap = Double.MaxValue; doStretch = direction > 0; if (direction < 0) { //disallow us from free stretching into another item if (previous != null) { Double pLeft = 0; Double pWidth = 0; Double pEnd = 0; previous.GetPlacementInfo(ref pLeft, ref pWidth, ref pEnd); gap = cLeft - pEnd; } else { //don't allow us to stretch further than the gap between current and start time DateTime s = (DateTime)GetValue(StartDateProperty); gap = cLeft; } doStretch = gap > _bumpThreshold; if (gap < useDeltaX) { useDeltaX = gap; } } doStretch &= ctrl.CanDelta(0, useDeltaX); if (doStretch) { ctrl.MoveStartTime(useDeltaX); } #endregion break; default: break; #endregion } break; case TimeLineAction.StretchEnd: switch (e.Mode) { #region stretchend case TimeLineManipulationMode.Linked: #region linked Double gap = Double.MaxValue; if (after != null) { Double aLeft = 0; Double aWidth = 0; Double aEnd = 0; after.GetPlacementInfo(ref aLeft, ref aWidth, ref aEnd); gap = aLeft - cEnd; } if (direction > 0 && gap > _bumpThreshold && gap < useDeltaX)//if we are positive, not linked but about to bump useDeltaX = -gap; if (gap < _bumpThreshold) {//we are linked if (ctrl.CanDelta(1, useDeltaX) && after.CanDelta(0, useDeltaX)) { ctrl.MoveEndTime(useDeltaX); after.MoveStartTime(useDeltaX); } } else if (ctrl.CanDelta(0, useDeltaX)) { ctrl.MoveEndTime(useDeltaX); } break; #endregion case TimeLineManipulationMode.Free: #region free Double nextGap = Double.MaxValue; doStretch = true; if (direction > 0 && after != null) { //disallow us from free stretching into another item Double nLeft = 0; Double nWidth = 0; Double nEnd = 0; after.GetPlacementInfo(ref nLeft, ref nWidth, ref nEnd); nextGap = nLeft - cEnd; doStretch = nextGap > _bumpThreshold; if (nextGap < useDeltaX) useDeltaX = nextGap; } doStretch &= ctrl.CanDelta(1, useDeltaX); if (doStretch) { ctrl.MoveEndTime(useDeltaX); } break; #endregion default: break; #endregion } break; default: break; } }