private static void OnViewLevelChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { TimeLineItemControl ctrl = d as TimeLineItemControl; if (ctrl != null) { ctrl.PlaceOnCanvas(); } }
private static void OnTimeValueChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { TimeLineItemControl ctrl = d as TimeLineItemControl; if (ctrl != null) { ctrl.PlaceOnCanvas(); ctrl.Duration = ctrl.EndTime - ctrl.StartTime; } }
private TimeLineItemControl CreateTimeLineItemControl(ITimeLineDataItem data) { Binding startBinding = new Binding("StartTime"); startBinding.Mode = BindingMode.TwoWay; startBinding.UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged; Binding endBinding = new Binding("EndTime"); endBinding.Mode = BindingMode.TwoWay; endBinding.UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged; DateTime timelineStart = StartDate; Binding expandedBinding = new Binding("TimelineViewExpanded"); expandedBinding.Mode = BindingMode.TwoWay; endBinding.UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged; TimeLineItemControl adder = new TimeLineItemControl(); adder.TimeLineStartTime = timelineStart; adder.DataContext = data; adder.Content = data; adder.SetBinding(TimeLineItemControl.StartTimeProperty, startBinding); adder.SetBinding(TimeLineItemControl.EndTimeProperty, endBinding); adder.SetBinding(TimeLineItemControl.IsExpandedProperty, expandedBinding); if (_template != null) { adder.ContentTemplate = _template; } /*adder.PreviewMouseLeftButtonDown += item_PreviewEditButtonDown; adder.MouseMove += item_MouseMove; adder.PreviewMouseLeftButtonUp += item_PreviewEditButtonUp;*/ adder.PreviewMouseRightButtonDown += item_PreviewEditButtonDown; adder.MouseMove += item_MouseMove; adder.PreviewMouseRightButtonUp += item_PreviewEditButtonUp; adder.PreviewMouseLeftButtonUp += item_PreviewDragButtonUp; adder.PreviewMouseLeftButtonDown += item_PreviewDragButtonDown; adder.UnitSize = UnitSize; return adder; }
private void BringChainIntoView(TimeLineItemControl first, TimeLineItemControl last, int direction) { Double l1 = 0; Double l2 = 0; Double w = 0; Double w2 = 0; Double end = 0; first.GetPlacementInfo(ref l1, ref w, ref end); last.GetPlacementInfo(ref l2, ref w2, ref end); Double chainW = end - l1; Double leadBuffer = 4 * UnitSize; chainW += leadBuffer; if (direction > 0) { first.BringIntoView(new Rect(new Point(0, 0), new Point(chainW, Height))); } else { first.BringIntoView(new Rect(new Point(-leadBuffer, 0), new Point(chainW, Height))); } }
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; } }
public TimeLineDragAdorner(TimeLineItemControl uiElement, DataTemplate template) : base(uiElement) { _adorningContentPresenter = new ContentPresenter(); _adorningContentPresenter.Content = uiElement.DataContext; _adorningContentPresenter.ContentTemplate = template; _adorningContentPresenter.Opacity = 0.5; _layer = AdornerLayer.GetAdornerLayer(uiElement); _layer.Add(this); IsHitTestVisible = false; }
void TimeLineControl_Drop(object sender, DragEventArgs e) { DragAdorner = null; TimeLineItemControl dropper = e.Data.GetData(typeof(TimeLineItemControl)) as TimeLineItemControl; ITimeLineDataItem dropData = null; if (dropper == null) { //dropData = e.Data.GetData(typeof(ITimeLineDataItem)) as ITimeLineDataItem; dropData = e.Data.GetData("GongSolutions.Wpf.DragDrop") as ITimeLineDataItem; if (dropData != null) { //I haven't figured out why but //sometimes when dropping from an external source //the drop event hits twice. //that results in ugly duplicates ending up in the timeline //and it is a mess. if (Items.Contains(dropData)) return; //create a new timeline item control from this data dropper = CreateTimeLineItemControl(dropData); dropper.StartTime = StartDate; dropper.InitializeDefaultLength(); Children.Remove(_tmpDraggAdornerControl); _tmpDraggAdornerControl = null; } } var dropX = e.GetPosition(this).X; int newIndex = GetDroppedNewIndex(dropX); var curData = dropper.DataContext as ITimeLineDataItem; var curIndex = Items.IndexOf(curData); if ((curIndex == newIndex || curIndex + 1 == newIndex) && dropData == null && dropper.Parent == this)//dropdata null is to make sure we aren't failing on adding a new data item into the timeline //dropper.parent==this makes it so that we allow a dropper control from another timeline to be inserted in at the start. { return;//our drag did nothing meaningful so we do nothing. } if (dropper != null) { DateTime start = (DateTime)GetValue(StartDateProperty); if (newIndex == 0) { if (dropData == null) { RemoveTimeLineItemControl(dropper); } if (dropper.Parent != this && dropper.Parent is TimeLineControl) { var tlCtrl = dropper.Parent as TimeLineControl; tlCtrl.RemoveTimeLineItemControl(dropper); } InsertTimeLineItemControlAt(newIndex, dropper); dropper.MoveToNewStartTime(start); MakeRoom(newIndex, dropper.Width); } else//we are moving this after something. { //find out if we are moving the existing one back or forward. var placeAfter = GetTimeLineItemControlAt(newIndex - 1); if (placeAfter != null) { start = placeAfter.EndTime; RemoveTimeLineItemControl(dropper); if (curIndex < newIndex && curIndex >= 0)//-1 is on an insert in which case we definitely don't want to take off on our new index value { //we are moving forward. newIndex--;//when we removed our item, we shifted our insert index back 1 } if (dropper.Parent != null && dropper.Parent != this) { var ptl = dropper.Parent as TimeLineControl; ptl.RemoveTimeLineItemControl(dropper); } InsertTimeLineItemControlAt(newIndex, dropper); dropper.MoveToNewStartTime(start); MakeRoom(newIndex, dropper.Width); } } } //ReDrawChildren(); DrawBackGround(); e.Handled = true; }
void TimeLineControl_DragOver(object sender, DragEventArgs e) { //throw new NotImplementedException(); TimeLineItemControl d = e.Data.GetData(typeof(TimeLineItemControl)) as TimeLineItemControl; if (d != null) { if (Manager != null) { if (!Manager.CanAddToTimeLine(d.DataContext as ITimeLineDataItem)) { e.Effects = DragDropEffects.None; return; } } e.Effects = DragDropEffects.Move; //this is an internal drag or a drag from another time line control if (DragAdorner == null) { _dragAdorner = new TimeLineDragAdorner(d, ItemTemplate); } DragAdorner.MousePosition = e.GetPosition(d); DragAdorner.InvalidateVisual(); } else {//GongSolutions.Wpf.DragDrop var d2 = e.Data.GetData("GongSolutions.Wpf.DragDrop"); if (d2 != null) { if (Manager != null) { if (!Manager.CanAddToTimeLine(d2 as ITimeLineDataItem)) { e.Effects = DragDropEffects.None; return; } } e.Effects = DragDropEffects.Move; if (DragAdorner == null) { //we are dragging from an external source and we don't have a timeline item control of any sort Children.Remove(_tmpDraggAdornerControl); //in order to get an adornment layer the control has to be somewhere _tmpDraggAdornerControl = new TimeLineItemControl(); _tmpDraggAdornerControl.UnitSize = UnitSize; Children.Add(_tmpDraggAdornerControl); Canvas.SetLeft(_tmpDraggAdornerControl, -1000000); _tmpDraggAdornerControl.DataContext = d2; _tmpDraggAdornerControl.StartTime = StartDate; _tmpDraggAdornerControl.InitializeDefaultLength(); _tmpDraggAdornerControl.ContentTemplate = ItemTemplate; _dragAdorner = new TimeLineDragAdorner(_tmpDraggAdornerControl, ItemTemplate); } DragAdorner.MousePosition = e.GetPosition(_tmpDraggAdornerControl); DragAdorner.InvalidateVisual(); } } DragScroll(e); }
void TimeLineControL_DragLeave(object sender, DragEventArgs e) { DragAdorner = null; Children.Remove(_tmpDraggAdornerControl); _tmpDraggAdornerControl = null; }
private void RemoveTimeLineItemControl(TimeLineItemControl remover) { var curData = remover.DataContext as ITimeLineDataItem; remover.PreviewMouseRightButtonDown -= item_PreviewEditButtonDown; remover.MouseMove -= item_MouseMove; remover.PreviewMouseRightButtonUp -= item_PreviewEditButtonUp; remover.PreviewMouseLeftButtonUp -= item_PreviewDragButtonUp; remover.PreviewMouseLeftButtonDown -= item_PreviewDragButtonDown; Items.Remove(curData); Children.Remove(remover); }
void item_PreviewDragButtonUp(object sender, MouseButtonEventArgs e) { _dragStartPosition.X = double.MinValue; _dragStartPosition.Y = double.MinValue; _dragObject = null; }
void item_PreviewDragButtonDown(object sender, MouseButtonEventArgs e) { _dragStartPosition = Mouse.GetPosition(null); _dragObject = sender as TimeLineItemControl; }
private void InsertTimeLineItemControlAt(int index, TimeLineItemControl adder) { var Data = adder.DataContext as ITimeLineDataItem; if (Items.Contains(Data)) return; adder.PreviewMouseRightButtonDown -= item_PreviewEditButtonDown; adder.MouseMove -= item_MouseMove; adder.PreviewMouseRightButtonUp -= item_PreviewEditButtonUp; adder.PreviewMouseLeftButtonUp -= item_PreviewDragButtonUp; adder.PreviewMouseLeftButtonDown -= item_PreviewDragButtonDown; adder.PreviewMouseRightButtonDown += item_PreviewEditButtonDown; adder.MouseMove += item_MouseMove; adder.PreviewMouseRightButtonUp += item_PreviewEditButtonUp; adder.PreviewMouseLeftButtonUp += item_PreviewDragButtonUp; adder.PreviewMouseLeftButtonDown += item_PreviewDragButtonDown; //child 0 is our grid and we want to keep that there. Children.Insert(index + 1, adder); Items.Insert(index, Data); }
/// <summary> /// Returns a list of all timeline controls starting with the current one and moving forward /// so long as they are contiguous. /// </summary> /// <param name="current"></param> /// <returns></returns> private List<TimeLineItemControl> GetTimeLineForwardChain(TimeLineItemControl current, int afterIndex, ref Double chainGap) { List<TimeLineItemControl> returner = new List<TimeLineItemControl>() { current }; Double left = 0, width = 0, end = 0; current.GetPlacementInfo(ref left, ref width, ref end); if (afterIndex < 0) { //we are on the end of the list so there is no limit. chainGap = Double.MaxValue; return returner; } Double bumpThreshold = _bumpThreshold; Double lastAddedEnd = end; while (afterIndex < Items.Count) { left = width = end = 0; var checker = GetTimeLineItemControlAt(afterIndex++); if (checker != null) { checker.GetPlacementInfo(ref left, ref width, ref end); Double gap = left - lastAddedEnd; if (gap > bumpThreshold) { chainGap = gap; return returner; } returner.Add(checker); lastAddedEnd = end; } } //we have chained off to the end and thus have no need to worry about our gap chainGap = Double.MaxValue; return returner; }
/// <summary> /// Returns a list of all timeline controls starting with the current one and moving backwoards /// so long as they are contiguous. If the chain reaches back to the start time of the timeline then the /// ChainsBackToStart boolean is modified to reflect that. /// </summary> /// <param name="current"></param> /// <returns></returns> private List<TimeLineItemControl> GetTimeLineBackwardsChain(TimeLineItemControl current, int prevIndex, ref Boolean ChainsBackToStart, ref Double chainGap) { List<TimeLineItemControl> returner = new List<TimeLineItemControl>() { current }; Double left = 0, width = 0, end = 0; current.GetPlacementInfo(ref left, ref width, ref end); if (prevIndex < 0) { chainGap = Double.MaxValue; ChainsBackToStart = left == 0; return returner; } Double lastAddedLeft = left; while (prevIndex >= 0) { left = width = end = 0; var checker = GetTimeLineItemControlAt(prevIndex--); if (checker != null) { checker.GetPlacementInfo(ref left, ref width, ref end); if (lastAddedLeft - end > _bumpThreshold) { //our chain just broke; chainGap = lastAddedLeft - end; ChainsBackToStart = lastAddedLeft == 0; return returner; } returner.Add(checker); lastAddedLeft = left; } } ChainsBackToStart = lastAddedLeft == 0; chainGap = lastAddedLeft;//gap between us and zero; return returner; }
private static void OnEditThresholdChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { TimeLineItemControl ctrl = d as TimeLineItemControl; }