private TimeSpan PixelsToTimespan(double pixelCount, TimelineScroller rootWindow)
        {
            double percent   = pixelCount / rootWindow.ActualWidth;
            var    viewRange = this.Navigator.ViewRange;

            return(TimeSpan.FromTicks((long)((double)viewRange.Duration.Ticks * percent)));
        }
Ejemplo n.º 2
0
        private DateTime GetTimeAtMousePointer(MouseEventArgs e)
        {
            TimelineScroller root = this.FindTimelineScroller(e.Source);

            if (root != null)
            {
                Point    point     = e.GetPosition(root);
                double   percent   = point.X / root.ActualWidth;
                var      viewRange = this.Navigator.ViewRange;
                DateTime time      = viewRange.StartTime + TimeSpan.FromTicks((long)((double)viewRange.Duration.Ticks * percent));

                // If we're currently snapping to some Visualization Object, adjust the time to the timestamp of the nearest message
                DateTime?snappedTime = null;
                PlotVisualizationObject snapToVisualizationObject = this.Container.SnapToVisualizationObject as PlotVisualizationObject;
                if (snapToVisualizationObject != null)
                {
                    snappedTime = snapToVisualizationObject.GetTimeOfNearestMessage(time, snapToVisualizationObject.SummaryData?.Count ?? 0, (idx) => snapToVisualizationObject.SummaryData[idx].OriginatingTime);
                }

                return(snappedTime ?? time);
            }

            Console.WriteLine("TimelineVisualizationPanel.GetTimeAtMousePointer() - Could not find the TimelineScroller in the tree");
            return(DateTime.UtcNow);
        }
        private void DragAnnotationEdge(MouseEventArgs e)
        {
            // Get the timeline scroller
            TimelineScroller timelineScroller = this.FindTimelineScroller(e.Source);

            // Get the time at the mouse cursor
            DateTime cursorTime = this.GetTimeAtMousePointer(e.GetPosition(e.Source as IInputElement), timelineScroller, true);

            // Make sure we stay within bounds
            if (cursorTime < this.annotationDragInfo.MinimumTime)
            {
                cursorTime = this.annotationDragInfo.MinimumTime;
            }

            if (cursorTime > this.annotationDragInfo.MaximumTime)
            {
                cursorTime = this.annotationDragInfo.MaximumTime;
            }

            // Set the new positions of the ends of the annotation(s)
            if (this.annotationDragInfo.LeftAnnotation != null)
            {
                this.annotationDragInfo.LeftAnnotation.Interval = new TimeInterval(this.annotationDragInfo.LeftAnnotation.Interval.Left, cursorTime);
            }

            if (this.annotationDragInfo.RightAnnotation != null)
            {
                this.annotationDragInfo.RightAnnotation.Interval = new TimeInterval(cursorTime, this.annotationDragInfo.RightAnnotation.Interval.Right);
            }

            this.UpdateDisplayData();

            VisualizationContext.Instance.VisualizationContainer.Navigator.Cursor = cursorTime;
        }
        private void DoMouseDoubleClick(MouseButtonEventArgs e)
        {
            // Get the timeline scroller
            TimelineScroller timelineScroller = this.FindTimelineScroller(e.Source);

            // Get the time at the mouse cursor
            DateTime cursorTime = this.GetTimeAtMousePointer(e.GetPosition(e.Source as IInputElement), timelineScroller, false);

            // Get the item (if any) that straddles this time
            int index = this.GetAnnotationIndexByTime(cursorTime);

            if (index > -1)
            {
                // Get the annotation that was hit
                Message <TimeIntervalAnnotation> annotation = this.Data[index];

                // Set the navigator selection to the bounds of the annotation
                TimeInterval annotationRange = annotation.Data.Interval;
                VisualizationContext.Instance.VisualizationContainer.Navigator.SelectionRange.SetRange(annotationRange);

                // If the shift key was down, then also zoom to the annotation (with 10% empty space to the left and right)
                if (Keyboard.IsKeyDown(Key.LeftShift) || Keyboard.IsKeyDown(Key.RightShift))
                {
                    double bufferSeconds = annotationRange.Span.TotalSeconds * 0.1d;
                    VisualizationContext.Instance.VisualizationContainer.Navigator.ViewRange.SetRange(annotationRange.Left.AddSeconds(-bufferSeconds), annotationRange.Right.AddSeconds(bufferSeconds));
                }
            }
        }
Ejemplo n.º 5
0
        private DateTime GetTimeAtMousePointer(MouseEventArgs e)
        {
            TimelineScroller root = this.FindTimelineScroller(e.Source);

            if (root != null)
            {
                Point    point     = e.GetPosition(root);
                double   percent   = point.X / root.ActualWidth;
                var      viewRange = this.Navigator.ViewRange;
                DateTime time      = viewRange.StartTime + TimeSpan.FromTicks((long)((double)viewRange.Duration.Ticks * percent));
                return(time);
            }

            Console.WriteLine("TimelineVisualizationPanel.GetTimeAtMousePointer() - Could not find the TimelineScroller in the tree");
            return(DateTime.UtcNow);
        }
Ejemplo n.º 6
0
        /// <summary>
        /// Gets the timeline scroller parent of a framework element.
        /// </summary>
        /// <param name="sourceElement">The framework element to search from.</param>
        /// <returns>The timeline scroller object.</returns>
        public TimelineScroller GetTimelineScroller(object sourceElement)
        {
            if (this.timelineScroller == null)
            {
                // Walk up the visual tree until we either find the
                // Timeline Scroller or fall off the top of the tree
                DependencyObject target = sourceElement as DependencyObject;
                while (target != null && !(target is TimelineScroller))
                {
                    target = VisualTreeHelper.GetParent(target);
                }

                this.timelineScroller = target as TimelineScroller;
            }

            return(this.timelineScroller);
        }
        private DateTime GetTimeAtMousePointer(Point point, TimelineScroller root, bool useSnap)
        {
            double   percent   = point.X / root.ActualWidth;
            var      viewRange = this.Navigator.ViewRange;
            DateTime time      = viewRange.StartTime + TimeSpan.FromTicks((long)((double)viewRange.Duration.Ticks * percent));

            // If we're currently snapping to some Visualization Object, adjust the time to the timestamp of the nearest message
            DateTime?snappedTime = null;

            if (useSnap)
            {
                IStreamVisualizationObject snapToVisualizationObject = this.Container.SnapToVisualizationObject as IStreamVisualizationObject;
                if (snapToVisualizationObject != null)
                {
                    snappedTime = snapToVisualizationObject.GetSnappedTime(time, SnappingBehavior.Nearest);
                }
            }

            return(snappedTime ?? time);
        }
        private void DoMouseMove(MouseEventArgs e)
        {
            if (this.annotationDragInfo != null)
            {
                this.DragAnnotationEdge(e);
                e.Handled = true;
            }
            else
            {
                // Get the timeline scroller and the canvas
                TimelineScroller timelineScroller = this.FindTimelineScroller(e.Source);
                Canvas           canvas           = this.FindCanvas(e.Source);

                // Get the time at the mouse cursor
                DateTime cursorTime = this.GetTimeAtMousePointer(e.GetPosition(e.Source as IInputElement), timelineScroller, false);

                // Get the item (if any) that straddles this time
                if (this.EnableAnnotationDrag)
                {
                    int index = this.GetAnnotationIndexByTime(cursorTime);
                    if (index > -1)
                    {
                        AnnotationEdge annotationEdge = this.MouseOverAnnotationEdge(cursorTime, this.Data[index].Data, timelineScroller);
                        if (annotationEdge != AnnotationEdge.None)
                        {
                            canvas.Cursor = Cursors.SizeWE;
                        }
                        else
                        {
                            canvas.Cursor = Cursors.Arrow;
                        }
                    }
                    else
                    {
                        canvas.Cursor = Cursors.Arrow;
                    }
                }
            }
        }
Ejemplo n.º 9
0
        /// <summary>
        /// Gets the time at the mouse pointer, optionally adjusting for visualization object snap.
        /// </summary>
        /// <param name="mouseEventArgs">A mouse event args object.</param>
        /// <param name="useSnap">If true, and if a visualization object is currently being snapped to, then adjust the time to the nearest message in the visualization object being snapped to.</param>
        /// <returns>The time represented by the mouse pointer.</returns>
        public DateTime GetTimeAtMousePointer(MouseEventArgs mouseEventArgs, bool useSnap)
        {
            TimelineScroller root = this.GetTimelineScroller(mouseEventArgs.Source);

            if (root != null)
            {
                Point    point     = mouseEventArgs.GetPosition(root);
                double   percent   = point.X / root.ActualWidth;
                var      viewRange = this.Navigator.ViewRange;
                DateTime time      = viewRange.StartTime + TimeSpan.FromTicks((long)((double)viewRange.Duration.Ticks * percent));

                // If we're currently snapping to some Visualization Object, adjust the time to the timestamp of the nearest message
                DateTime?snappedTime = null;
                if (useSnap == true && VisualizationContext.Instance.VisualizationContainer.SnapToVisualizationObject is IStreamVisualizationObject snapToVisualizationObject)
                {
                    snappedTime = DataManager.Instance.GetTimeOfNearestMessage(snapToVisualizationObject.StreamSource, time, NearestMessageType.Nearest);
                }

                return(snappedTime ?? time);
            }

            return(DateTime.UtcNow);
        }
Ejemplo n.º 10
0
        private DateTime GetTimeAtMousePointer(MouseEventArgs e)
        {
            TimelineScroller root = this.FindTimelineScroller(e.Source);

            if (root != null)
            {
                Point    point     = e.GetPosition(root);
                double   percent   = point.X / root.ActualWidth;
                var      viewRange = this.Navigator.ViewRange;
                DateTime time      = viewRange.StartTime + TimeSpan.FromTicks((long)((double)viewRange.Duration.Ticks * percent));

                // If we're currently snapping to some Visualization Object, adjust the time to the timestamp of the nearest message
                DateTime?snappedTime = null;
                if (VisualizationContext.Instance.VisualizationContainer.SnapToVisualizationObject is IStreamVisualizationObject snapToVisualizationObject)
                {
                    snappedTime = snapToVisualizationObject.GetSnappedTime(time);
                }

                return(snappedTime ?? time);
            }

            Debug.WriteLine("TimelineVisualizationPanel.GetTimeAtMousePointer() - Could not find the TimelineScroller in the tree");
            return(DateTime.UtcNow);
        }
        private AnnotationEdge MouseOverAnnotationEdge(DateTime cursorTime, TimeIntervalAnnotation annotation, TimelineScroller timelineScroller)
        {
            // Work out what time interval is expressed in 3 pixels at the current zoom
            double   percent        = 5.0d / timelineScroller.ActualWidth;
            var      viewRange      = this.Navigator.ViewRange;
            TimeSpan hitTargetWidth = TimeSpan.FromTicks((long)((double)viewRange.Duration.Ticks * percent));

            // Check if the mouse cursor is within 3 pixels of the left or right edge of the annoation
            if (Math.Abs((annotation.Interval.Left - cursorTime).Ticks) <= hitTargetWidth.Ticks)
            {
                return(AnnotationEdge.Left);
            }

            if (Math.Abs((annotation.Interval.Right - cursorTime).Ticks) <= hitTargetWidth.Ticks)
            {
                return(AnnotationEdge.Right);
            }

            return(AnnotationEdge.None);
        }
        private void DoMouseLeftButtonDown(MouseButtonEventArgs e)
        {
            TimelineVisualizationPanel timelinePanel = this.Panel as TimelineVisualizationPanel;

            // Get the time at the mouse cursor
            DateTime cursorTime = timelinePanel.GetTimeAtMousePointer(e, false);

            Message <TimeIntervalAnnotation> annotation = default;
            AnnotationEdge annotationEdge = AnnotationEdge.None;

            // Get the item (if any) that straddles this time
            int index = this.GetAnnotationIndexByTime(cursorTime);

            if (index > -1)
            {
                // Get the annotation that was hit
                annotation = this.Data[index];

                // Check if the mouse is over an edge of the annotation
                annotationEdge = this.MouseOverAnnotationEdge(cursorTime, this.Data[index].Data, timelinePanel.GetTimelineScroller(e.Source));
            }

            // If the shift key is down, the user is dropping the start selection marker. If there is no VO currently being snapped
            // to and the mouse is over an annotation edge, then manually set the selection marker right on the edge. Otherwise
            // let the event bubble up to the timeline visualization panel which will set the selection marker in the usual fashion.
            if (Keyboard.IsKeyDown(Key.LeftShift) || Keyboard.IsKeyDown(Key.RightShift))
            {
                if ((VisualizationContext.Instance.VisualizationContainer.SnapToVisualizationObject == null) && (annotationEdge != AnnotationEdge.None))
                {
                    DateTime selectionMarkerTime = annotationEdge == AnnotationEdge.Left ? annotation.Data.Interval.Left : annotation.Data.Interval.Right;
                    this.Navigator.SelectionRange.SetRange(selectionMarkerTime, this.Navigator.SelectionRange.EndTime >= selectionMarkerTime ? this.Navigator.SelectionRange.EndTime : DateTime.MaxValue);
                    e.Handled = true;
                }
                else
                {
                    return;
                }
            }

            // If we're over an annotation
            if (annotation != default)
            {
                if (annotationEdge == AnnotationEdge.None)
                {
                    // We're over an annotation, but not an annotation edge, display the annotation's properties
                    this.SelectDisplayObject(annotation.Data);

                    // Begin annotation edit if it's enabled
                    if (this.EnableAnnotationValueEdit)
                    {
                        // Work out the track number to be edited based on the mouse position
                        TimelineScroller timelineScroller = timelinePanel.GetTimelineScroller(e.Source);
                        Point            point            = e.GetPosition(timelineScroller);
                        int trackId = (int)(point.Y / timelineScroller.ActualHeight * (double)annotation.Data.Values.Count);

                        // Find the display data object corresponding to the annotation and fire an edit event to the view
                        TimeIntervalAnnotationDisplayData displayObject = this.DisplayData.FirstOrDefault(d => d.Annotation.Data.Interval.Right == annotation.Data.Interval.Right);
                        this.TimeIntervalAnnotationEdit?.Invoke(this, new TimeIntervalAnnotationEditEventArgs(displayObject, trackId));
                    }
                }

                // Check if we're over an edge and annotation drag is enabled.
                if (annotationEdge != AnnotationEdge.None && this.EnableAnnotationDrag)
                {
                    // Get the previous and next annotations (if any) and check if they abut the annotation whose edge we're going to drag
                    Message <TimeIntervalAnnotation>?previousAnnotation = index > 0 ? this.Data[index - 1] : (Message <TimeIntervalAnnotation>?)null;
                    bool previousAnnotationAbuts = previousAnnotation != null && previousAnnotation.Value.Data.Interval.Right == annotation.Data.Interval.Left;
                    Message <TimeIntervalAnnotation>?nextAnnotation = index < this.Data.Count - 1 ? this.Data[index + 1] : (Message <TimeIntervalAnnotation>?)null;
                    bool nextAnnotationAbuts = nextAnnotation != null && nextAnnotation.Value.Data.Interval.Left == annotation.Data.Interval.Right;

                    // If the ALT key is down, then we will not try to move the annotation that abuts this one
                    bool moveNeighborAnnotation = !Keyboard.IsKeyDown(Key.LeftAlt) && !Keyboard.IsKeyDown(Key.RightAlt);

                    // Work out the minimum and maximum times we can drag the annotation's edge to
                    DateTime minTime;
                    DateTime maxTime;
                    if (annotationEdge == AnnotationEdge.Left)
                    {
                        maxTime = annotation.Data.Interval.Right;
                        if (previousAnnotation == null)
                        {
                            minTime = this.Navigator.ViewRange.StartTime;
                        }
                        else if (previousAnnotationAbuts && moveNeighborAnnotation)
                        {
                            minTime = previousAnnotation.Value.Data.Interval.Left;
                        }
                        else
                        {
                            minTime = previousAnnotation.Value.Data.Interval.Right;
                        }
                    }
                    else
                    {
                        minTime = annotation.Data.Interval.Left;
                        if (nextAnnotation == null)
                        {
                            maxTime = this.Navigator.ViewRange.EndTime;
                        }
                        else if (nextAnnotationAbuts && moveNeighborAnnotation)
                        {
                            maxTime = nextAnnotation.Value.Data.Interval.Right;
                        }
                        else
                        {
                            maxTime = nextAnnotation.Value.Data.Interval.Left;
                        }
                    }

                    // Create the drag data that specifies which annotation(s) to drag, and the minimum and maximum time we can drag to
                    if (annotationEdge == AnnotationEdge.Right)
                    {
                        this.annotationDragInfo = new TimeIntervalAnnotationDragInfo(annotation, moveNeighborAnnotation && nextAnnotationAbuts ? nextAnnotation : null, minTime, maxTime);
                    }
                    else
                    {
                        this.annotationDragInfo = new TimeIntervalAnnotationDragInfo(moveNeighborAnnotation && previousAnnotationAbuts ? previousAnnotation : null, annotation, minTime, maxTime);
                    }
                }
            }
            else
            {
                // We're not over any annotation, cancel any current edit operation in the view and display the VO's properties
                this.TimeIntervalAnnotationEdit?.Invoke(this, new TimeIntervalAnnotationEditEventArgs(null, 0));
                this.SelectDisplayObject(null);
            }
        }
        private AnnotationEdge MouseOverAnnotationEdge(DateTime cursorTime, TimeIntervalAnnotation annotation, TimelineScroller timelineScroller)
        {
            // Work out what time interval is expressed in 3 pixels at the current zoom
            TimeSpan hitTargetWidth = this.PixelsToTimespan(5.0d, timelineScroller);

            // Check if the mouse cursor is within 3 pixels of the left or right edge of the annoation
            if (Math.Abs((annotation.Interval.Left - cursorTime).Ticks) <= hitTargetWidth.Ticks)
            {
                return(AnnotationEdge.Left);
            }

            if (Math.Abs((annotation.Interval.Right - cursorTime).Ticks) <= hitTargetWidth.Ticks)
            {
                return(AnnotationEdge.Right);
            }

            return(AnnotationEdge.None);
        }
        private void DoMouseLeftButtonDown(MouseButtonEventArgs e)
        {
            // Get the timeline scroller
            TimelineScroller timelineScroller = this.FindTimelineScroller(e.Source);

            // Get the time at the mouse cursor
            DateTime cursorTime = this.GetTimeAtMousePointer(e.GetPosition(e.Source as IInputElement), timelineScroller, false);

            // Get the item (if any) that straddles this time
            int index = this.GetAnnotationIndexByTime(cursorTime);

            if (index > -1)
            {
                // Get the annotation that was hit
                Message <TimeIntervalAnnotation> annotation = this.Data[index];

                Canvas canvas = this.FindCanvas(e.Source);

                // Check if the mouse is over an edge of the annotation
                AnnotationEdge annotationEdge = this.MouseOverAnnotationEdge(cursorTime, this.Data[index].Data, timelineScroller);
                if (annotationEdge != AnnotationEdge.None && this.EnableAnnotationDrag)
                {
                    // Get the previous and next annotations (if any) and check if they abut the annotation whose edge we're going to drag
                    Message <TimeIntervalAnnotation>?previousAnnotation = index > 0 ? this.Data[index - 1] : (Message <TimeIntervalAnnotation>?)null;
                    bool previousAnnotationAbuts = previousAnnotation != null && previousAnnotation.Value.Data.Interval.Right == annotation.Data.Interval.Left;
                    Message <TimeIntervalAnnotation>?nextAnnotation = index < this.Data.Count - 1 ? this.Data[index + 1] : (Message <TimeIntervalAnnotation>?)null;
                    bool nextAnnotationAbuts = nextAnnotation != null && nextAnnotation.Value.Data.Interval.Left == annotation.Data.Interval.Right;

                    // If the ALT key is down, then we will not try to move the annotation that abuts this one
                    bool moveNeighborAnnotation = !Keyboard.IsKeyDown(Key.LeftAlt) && !Keyboard.IsKeyDown(Key.RightAlt);

                    // Work out the minimum and maximum times we can drag the annotation's edge to
                    DateTime minTime;
                    DateTime maxTime;
                    if (annotationEdge == AnnotationEdge.Left)
                    {
                        maxTime = annotation.Data.Interval.Right;
                        if (previousAnnotation == null)
                        {
                            minTime = this.Navigator.ViewRange.StartTime;
                        }
                        else if (previousAnnotationAbuts && moveNeighborAnnotation)
                        {
                            minTime = previousAnnotation.Value.Data.Interval.Left;
                        }
                        else
                        {
                            minTime = previousAnnotation.Value.Data.Interval.Right;
                        }
                    }
                    else
                    {
                        minTime = annotation.Data.Interval.Left;
                        if (nextAnnotation == null)
                        {
                            maxTime = this.Navigator.ViewRange.EndTime;
                        }
                        else if (nextAnnotationAbuts && moveNeighborAnnotation)
                        {
                            maxTime = nextAnnotation.Value.Data.Interval.Right;
                        }
                        else
                        {
                            maxTime = nextAnnotation.Value.Data.Interval.Left;
                        }
                    }

                    // Create the drag data that specifies which annotation(s) to drag, and the minimum and maximum time we can drag to
                    if (annotationEdge == AnnotationEdge.Right)
                    {
                        this.annotationDragInfo = new TimeIntervalAnnotationDragInfo(annotation, moveNeighborAnnotation && nextAnnotationAbuts ? nextAnnotation : null, minTime, maxTime);
                    }
                    else
                    {
                        this.annotationDragInfo = new TimeIntervalAnnotationDragInfo(moveNeighborAnnotation && previousAnnotationAbuts ? previousAnnotation : null, annotation, minTime, maxTime);
                    }
                }
                else
                {
                    this.SelectDisplayObject(annotation.Data);
                }

                e.Handled = true;
            }
            else
            {
                this.SelectDisplayObject(null);
            }
        }