コード例 #1
0
        public override void Draw(DrawingContext drawingContext, ulong firstVisibleTick, ulong lastVisibleTick)
        {
            Rect r = new Rect(0, 0, this.ActualWidth, this.ActualHeight);

            drawingContext.DrawRectangle(this.IsKeyboardFocused ? this.FocusedBackground : this.Background, null, r);

            if (this.DataSource == null)
            {
                return;
            }

            UpdateBitmap();

            drawingContext.PushClip(new RectangleGeometry(r));

            List<LabeledRange> labeledRanges = new List<LabeledRange>();
            FormattedText ftLabel = null;
            const double textMargin = 3;

            if (this.LabelFontSize > 0)
            {
                // Calculate label rect requirements
                foreach (var selectedNode in this.selectedNodes)
                {
                    // We're +1 because there is some kind of sub-pixel misalignment between the event lane itself and the bitmap.
                    var middle = TimeAxis.TimeToScreen(selectedNode.StartTime + (selectedNode.Duration / 2)) + 1;
                    var x1 = TimeAxis.TimeToScreen(selectedNode.StartTime) + 1;
                    var x2 = TimeAxis.TimeToScreen(selectedNode.StartTime + selectedNode.Duration) + 1;
                    if (x1 <= this.PixelWidth && x2 > 0)
                    {
                        if (ftLabel == null)
                        {
                            // NOTE: It is assumed that all selected nodes have the same name...
                            ftLabel = new FormattedText(selectedNode.Name, CultureInfo.CurrentCulture, FlowDirection.LeftToRight,
                                this.labelTypeface, this.LabelFontSize, this.IsKeyboardFocused ? this.FocusedSelectionForeground : this.SelectionForeground);
                        }

                        // Try to center the label under the node.  But adjust its position if it 
                        // is clipped by the left or right edge of the timeline.
                        var left = middle - ftLabel.Width / 2;
                        if (left < textMargin)
                        {
                            left = textMargin;
                        }
                        else if (left + ftLabel.Width > this.ActualWidth - textMargin)
                        {
                            left = this.ActualWidth - textMargin - ftLabel.Width;
                        }

                        // Create a labeled range for this label
                        var range = new LabeledRange();
                        range.Start = x1;
                        range.End = x2;
                        range.Rect = new Rect(left, this.palette.BitmapPixelHeight, ftLabel.Width, this.SelectionFanHeight + this.labelTextHeight + (this.LabelMargin * 2));
                        range.Rect.Inflate(textMargin, 0);
                        range.ContainsPrimaryNode = (selectedNode == this.primarySelectedNode);

                        labeledRanges.Add(range);
                    }
                }
            }

            if (ftLabel != null)
            {
                List<LabeledRange> mergedRanges = new List<LabeledRange>(labeledRanges.Count);

                // Merge the overlapping label rects together
                while (labeledRanges.Count > 0)
                {
                    LabeledRange range = labeledRanges[0];

                    labeledRanges.RemoveAt(0);

                    for (int i = 0; i < labeledRanges.Count; )
                    {
                        if (range.Rect.IntersectsWith(labeledRanges[i].Rect))
                        {
                            range.Union(labeledRanges[i]);
                            labeledRanges.RemoveAt(i);
                        }
                        else
                        {
                            i++;
                        }
                    }

                    double centerX = range.Rect.Left + (range.Rect.Width / 2) - (ftLabel.Width / 2);
                    range.Rect = new Rect(centerX, range.Rect.Top, ftLabel.Width, range.Rect.Height);
                    range.Rect.Inflate(textMargin, 0);
                    mergedRanges.Add(range);
                }

                double textRectTop = this.DesiredSize.Height - (ftLabel.Height + this.LabelMargin + this.BottomMargin);
                double textRectBottom = this.DesiredSize.Height - this.BottomMargin;

                // Draw the remaining labeled ranges
                foreach (var range in mergedRanges)
                {
                    double centerX = range.Rect.Left + (range.Rect.Width / 2) - (ftLabel.Width / 2);
                    var geometry = new StreamGeometry() { FillRule = FillRule.EvenOdd };

                    using (StreamGeometryContext ctx = geometry.Open())
                    {
                        ctx.BeginFigure(new Point(range.End, range.Rect.Top), isFilled: true, isClosed: true);
                        ctx.LineTo(new Point(range.Rect.Right, textRectTop), true, true);
                        ctx.LineTo(new Point(range.Rect.Right, textRectBottom), true, true);
                        ctx.LineTo(new Point(range.Rect.Left, textRectBottom), true, true);
                        ctx.LineTo(new Point(range.Rect.Left, textRectTop), true, true);

                        if (range.SubRanges == null)
                        {
                            ctx.LineTo(new Point(range.Start, range.Rect.Top), true, true);
                        }
                        else
                        {
                            double inc = range.Rect.Width / range.SubRanges.Count;
                            double nextValley = range.Rect.Left + inc;

                            for (int i = 0; i < range.SubRanges.Count; i++)
                            {
                                var subrange = range.SubRanges[i];

                                ctx.LineTo(new Point(subrange.Item1, range.Rect.Top), true, true);
                                if (i < range.SubRanges.Count - 1)
                                {
                                    ctx.LineTo(new Point(subrange.Item2, range.Rect.Top), false, true);
                                    ctx.LineTo(new Point(nextValley, textRectTop), true, true);
                                    nextValley += inc;
                                }
                            }
                        }

                        ctx.LineTo(new Point(range.End, range.Rect.Top), false, true);
                    }

                    var brush = this.Background;
                    var foreground = this.Foreground;

                    if (this.IsKeyboardFocused)
                    {
                        if (range.ContainsPrimaryNode)
                        {
                            brush = this.FocusedSelectionBackground;
                            foreground = this.FocusedSelectionForeground;
                        }
                        else
                        {
                            brush = this.FocusedBackground;
                            foreground = this.FocusedForeground;
                        }
                    }

                    drawingContext.DrawGeometry(brush, this.standardPen, geometry);
                    ftLabel.SetForegroundBrush(foreground);
                    drawingContext.DrawText(ftLabel, new Point(centerX, textRectTop));
                }
            }

            drawingContext.Pop();
        }
コード例 #2
0
            public void Union(LabeledRange range)
            {
                if (this.SubRanges == null)
                {
                    this.SubRanges = new List<Tuple<double, double>>();
                    this.SubRanges.Add(new Tuple<double, double>(this.Start, this.End));
                }

                this.Start = Math.Min(this.Start, range.Start);
                this.End = Math.Max(this.End, range.End);
                this.Rect.Union(range.Rect);

                if (range.SubRanges == null)
                {
                    this.SubRanges.Add(new Tuple<double, double>(range.Start, range.End));
                }
                else
                {
                    this.SubRanges.AddRange(range.SubRanges);
                }

                this.ContainsPrimaryNode |= range.ContainsPrimaryNode;
            }