Пример #1
0
        private SkiaGeometrySource2D GetGeometry(Size finalSize)
        {
            var strokeThickness = StrokeThickness;
            var radiusX         = RadiusX;
            var radiusY         = RadiusY;

            var offset = new Vector2((float)(strokeThickness * 0.5), (float)(strokeThickness * 0.5));
            var size   = new Vector2((float)finalSize.Width, (float)finalSize.Height);

            SkiaGeometrySource2D geometry;

            if (radiusX == 0 || radiusY == 0)
            {
                // Simple rectangle
                geometry = new SkiaGeometrySource2D(
                    CompositionGeometry.BuildRectangleGeometry(
                        offset,
                        size));
            }
            else
            {
                // Complex rectangle
                geometry = new SkiaGeometrySource2D(
                    CompositionGeometry.BuildRoundedRectangleGeometry(
                        offset,
                        size,
                        new Vector2((float)radiusX, (float)radiusY)));
            }

            return(geometry);
        }
Пример #2
0
            CompositionSpriteShape CreateSpriteShape(CompositionGeometry geometry, Matrix3x2 transformMatrix)
            {
                var result = _c.CreateSpriteShape(geometry);

                result.TransformMatrix = transformMatrix;
                return(result);
            }
Пример #3
0
            CompositionSpriteShape CreateSpriteShape(CompositionGeometry geometry, Matrix3x2 transformMatrix, CompositionBrush fillBrush)
            {
                var result = _c.CreateSpriteShape(geometry);

                result.TransformMatrix = transformMatrix;
                result.FillBrush       = fillBrush;
                return(result);
            }
Пример #4
0
        protected override void OnApplyTemplate()
        {
            Indicator = (ProgressBarRingSlice)GetTemplateChild("Indicator");
            Rotation  = (RotateTransform)GetTemplateChild("Rotation");

            if (Indicator != null)
            {
                OnApplyLegacyTemplate();
            }
            else if (ApiInfo.CanUseDirectComposition)
            {
                var ellipse = Window.Current.Compositor.CreateEllipseGeometry();
                ellipse.Radius  = new Vector2(21);
                ellipse.Center  = new Vector2(24);
                ellipse.TrimEnd = 0f;

                var shape = Window.Current.Compositor.CreateSpriteShape(ellipse);
                shape.CenterPoint     = new Vector2(24);
                shape.StrokeThickness = 2;
                shape.StrokeBrush     = Window.Current.Compositor.CreateColorBrush(Windows.UI.Colors.Red);
                shape.StrokeStartCap  = CompositionStrokeCap.Round;
                shape.StrokeEndCap    = CompositionStrokeCap.Round;

                var visual = Window.Current.Compositor.CreateShapeVisual();
                visual.Shapes.Add(shape);
                visual.Size        = new Vector2(48);
                visual.CenterPoint = new Vector3(24);

                var easing  = Window.Current.Compositor.CreateLinearEasingFunction();
                var forever = Window.Current.Compositor.CreateScalarKeyFrameAnimation();
                forever.InsertKeyFrame(1, 360, easing);
                forever.IterationBehavior = AnimationIterationBehavior.Forever;
                forever.Duration          = TimeSpan.FromSeconds(3);

                var trimEnd = Window.Current.Compositor.CreateScalarKeyFrameAnimation();
                trimEnd.Target = nameof(CompositionGeometry.TrimEnd);
                trimEnd.InsertExpressionKeyFrame(1.0f, "this.FinalValue", Window.Current.Compositor.CreateLinearEasingFunction());

                var visibility = Window.Current.Compositor.CreateExpressionAnimation("target.TrimEnd < 1");
                visibility.SetReferenceParameter("target", ellipse);

                var animations = Window.Current.Compositor.CreateImplicitAnimationCollection();
                animations[nameof(CompositionGeometry.TrimEnd)] = trimEnd;

                ellipse.ImplicitAnimations = animations;
                visual.StartAnimation("IsVisible", visibility);
                visual.StartAnimation("RotationAngleInDegrees", forever);

                _ellipse = ellipse;

                ElementCompositionPreview.SetElementChildVisual(this, visual);
            }
        }
        private void DrawShapeGeometry(CompositionGeometry geometry, IShape shape)
        {
            CompositionSpriteShape spriteShape = _compositor.CreateSpriteShape(geometry);

            IBrush?fill = shape.Fill;

            if (fill != null)
            {
                spriteShape.FillBrush = fill.ToCompositionBrush(_compositor);
            }

            IBrush?stroke = shape.Stroke;

            if (stroke != null)
            {
                spriteShape.StrokeBrush     = stroke.ToCompositionBrush(_compositor);
                spriteShape.StrokeThickness = (float)shape.StrokeThickness;

                CompositionStrokeCap strokeCap = shape.StrokeLineCap switch
                {
                    PenLineCap.Flat => CompositionStrokeCap.Flat,
                    PenLineCap.Round => CompositionStrokeCap.Round,
                    PenLineCap.Square => CompositionStrokeCap.Square,
                    _ => throw new InvalidOperationException($"Unknown PenLineCap value {shape.StrokeLineCap}")
                };
                spriteShape.StrokeStartCap = strokeCap;
                spriteShape.StrokeEndCap   = strokeCap;

                spriteShape.StrokeLineJoin = shape.StrokeLineJoin switch
                {
                    PenLineJoin.Miter => CompositionStrokeLineJoin.Miter,
                    PenLineJoin.Bevel => CompositionStrokeLineJoin.Bevel,
                    PenLineJoin.Round => CompositionStrokeLineJoin.Round,
                    _ => throw new InvalidOperationException($"Unknown PenLineJoin value {shape.StrokeLineJoin}")
                };

                // TODO: Check that miter limit definition matches StandardUI (half thickness vs full thickness)
                spriteShape.StrokeMiterLimit = (float)shape.StrokeMiterLimit;

                // TODO: Handle dash pattern
            }

            if (_shapeVisual == null)
            {
                _shapeVisual = _compositor.CreateShapeVisual();
            }

            _shapeVisual.Shapes.Add(spriteShape);
        }
        // Remove redundant TrimEnd, TrimOffset, and TrimStart properties.
        static void OptimizeGeometryProperties(CompositionGeometry obj)
        {
            // Unset properties that are set to their default values.
            if (obj.TrimEnd == 1)
            {
                obj.TrimEnd = null;
            }

            if (obj.TrimOffset == 0)
            {
                obj.TrimOffset = null;
            }

            if (obj.TrimStart == 0)
            {
                obj.TrimStart = null;
            }
        }
Пример #7
0
        CompositionGeometry GetCompositionGeometry(CompositionGeometry obj)
        {
            switch (obj.Type)
            {
            case CompositionObjectType.CompositionPathGeometry:
                return(GetCompositionPathGeometry((CompositionPathGeometry)obj));

            case CompositionObjectType.CompositionEllipseGeometry:
                return(GetCompositionEllipseGeometry((CompositionEllipseGeometry)obj));

            case CompositionObjectType.CompositionRectangleGeometry:
                return(GetCompositionRectangleGeometry((CompositionRectangleGeometry)obj));

            case CompositionObjectType.CompositionRoundedRectangleGeometry:
                return(GetCompositionRoundedRectangleGeometry((CompositionRoundedRectangleGeometry)obj));

            default:
                throw new InvalidOperationException();
            }
        }
Пример #8
0
        T CacheAndInitializeCompositionGeometry <T>(CompositionGeometry source, T target)
            where T : CompositionGeometry
        {
            CacheAndInitializeCompositionObject(source, target);
            if (source.TrimStart != 0)
            {
                target.TrimStart = source.TrimStart;
            }

            if (source.TrimEnd != 1)
            {
                target.TrimEnd = source.TrimEnd;
            }

            if (source.TrimOffset != 0)
            {
                target.TrimOffset = source.TrimOffset;
            }

            return(target);
        }
Пример #9
0
        internal static PropertyId GetNonDefaultGeometryProperties(CompositionGeometry obj)
        {
            var result = PropertyId.None;

            if (obj.TrimStart.HasValue)
            {
                result |= PropertyId.TrimStart;
            }

            if (obj.TrimEnd.HasValue)
            {
                result |= PropertyId.TrimEnd;
            }

            if (obj.TrimOffset.HasValue)
            {
                result |= PropertyId.TrimOffset;
            }

            return(result | GetNonDefaultCompositionObjectProperties(obj));
        }
Пример #10
0
        IEnumerable <XObject> GetCompositionGeometryContents(CompositionGeometry obj)
        {
            foreach (var item in GetCompositionObjectContents(obj))
            {
                yield return(item);
            }

            foreach (var item in FromAnimatableScalar(nameof(obj.TrimStart), obj.Animators, obj.TrimStart))
            {
                yield return(item);
            }

            foreach (var item in FromAnimatableScalar(nameof(obj.TrimEnd), obj.Animators, obj.TrimEnd))
            {
                yield return(item);
            }

            foreach (var item in FromAnimatableScalar(nameof(obj.TrimOffset), obj.Animators, obj.TrimOffset))
            {
                yield return(item);
            }
        }
Пример #11
0
 internal override SKPath GetSKPath() => CompositionGeometry.BuildLineGeometry(StartPoint.ToVector2(), EndPoint.ToVector2());
Пример #12
0
 internal override SKPath GetSKPath() =>
 CompositionGeometry.BuildRectangleGeometry(offset: new Vector2((float)Rect.X, (float)Rect.Y), size: new Vector2((float)Rect.Width, (float)Rect.Height));
Пример #13
0
        private void InitializeAnimation()
        {
            if (!ApiInfo.CanUseDirectComposition)
            {
                return;
            }

            var width    = 18f;
            var height   = 10f;
            var stroke   = 2f;
            var distance = stroke * 2;

            var sqrt = (float)Math.Sqrt(2);

            var side     = (stroke / sqrt) / 2f;
            var diagonal = height * sqrt;
            var length   = (diagonal / 2f) / sqrt;

            var join = stroke / 2 * sqrt;

            var line11 = Window.Current.Compositor.CreateLineGeometry();
            var line12 = Window.Current.Compositor.CreateLineGeometry();

            line11.Start = new Vector2(width - height + side + join - length - distance, height - side - length);
            line11.End   = new Vector2(width - height + side + join - distance, height - side);

            line12.Start = new Vector2(width - height + side - distance, height - side);
            line12.End   = new Vector2(width - side - distance, side);

            var shape11 = Window.Current.Compositor.CreateSpriteShape(line11);

            shape11.StrokeThickness    = 2;
            shape11.StrokeBrush        = Window.Current.Compositor.CreateColorBrush(Windows.UI.Colors.Black);
            shape11.IsStrokeNonScaling = true;

            var shape12 = Window.Current.Compositor.CreateSpriteShape(line12);

            shape12.StrokeThickness    = 2;
            shape12.StrokeBrush        = Window.Current.Compositor.CreateColorBrush(Windows.UI.Colors.Black);
            shape12.IsStrokeNonScaling = true;

            var visual1 = Window.Current.Compositor.CreateShapeVisual();

            visual1.Shapes.Add(shape12);
            visual1.Shapes.Add(shape11);
            visual1.Size        = new Vector2(18, 10);
            visual1.CenterPoint = new Vector3(18, 5, 0);


            var line21 = Window.Current.Compositor.CreateLineGeometry();
            var line22 = Window.Current.Compositor.CreateLineGeometry();

            line21.Start = new Vector2(width - height + side + join - length, height - side - length);
            line21.End   = new Vector2(width - height + side + join, height - side);

            line22.Start = new Vector2(width - height + side, height - side);
            line22.End   = new Vector2(width - side, side);

            var shape21 = Window.Current.Compositor.CreateSpriteShape(line21);

            shape21.StrokeThickness = 2;
            shape21.StrokeBrush     = Window.Current.Compositor.CreateColorBrush(Windows.UI.Colors.Black);

            var shape22 = Window.Current.Compositor.CreateSpriteShape(line22);

            shape22.StrokeThickness = 2;
            shape22.StrokeBrush     = Window.Current.Compositor.CreateColorBrush(Windows.UI.Colors.Black);

            var visual2 = Window.Current.Compositor.CreateShapeVisual();

            visual2.Shapes.Add(shape22);
            visual2.Shapes.Add(shape21);
            visual2.Size = new Vector2(18, 10);


            var container = Window.Current.Compositor.CreateContainerVisual();

            container.Children.InsertAtTop(visual2);
            container.Children.InsertAtTop(visual1);
            container.Size = new Vector2(18, 10);

            ElementCompositionPreview.SetElementChildVisual(Label, container);

            _line11    = line11;
            _line12    = line12;
            _line21    = line21;
            _line22    = line22;
            _shapes    = new[] { shape11, shape12, shape21, shape22 };
            _visual1   = visual1;
            _container = container;
        }
Пример #14
0
 internal CompositionSpriteShape(CompositionGeometry geometry = null)
 {
     Geometry = geometry;
 }
 RectangleOrRoundedRectangleGeometry(CompositionGeometry compositionGeometry)
 {
     _compositionGeometry = compositionGeometry;
 }
Пример #16
0
        static void TranslateAndApplyTrimPath(
            ShapeContext context,
            CompositionGeometry geometry,
            bool reverseDirection,
            double trimOffsetDegrees)
        {
            var trimPath = context.TrimPath;

            if (trimPath is null)
            {
                return;
            }

            if (reverseDirection)
            {
                trimPath = trimPath.CloneWithReversedDirection();
            }

            var startTrim      = Optimizer.TrimAnimatable(context, trimPath.Start);
            var endTrim        = Optimizer.TrimAnimatable(context, trimPath.End);
            var trimPathOffset = Optimizer.TrimAnimatable(context, trimPath.Offset);

            if (!startTrim.IsAnimated && !endTrim.IsAnimated)
            {
                // Handle some well-known static cases.
                if (startTrim.InitialValue.Value == 0 && endTrim.InitialValue.Value == 1)
                {
                    // The trim does nothing.
                    return;
                }
                else if (startTrim.InitialValue == endTrim.InitialValue)
                {
                    // TODO - the trim trims away all of the path.
                }
            }

            var order = GetAnimatableOrder(in startTrim, in endTrim);

            switch (order)
            {
            case AnimatableOrder.Before:
            case AnimatableOrder.Equal:
                break;

            case AnimatableOrder.After:
            {
                // Swap is necessary to match the WinComp semantics.
                var temp = startTrim;
                startTrim = endTrim;
                endTrim   = temp;
            }

            break;

            case AnimatableOrder.BeforeAndAfter:
                break;

            default:
                throw new InvalidOperationException();
            }

            if (order == AnimatableOrder.BeforeAndAfter)
            {
                // Add properties that will be animated. The TrimStart and TrimEnd properties
                // will be set by these values through an expression.
                Animate.TrimStartOrTrimEndPropertySetValue(context, startTrim, geometry, "TStart");
                var trimStartExpression = context.ObjectFactory.CreateExpressionAnimation(ExpressionFactory.MinTStartTEnd);
                trimStartExpression.SetReferenceParameter("my", geometry);
                Animate.WithExpression(geometry, trimStartExpression, nameof(geometry.TrimStart));

                Animate.TrimStartOrTrimEndPropertySetValue(context, endTrim, geometry, "TEnd");
                var trimEndExpression = context.ObjectFactory.CreateExpressionAnimation(ExpressionFactory.MaxTStartTEnd);
                trimEndExpression.SetReferenceParameter("my", geometry);
                Animate.WithExpression(geometry, trimEndExpression, nameof(geometry.TrimEnd));
            }
            else
            {
                // Directly animate the TrimStart and TrimEnd properties.
                if (startTrim.IsAnimated)
                {
                    Animate.TrimStartOrTrimEnd(context, startTrim, geometry, nameof(geometry.TrimStart), "TrimStart", null);
                }
                else
                {
                    geometry.TrimStart = ConvertTo.Float(startTrim.InitialValue);
                }

                if (endTrim.IsAnimated)
                {
                    Animate.TrimStartOrTrimEnd(context, endTrim, geometry, nameof(geometry.TrimEnd), "TrimEnd", null);
                }
                else
                {
                    geometry.TrimEnd = ConvertTo.Float(endTrim.InitialValue);
                }
            }

            if (trimOffsetDegrees != 0 && !trimPathOffset.IsAnimated)
            {
                // Rectangle shapes are treated specially here to account for Lottie rectangle 0,0 being
                // top right and WinComp rectangle 0,0 being top left. As long as the TrimOffset isn't
                // being animated we can simply add an offset to the trim path.
                geometry.TrimOffset = (float)((trimPathOffset.InitialValue.Degrees + trimOffsetDegrees) / 360);
            }
            else
            {
                if (trimOffsetDegrees != 0)
                {
                    // TODO - can be handled with another property.
                    context.Issues.AnimatedTrimOffsetWithStaticTrimOffsetIsNotSupported();
                }

                if (trimPathOffset.IsAnimated)
                {
                    Animate.ScaledRotation(context, trimPathOffset, 1 / 360.0, geometry, nameof(geometry.TrimOffset), "TrimOffset", null);
                }
                else
                {
                    geometry.TrimOffset = ConvertTo.Float(trimPathOffset.InitialValue.Degrees / 360);
                }
            }
        }
Пример #17
0
 internal override SKPath GetSKPath() => CompositionGeometry.BuildEllipseGeometry(Center.ToVector2(), new Vector2((float)RadiusX, (float)RadiusY));