Beispiel #1
0
        /// <summary>
        /// Finds a container for a new visual based on the drawing attributes
        /// of the stroke rendered into that visual.
        /// </summary>
        /// <param name="drawingAttributes">drawing attributes</param>
        /// <returns>visual</returns>
        private ContainerVisual GetContainerVisual(DrawingAttributes drawingAttributes)
        {
            System.Diagnostics.Debug.Assert(drawingAttributes != null);

            HighlighterContainerVisual hcVisual;

            if (drawingAttributes.IsHighlighter)
            {
                // For a highlighter stroke, the color.A is neglected.
                Color color = StrokeRenderer.GetHighlighterColor(drawingAttributes.Color);
                if ((_highlighters == null) || (_highlighters.TryGetValue(color, out hcVisual) == false))
                {
                    if (_highlighters == null)
                    {
                        _highlighters = new Dictionary <Color, HighlighterContainerVisual>();
                    }

                    hcVisual         = new HighlighterContainerVisual(color);
                    hcVisual.Opacity = StrokeRenderer.HighlighterOpacity;
                    _highlightersRoot.Children.Add(hcVisual);

                    _highlighters.Add(color, hcVisual);
                }
                else if (VisualTreeHelper.GetParent(hcVisual) == null)
                {
                    _highlightersRoot.Children.Add(hcVisual);
                }
                return(hcVisual);
            }
            else
            {
                return(_regularInkVisuals);
            }
        }
Beispiel #2
0
            /// <summary>
            /// Updates the contents of the visual.
            /// </summary>
            internal void Update()
            {
                using (DrawingContext drawingContext = RenderOpen())
                {
                    bool highContrast = _renderer.IsHighContrast();

                    if (highContrast == true && _stroke.DrawingAttributes.IsHighlighter)
                    {
                        // we don't render highlighters in high contrast
                        return;
                    }

                    DrawingAttributes da;
                    if (highContrast)
                    {
                        da       = _stroke.DrawingAttributes.Clone();
                        da.Color = _renderer.GetHighContrastColor();
                    }
                    else if (_stroke.DrawingAttributes.IsHighlighter == true)
                    {
                        // Get the drawing attributes to use for a highlighter stroke. This can be a copied DA with color.A
                        // overridden if color.A != 255.
                        da = StrokeRenderer.GetHighlighterAttributes(_stroke, _stroke.DrawingAttributes);
                    }
                    else
                    {
                        // Otherwise, usethe DA on this stroke
                        da = _stroke.DrawingAttributes;
                    }

                    // Draw selected stroke as hollow
                    _stroke.DrawInternal(drawingContext, da, _stroke.IsSelected);
                }
            }
Beispiel #3
0
        /// <summary>
        /// Render the StrokeCollection under the specified DrawingContext. This draw method uses the
        /// passing in drawing attribute to override that on the stroke.
        /// </summary>
        /// <param name="drawingContext"></param>
        /// <param name="drawingAttributes"></param>
        public void Draw(DrawingContext drawingContext, DrawingAttributes drawingAttributes)
        {
            if (null == drawingContext)
            {
                throw new System.ArgumentNullException("context");
            }

            if (null == drawingAttributes)
            {
                throw new System.ArgumentNullException("drawingAttributes");
            }

            //             context.VerifyAccess();

            //our code never calls this public API so we can assume that opacity
            //has not been set up

            if (drawingAttributes.IsHighlighter)
            {
                drawingContext.PushOpacity(StrokeRenderer.HighlighterOpacity);
                try
                {
                    this.DrawInternal(drawingContext, StrokeRenderer.GetHighlighterAttributes(this, this.DrawingAttributes), false);
                }
                finally
                {
                    drawingContext.Pop();
                }
            }
            else
            {
                this.DrawInternal(drawingContext, drawingAttributes, false);
            }
        }
Beispiel #4
0
        /// <summary>
        /// Stroke Invalidated event handler
        /// </summary>
        private void OnStrokeInvalidated(object sender, EventArgs eventArgs)
        {
            System.Diagnostics.Debug.Assert(_strokes.IndexOf(sender as Stroke) != -1);

            // Find the visual associated with the changed stroke.
            StrokeVisual visual;
            Stroke       stroke = (Stroke)sender;

            if (_visuals.TryGetValue(stroke, out visual) == false)
            {
                throw new System.ArgumentException(SR.Get(SRID.UnknownStroke1));
            }

            // The original value of IsHighligher and Color are cached in StrokeVisual.
            // if (IsHighlighter value changed or (IsHighlighter == true and not changed and color changed)
            // detach and re-attach the corresponding visual;
            // otherwise Invalidate the corresponding StrokeVisual
            if (visual.CachedIsHighlighter != stroke.DrawingAttributes.IsHighlighter ||
                (stroke.DrawingAttributes.IsHighlighter &&
                 StrokeRenderer.GetHighlighterColor(visual.CachedColor) != StrokeRenderer.GetHighlighterColor(stroke.DrawingAttributes.Color)))
            {
                // The change requires reparenting the visual in the tree.
                DetachVisual(visual);
                AttachVisual(visual, false /*buildingStrokeCollection*/);

                // Update the cached values
                visual.CachedIsHighlighter = stroke.DrawingAttributes.IsHighlighter;
                visual.CachedColor         = stroke.DrawingAttributes.Color;
            }
            // Update the visual.
            visual.Update();
        }
Beispiel #5
0
        /// <summary>
        /// Render the StrokeCollection under the specified DrawingContext.
        /// </summary>
        /// <param name="context"></param>
        public void Draw(DrawingContext context)
        {
            if (null == context)
            {
                throw new System.ArgumentNullException("context");
            }

            //The verification of UI context affinity is done in Stroke.Draw()

            List <Stroke> solidStrokes = new List <Stroke>();
            Dictionary <Color, List <Stroke> > highLighters = new Dictionary <Color, List <Stroke> >();

            for (int i = 0; i < this.Count; i++)
            {
                Stroke        stroke = this[i];
                List <Stroke> strokes;
                if (stroke.DrawingAttributes.IsHighlighter)
                {
                    // It's very important to override the Alpha value so that Colors of the same RGB vale
                    // but different Alpha would be in the same list.
                    Color color = StrokeRenderer.GetHighlighterColor(stroke.DrawingAttributes.Color);
                    if (highLighters.TryGetValue(color, out strokes) == false)
                    {
                        strokes = new List <Stroke>();
                        highLighters.Add(color, strokes);
                    }
                    strokes.Add(stroke);
                }
                else
                {
                    solidStrokes.Add(stroke);
                }
            }

            foreach (List <Stroke> strokes in highLighters.Values)
            {
                context.PushOpacity(StrokeRenderer.HighlighterOpacity);
                try
                {
                    foreach (Stroke stroke in strokes)
                    {
                        stroke.DrawInternal(context, StrokeRenderer.GetHighlighterAttributes(stroke, stroke.DrawingAttributes),
                                            false /*Don't draw selected stroke as hollow*/);
                    }
                }
                finally
                {
                    context.Pop();
                }
            }

            foreach (Stroke stroke in solidStrokes)
            {
                stroke.DrawInternal(context, stroke.DrawingAttributes, false /*Don't draw selected stroke as hollow*/);
            }
        }
Beispiel #6
0
        /// <summary>
        /// Get the Geometry of the Stroke
        /// </summary>
        /// <param name="drawingAttributes"></param>
        /// <returns></returns>
        public Geometry GetGeometry(DrawingAttributes drawingAttributes)
        {
            if (drawingAttributes == null)
            {
                throw new ArgumentNullException("drawingAttributes");
            }

            bool geometricallyEqual = DrawingAttributes.GeometricallyEqual(drawingAttributes, this.DrawingAttributes);

            // need to recalculate the PathGemetry if the DA passed in is "geometrically" different from
            // this DA, or if the cached PathGeometry is dirty.
            if (false == geometricallyEqual || (true == geometricallyEqual && null == _cachedGeometry))
            {
                //Recalculate _pathGeometry;
                StrokeNodeIterator iterator = StrokeNodeIterator.GetIterator(this, drawingAttributes);
                Geometry           geometry;
                Rect bounds;
                StrokeRenderer.CalcGeometryAndBounds(iterator,
                                                     drawingAttributes,
#if DEBUG_RENDERING_FEEDBACK
                                                     null, 0d, false,
#endif
                                                     true, //calc bounds
                                                     out geometry,
                                                     out bounds);

                // return the calculated value directly. We cannot cache the result since the DA passed in
                // is "geometrically" different from this.DrawingAttributes.
                if (false == geometricallyEqual)
                {
                    return(geometry);
                }

                // Cache the value and set _isPathGeometryDirty to false;
                SetGeometry(geometry);
                SetBounds(bounds);

                return(geometry);
            }

            // return a ref to our _cachedGeometry
            System.Diagnostics.Debug.Assert(_cachedGeometry != null && _cachedGeometry.IsFrozen);
            return(_cachedGeometry);
        }
Beispiel #7
0
        public static void CalcGeometryAndBoundsWithTransform()
        {
            var drawingAttribute   = new DrawingAttributes();
            var strokeNodeIterator = StrokeNodeIterator.GetIterator(new StylusPointCollection(new Point[]
            {
                new Point(10, 10),
                new Point(11, 10),
                new Point(12, 10),
                new Point(13, 10),
                new Point(14, 10),
                new Point(15, 10),
                new Point(15, 11),
                new Point(15, 12),
                new Point(15, 13),
                new Point(15, 14),
                new Point(15, 15),
                new Point(25, 35),
                new Point(35, 15),
                new Point(55, 25),
            }), drawingAttribute);

            StrokeRenderer.CalcGeometryAndBoundsWithTransform(strokeNodeIterator, drawingAttribute,
                                                              MatrixTypes.TRANSFORM_IS_IDENTITY, true, out var geometry, out var bounds);
        }
Beispiel #8
0
        /// <summary>
        /// The core functionality to draw a stroke. The function can be called from the following code paths.
        ///     i) From StrokeVisual.OnRender
        ///         a. Highlighter strokes have been grouped and the correct opacity has been set on the container visual.
        ///         b. For a highlighter stroke with color.A != 255, the DA passed in is a copy with color.A set to 255.
        ///         c. _drawAsHollow can be true, i.e., Selected stroke is drawn as hollow
        ///     ii) From StrokeCollection.Draw.
        ///         a. Highlighter strokes have been grouped and the correct opacity has been pushed.
        ///         b. For a highlighter stroke with color.A != 255, the DA passed in is a copy with color.A set to 255.
        ///         c. _drawAsHollow is always false, i.e., Selected stroke is not drawn as hollow
        ///     iii) From Stroke.Draw
        ///         a. The correct opacity has been pushed for a highlighter stroke
        ///         b. For a highlighter stroke with color.A != 255, the DA passed in is a copy with color.A set to 255.
        ///         c. _drawAsHollow is always false, i.e., Selected stroke is not drawn as hollow
        /// We need to document the following:
        /// 1) our default implementation so developers can see what we've done here -
        ///    including how we handle IsHollow
        /// 2) the fact that opacity has already been set up correctly for the call.
        /// 3) that developers should not call base.DrawCore if they override this
        /// </summary>
        /// <param name="drawingContext">DrawingContext to draw on</param>
        /// <param name="drawingAttributes">DrawingAttributes to draw with</param>
        protected virtual void DrawCore(DrawingContext drawingContext, DrawingAttributes drawingAttributes)
        {
            if (null == drawingContext)
            {
                throw new System.ArgumentNullException("drawingContext");
            }

            if (null == drawingAttributes)
            {
                throw new System.ArgumentNullException("drawingAttributes");
            }

            if (_drawAsHollow == true)
            {
                // Draw as hollow. Our profiler result shows that the two-pass-rendering approach is about 5 times
                // faster that using GetOutlinePathGeometry.
                // also, the minimum display size for selected ink is our default width / height

                Matrix            innerTransform, outerTransform;
                DrawingAttributes selectedDA = drawingAttributes.Clone();
                selectedDA.Height = Math.Max(selectedDA.Height, DrawingAttributes.DefaultHeight);
                selectedDA.Width  = Math.Max(selectedDA.Width, DrawingAttributes.DefaultWidth);
                CalcHollowTransforms(selectedDA, out innerTransform, out outerTransform);

                // First pass drawing. Use drawingAttributes.Color to create a solid color brush. The stroke will be drawn as
                // 1 avalon-unit higher and wider (HollowLineSize = 1.0f)
                selectedDA.StylusTipTransform = outerTransform;
                SolidColorBrush brush = new SolidColorBrush(drawingAttributes.Color);
                brush.Freeze();
                drawingContext.DrawGeometry(brush, null, GetGeometry(selectedDA));

                //Second pass drawing with a white color brush. The stroke will be drawn as
                // 1 avalon-unit shorter and narrower (HollowLineSize = 1.0f) if the actual-width/height (considering StylusTipTransform)
                // is larger than HollowLineSize. Otherwise the same size stroke is drawn.
                selectedDA.StylusTipTransform = innerTransform;
                drawingContext.DrawGeometry(Brushes.White, null, GetGeometry(selectedDA));
            }
            else
            {
#if DEBUG_RENDERING_FEEDBACK
                //render debug feedback?
                Guid guid = new Guid("52053C24-CBDD-4547-AAA1-DEFEBF7FD1E1");
                if (this.ContainsPropertyData(guid))
                {
                    double thickness = (double)this.GetPropertyData(guid);

                    //first, draw the outline of the stroke
                    drawingContext.DrawGeometry(null,
                                                new Pen(Brushes.Black, thickness),
                                                GetGeometry());

                    Geometry g2;
                    Rect     b2;
                    //next, overlay the connecting quad points
                    StrokeRenderer.CalcGeometryAndBounds(StrokeNodeIterator.GetIterator(this, drawingAttributes),
                                                         drawingAttributes,
                                                         drawingContext, thickness, true,
                                                         true, //calc bounds
                                                         out g2,
                                                         out b2);
                }
                else
                {
#endif
                SolidColorBrush brush = new SolidColorBrush(drawingAttributes.Color);
                brush.Freeze();
                drawingContext.DrawGeometry(brush, null, GetGeometry(drawingAttributes));
#if DEBUG_RENDERING_FEEDBACK
            }
#endif
            }
        }
Beispiel #9
0
 internal static void CalcGeometryAndBoundsWithTransform(Context context)
 {
     StrokeRenderer.CalcGeometryAndBoundsWithTransform(context.StrokeNodeIterator, context.DrawingAttributes,
                                                       MatrixTypes.TRANSFORM_IS_IDENTITY, true, out var geometry, out var bounds);
 }