Example #1
0
        public override XPoint AddToPath(XGraphicsPath path, XPoint cursor, Base lastPathCommand = null)
        {
            if (Radii.Width == 0 || Radii.Height == 0)
            {
                path.AddLine(cursor, End.ToXPoint());
                return(End.ToXPoint());
            }
            if (End.X == cursor.X && End.Y == cursor.Y)
            {
                return(cursor);
            }

            path.AddArc(cursor, End.ToXPoint(), Radii.ToXSize(), XAxisRotation, IsLongArc, IsSweep ? XSweepDirection.Clockwise : XSweepDirection.Counterclockwise);
            return(End.ToXPoint());
        }
Example #2
0
        private void OnAmunTextBoxSizeChanged(object sender, SizeChangedEventArgs e)
        {
            logger.I("OnAmunTextBoxSizeChanged: from " + e.PreviousSize + " to " + e.NewSize);

            if (!e.Handled && GridContentStreamGeoElement != null && IsUsingAmunClippingBorder)
            {
                GridContentStreamGeoElement.Clear();
                Thickness borders = BorderThickness;

                Rect boundRect = new Rect(e.NewSize);
                //Rect innerRect = AIVUtil.HelperDeflateRect(boundRect, borders);

                using (StreamGeometryContext ctx = GridContentStreamGeoElement.Open())
                {
                    CornerRadius radii      = CornerRadius;
                    Radii        innerRadii = new Radii(radii, borders, false);
                    GenerateGeometry(ctx, boundRect, innerRadii);
                }
            }
        }
Example #3
0
        /// <summary>
        ///     Generates a StreamGeometry.
        /// </summary>
        /// <param name="ctx">An already opened StreamGeometryContext.</param>
        /// <param name="rect">Rectangle for geomentry conversion.</param>
        /// <param name="radii">Corner radii.</param>
        /// <returns>Result geometry.</returns>
        private static void GenerateGeometry(StreamGeometryContext ctx, Rect rect, Radii radii)
        {
            //
            //  compute the coordinates of the key points
            //

            Point topLeft     = new Point(radii.LeftTop, 0);
            Point topRight    = new Point(rect.Width - radii.RightTop, 0);
            Point rightTop    = new Point(rect.Width, radii.TopRight);
            Point rightBottom = new Point(rect.Width, rect.Height - radii.BottomRight);
            Point bottomRight = new Point(rect.Width - radii.RightBottom, rect.Height);
            Point bottomLeft  = new Point(radii.LeftBottom, rect.Height);
            Point leftBottom  = new Point(0, rect.Height - radii.BottomLeft);
            Point leftTop     = new Point(0, radii.TopLeft);

            //
            //  check keypoints for overlap and resolve by partitioning radii according to
            //  the percentage of each one.
            //

            //  top edge is handled here
            if (topLeft.X > topRight.X)
            {
                double v = (radii.LeftTop) / (radii.LeftTop + radii.RightTop) * rect.Width;
                topLeft.X  = v;
                topRight.X = v;
            }

            //  right edge
            if (rightTop.Y > rightBottom.Y)
            {
                double v = (radii.TopRight) / (radii.TopRight + radii.BottomRight) * rect.Height;
                rightTop.Y    = v;
                rightBottom.Y = v;
            }

            //  bottom edge
            if (bottomRight.X < bottomLeft.X)
            {
                double v = (radii.LeftBottom) / (radii.LeftBottom + radii.RightBottom) * rect.Width;
                bottomRight.X = v;
                bottomLeft.X  = v;
            }

            // left edge
            if (leftBottom.Y < leftTop.Y)
            {
                double v = (radii.TopLeft) / (radii.TopLeft + radii.BottomLeft) * rect.Height;
                leftBottom.Y = v;
                leftTop.Y    = v;
            }

            //
            //  add on offsets
            //

            Vector offset = new Vector(rect.TopLeft.X, rect.TopLeft.Y);

            topLeft     += offset;
            topRight    += offset;
            rightTop    += offset;
            rightBottom += offset;
            bottomRight += offset;
            bottomLeft  += offset;
            leftBottom  += offset;
            leftTop     += offset;

            //
            //  create the border geometry
            //
            ctx.BeginFigure(topLeft, true /* is filled */, true /* is closed */);

            // Top line
            ctx.LineTo(topRight, true /* is stroked */, false /* is smooth join */);

            // Upper-right corner
            double radiusX = rect.TopRight.X - topRight.X;
            double radiusY = rightTop.Y - rect.TopRight.Y;

            if (!DoubleUtil.IsZero(radiusX) ||
                !DoubleUtil.IsZero(radiusY))
            {
                ctx.ArcTo(rightTop, new Size(radiusX, radiusY), 0, false, SweepDirection.Clockwise, true, false);
            }

            // Right line
            ctx.LineTo(rightBottom, true /* is stroked */, false /* is smooth join */);

            // Lower-right corner
            radiusX = rect.BottomRight.X - bottomRight.X;
            radiusY = rect.BottomRight.Y - rightBottom.Y;
            if (!DoubleUtil.IsZero(radiusX) ||
                !DoubleUtil.IsZero(radiusY))
            {
                ctx.ArcTo(bottomRight, new Size(radiusX, radiusY), 0, false, SweepDirection.Clockwise, true, false);
            }

            // Bottom line
            ctx.LineTo(bottomLeft, true /* is stroked */, false /* is smooth join */);

            // Lower-left corner
            radiusX = bottomLeft.X - rect.BottomLeft.X;
            radiusY = rect.BottomLeft.Y - leftBottom.Y;
            if (!DoubleUtil.IsZero(radiusX) ||
                !DoubleUtil.IsZero(radiusY))
            {
                ctx.ArcTo(leftBottom, new Size(radiusX, radiusY), 0, false, SweepDirection.Clockwise, true, false);
            }

            // Left line
            ctx.LineTo(leftTop, true /* is stroked */, false /* is smooth join */);

            // Upper-left corner
            radiusX = topLeft.X - rect.TopLeft.X;
            radiusY = leftTop.Y - rect.TopLeft.Y;
            if (!DoubleUtil.IsZero(radiusX) ||
                !DoubleUtil.IsZero(radiusY))
            {
                ctx.ArcTo(topLeft, new Size(radiusX, radiusY), 0, false, SweepDirection.Clockwise, true, false);
            }
        }
Example #4
0
        /// <summary>
        /// In addition to the child, Border renders a background + border.  The background is drawn inside the border.
        /// </summary>
        protected override void OnRender(DrawingContext dc)
        {
            bool     useLayoutRounding = this.UseLayoutRounding;
            DpiScale dpi = GetDpi();

            if (_useComplexRenderCodePath)
            {
                Brush          brush;
                StreamGeometry borderGeometry = BorderGeometryCache;
                if (borderGeometry != null &&
                    (brush = BorderBrush) != null)
                {
                    dc.DrawGeometry(brush, null, borderGeometry);
                }

                StreamGeometry backgroundGeometry = BackgroundGeometryCache;
                if (backgroundGeometry != null &&
                    (brush = Background) != null)
                {
                    dc.DrawGeometry(brush, null, backgroundGeometry);
                }
            }
            else
            {
                Thickness border = BorderThickness;
                Brush     borderBrush;

                CornerRadius cornerRadius      = CornerRadius;
                double       outerCornerRadius = cornerRadius.TopLeft; // Already validated that all corners have the same radius
                bool         roundedCorners    = !DoubleUtil.IsZero(outerCornerRadius);

                // If we have a brush with which to draw the border, do so.
                // NB: We double draw corners right now.  Corner handling is tricky (bevelling, &c...) and
                //     we need a firm spec before doing "the right thing."  (greglett, ffortes)
                if (!border.IsZero &&
                    (borderBrush = BorderBrush) != null)
                {
                    // Initialize the first pen.  Note that each pen is created via new()
                    // and frozen if possible.  Doing this avoids the pen
                    // being copied when used in the DrawLine methods.
                    Pen pen = LeftPenCache;
                    if (pen == null)
                    {
                        pen       = new Pen();
                        pen.Brush = borderBrush;

                        if (useLayoutRounding)
                        {
                            pen.Thickness = UIElement.RoundLayoutValue(border.Left, dpi.DpiScaleX);
                        }
                        else
                        {
                            pen.Thickness = border.Left;
                        }
                        if (borderBrush.IsFrozen)
                        {
                            pen.Freeze();
                        }

                        LeftPenCache = pen;
                    }

                    double halfThickness;
                    if (border.IsUniform)
                    {
                        halfThickness = pen.Thickness * 0.5;


                        // Create rect w/ border thickness, and round if applying layout rounding.
                        Rect rect = new Rect(new Point(halfThickness, halfThickness),
                                             new Point(RenderSize.Width - halfThickness, RenderSize.Height - halfThickness));

                        if (roundedCorners)
                        {
                            dc.DrawRoundedRectangle(
                                null,
                                pen,
                                rect,
                                outerCornerRadius,
                                outerCornerRadius);
                        }
                        else
                        {
                            dc.DrawRectangle(
                                null,
                                pen,
                                rect);
                        }
                    }
                    else
                    {
                        // Nonuniform border; stroke each edge.
                        if (DoubleUtil.GreaterThan(border.Left, 0))
                        {
                            halfThickness = pen.Thickness * 0.5;
                            dc.DrawLine(
                                pen,
                                new Point(halfThickness, 0),
                                new Point(halfThickness, RenderSize.Height));
                        }

                        if (DoubleUtil.GreaterThan(border.Right, 0))
                        {
                            pen = RightPenCache;
                            if (pen == null)
                            {
                                pen       = new Pen();
                                pen.Brush = borderBrush;

                                if (useLayoutRounding)
                                {
                                    pen.Thickness = UIElement.RoundLayoutValue(border.Right, dpi.DpiScaleX);
                                }
                                else
                                {
                                    pen.Thickness = border.Right;
                                }

                                if (borderBrush.IsFrozen)
                                {
                                    pen.Freeze();
                                }

                                RightPenCache = pen;
                            }

                            halfThickness = pen.Thickness * 0.5;
                            dc.DrawLine(
                                pen,
                                new Point(RenderSize.Width - halfThickness, 0),
                                new Point(RenderSize.Width - halfThickness, RenderSize.Height));
                        }

                        if (DoubleUtil.GreaterThan(border.Top, 0))
                        {
                            pen = TopPenCache;
                            if (pen == null)
                            {
                                pen       = new Pen();
                                pen.Brush = borderBrush;
                                if (useLayoutRounding)
                                {
                                    pen.Thickness = UIElement.RoundLayoutValue(border.Top, dpi.DpiScaleY);
                                }
                                else
                                {
                                    pen.Thickness = border.Top;
                                }

                                if (borderBrush.IsFrozen)
                                {
                                    pen.Freeze();
                                }

                                TopPenCache = pen;
                            }

                            halfThickness = pen.Thickness * 0.5;
                            dc.DrawLine(
                                pen,
                                new Point(0, halfThickness),
                                new Point(RenderSize.Width, halfThickness));
                        }

                        if (DoubleUtil.GreaterThan(border.Bottom, 0))
                        {
                            pen = BottomPenCache;
                            if (pen == null)
                            {
                                pen       = new Pen();
                                pen.Brush = borderBrush;
                                if (useLayoutRounding)
                                {
                                    pen.Thickness = UIElement.RoundLayoutValue(border.Bottom, dpi.DpiScaleY);
                                }
                                else
                                {
                                    pen.Thickness = border.Bottom;
                                }
                                if (borderBrush.IsFrozen)
                                {
                                    pen.Freeze();
                                }

                                BottomPenCache = pen;
                            }

                            halfThickness = pen.Thickness * 0.5;
                            dc.DrawLine(
                                pen,
                                new Point(0, RenderSize.Height - halfThickness),
                                new Point(RenderSize.Width, RenderSize.Height - halfThickness));
                        }
                    }
                }

                // Draw background in rectangle inside border.
                Brush background = Background;
                if (background != null)
                {
                    // Intialize background
                    Point ptTL, ptBR;

                    if (useLayoutRounding)
                    {
                        ptTL = new Point(UIElement.RoundLayoutValue(border.Left, dpi.DpiScaleX),
                                         UIElement.RoundLayoutValue(border.Top, dpi.DpiScaleY));

                        if (FrameworkAppContextSwitches.DoNotApplyLayoutRoundingToMarginsAndBorderThickness)
                        {
                            ptBR = new Point(UIElement.RoundLayoutValue(RenderSize.Width - border.Right, dpi.DpiScaleX),
                                             UIElement.RoundLayoutValue(RenderSize.Height - border.Bottom, dpi.DpiScaleY));
                        }
                        else
                        {
                            ptBR = new Point(RenderSize.Width - UIElement.RoundLayoutValue(border.Right, dpi.DpiScaleX),
                                             RenderSize.Height - UIElement.RoundLayoutValue(border.Bottom, dpi.DpiScaleY));
                        }
                    }
                    else
                    {
                        ptTL = new Point(border.Left, border.Top);
                        ptBR = new Point(RenderSize.Width - border.Right, RenderSize.Height - border.Bottom);
                    }

                    // Do not draw background if the borders are so large that they overlap.
                    if (ptBR.X > ptTL.X && ptBR.Y > ptTL.Y)
                    {
                        if (roundedCorners)
                        {
                            Radii  innerRadii        = new Radii(cornerRadius, border, false); // Determine the inner edge radius
                            double innerCornerRadius = innerRadii.TopLeft;                     // Already validated that all corners have the same radius
                            dc.DrawRoundedRectangle(background, null, new Rect(ptTL, ptBR), innerCornerRadius, innerCornerRadius);
                        }
                        else
                        {
                            dc.DrawRectangle(background, null, new Rect(ptTL, ptBR));
                        }
                    }
                }
            }
        }
Example #5
0
        /// <summary>
        /// Border computes the position of its single child and applies its child's alignments to the child.
        ///
        /// </summary>
        /// <param name="finalSize">The size reserved for this element by the parent</param>
        /// <returns>The actual ink area of the element, typically the same as finalSize</returns>
        protected override Size ArrangeOverride(Size finalSize)
        {
            Thickness borders = BorderThickness;

            if (this.UseLayoutRounding && !FrameworkAppContextSwitches.DoNotApplyLayoutRoundingToMarginsAndBorderThickness)
            {
                DpiScale dpi = GetDpi();
                borders = new Thickness(UIElement.RoundLayoutValue(borders.Left, dpi.DpiScaleX), UIElement.RoundLayoutValue(borders.Top, dpi.DpiScaleY),
                                        UIElement.RoundLayoutValue(borders.Right, dpi.DpiScaleX), UIElement.RoundLayoutValue(borders.Bottom, dpi.DpiScaleY));
            }
            Rect boundRect = new Rect(finalSize);
            Rect innerRect = HelperDeflateRect(boundRect, borders);

            //  arrange child
            UIElement child = Child;

            if (child != null)
            {
                Rect childRect = HelperDeflateRect(innerRect, Padding);
                child.Arrange(childRect);
            }

            CornerRadius radii          = CornerRadius;
            Brush        borderBrush    = BorderBrush;
            bool         uniformCorners = AreUniformCorners(radii);

            //  decide which code path to execute. complex (geometry path based) rendering
            //  is used if one of the following is true:

            //  1. there are non-uniform rounded corners
            _useComplexRenderCodePath = !uniformCorners;

            if (!_useComplexRenderCodePath &&
                borderBrush != null)
            {
                SolidColorBrush originIndependentBrush = borderBrush as SolidColorBrush;

                bool uniformBorders = borders.IsUniform;

                _useComplexRenderCodePath =
                    //  2. the border brush is origin dependent (the only origin independent brush is a solid color brush)
                    (originIndependentBrush == null)
                    //  3. the border brush is semi-transtarent solid color brush AND border thickness is not uniform
                    //     (for uniform semi-transparent border Border.OnRender draws rectangle outline - so it works fine)
                    || ((originIndependentBrush.Color.A < 0xff) && !uniformBorders)
                    //  4. there are rounded corners AND the border thickness is not uniform
                    || (!DoubleUtil.IsZero(radii.TopLeft) && !uniformBorders);
            }

            if (_useComplexRenderCodePath)
            {
                Radii innerRadii = new Radii(radii, borders, false);

                StreamGeometry backgroundGeometry = null;

                //  calculate border / background rendering geometry
                if (!DoubleUtil.IsZero(innerRect.Width) && !DoubleUtil.IsZero(innerRect.Height))
                {
                    backgroundGeometry = new StreamGeometry();

                    using (StreamGeometryContext ctx = backgroundGeometry.Open())
                    {
                        GenerateGeometry(ctx, innerRect, innerRadii);
                    }

                    backgroundGeometry.Freeze();
                    BackgroundGeometryCache = backgroundGeometry;
                }
                else
                {
                    BackgroundGeometryCache = null;
                }

                if (!DoubleUtil.IsZero(boundRect.Width) && !DoubleUtil.IsZero(boundRect.Height))
                {
                    Radii          outerRadii     = new Radii(radii, borders, true);
                    StreamGeometry borderGeometry = new StreamGeometry();

                    using (StreamGeometryContext ctx = borderGeometry.Open())
                    {
                        GenerateGeometry(ctx, boundRect, outerRadii);

                        if (backgroundGeometry != null)
                        {
                            GenerateGeometry(ctx, innerRect, innerRadii);
                        }
                    }

                    borderGeometry.Freeze();
                    BorderGeometryCache = borderGeometry;
                }
                else
                {
                    BorderGeometryCache = null;
                }
            }
            else
            {
                BackgroundGeometryCache = null;
                BorderGeometryCache     = null;
            }

            return(finalSize);
        }
Example #6
0
        /// <inheritdoc />
        public override void Update(GameTime gameTime)
        {
            // In the demos, we use one time step per frame. We don't bother modifying the physics time step duration for different monitors so different refresh rates
            // change the rate of simulation. This doesn't actually change the result of the simulation, though, and the simplicity is a good fit for the demos.
            // In the context of a 'real' application, you could instead use a time accumulator to take time steps of fixed length as needed, or
            // fully decouple simulation and rendering rates across different threads.
            // (In either case, you'd also want to interpolate or extrapolate simulation results during rendering for smoothness.)
            // Note that taking steps of variable length can reduce stability. Gradual or one-off changes can work reasonably well.
            Simulation.Timestep(1 / 60f, ThreadDispatcher);
            Camera.Update(gameTime);

            if (Game.CurrentKeyboardState.IsKeyDown(Keys.Z) && CanShoot)
            {
                CanShoot = false;
                // Create the shape that we'll launch at the pyramids when the user presses a button.
                var radius      = 0.5f + 5 * (float)Random.NextDouble();
                var bulletShape = new Sphere(radius);

                // Note that the use of radius^3 for mass can produce some pretty serious mass ratios.
                // Observe what happens when a large ball sits on top of a few boxes with a fraction of the mass-
                // the collision appears much squishier and less stable. For most games, if you want to maintain rigidity, you'll want to use some combination of:
                // 1) Limit the ratio of heavy object masses to light object masses when those heavy objects depend on the light objects.
                // 2) Use a shorter timestep duration and update more frequently.
                // 3) Use a greater number of solver iterations.
                // #2 and #3 can become very expensive. In pathological cases, it can end up slower than using a quality-focused solver for the same simulation.
                // Unfortunately, at the moment, bepuphysics v2 does not contain any alternative solvers, so if you can't afford to brute force the the problem away,
                // the best solution is to cheat as much as possible to avoid the corner cases.
                var position        = new NumericVector3(-40 + 210 * (float)Random.NextDouble(), 130, 130);
                var bodyDescription = BodyDescription.CreateConvexDynamic(position,
                                                                          new BodyVelocity(new NumericVector3((float)Random.NextDouble(), 0, -110)),
                                                                          bulletShape.Radius * bulletShape.Radius * bulletShape.Radius, Simulation.Shapes, bulletShape);

                var bodyHandle = Simulation.Bodies.Add(bodyDescription);

                Radii.Add(radius);
                SphereHandles.Add(bodyHandle);
            }

            if (Game.CurrentKeyboardState.IsKeyUp(Keys.Z))
            {
                CanShoot = true;
            }


            BoxesWorld.Clear();
            var boxHandleCount = BoxHandles.Count;

            for (var index = 0; index < boxHandleCount; index++)
            {
                var pose       = Simulation.Bodies.GetBodyReference(BoxHandles[index]).Pose;
                var position   = pose.Position;
                var quaternion = pose.Orientation;
                var world      =
                    Matrix.CreateFromQuaternion(new Quaternion(quaternion.X, quaternion.Y, quaternion.Z,
                                                               quaternion.W)) * Matrix.CreateTranslation(new Vector3(position.X, position.Y, position.Z));
                BoxesWorld.Add(world);
            }

            SpheresWorld.Clear();
            var sphereHandleCount = SphereHandles.Count;

            for (var index = 0; index < sphereHandleCount; index++)
            {
                var pose       = Simulation.Bodies.GetBodyReference(SphereHandles[index]).Pose;
                var position   = pose.Position;
                var quaternion = pose.Orientation;
                var world      = Matrix.CreateScale(Radii[index]) *
                                 Matrix.CreateFromQuaternion(new Quaternion(quaternion.X, quaternion.Y, quaternion.Z,
                                                                            quaternion.W)) *
                                 Matrix.CreateTranslation(new Vector3(position.X, position.Y, position.Z));
                SpheresWorld.Add(world);
            }


            Game.Gizmos.UpdateViewProjection(Camera.View, Camera.Projection);

            base.Update(gameTime);
        }
Example #7
0
        /// <summary>
        ///     Generates a StreamGeometry.
        /// </summary>
        /// <param name="ctx">An already opened StreamGeometryContext.</param>
        /// <param name="rect">Rectangle for geomentry conversion.</param>
        /// <param name="radii">Corner radii.</param>
        /// <returns>Result geometry.</returns>
        private static void GenerateGeometry(StreamGeometryContext ctx, Rect rect, Radii radii)
        {
            //
            //  compute the coordinates of the key points
            //

            Point topLeft = new Point(radii.LeftTop, 0);
            Point topRight = new Point(rect.Width - radii.RightTop, 0);
            Point rightTop = new Point(rect.Width, radii.TopRight);
            Point rightBottom = new Point(rect.Width, rect.Height - radii.BottomRight);
            Point bottomRight = new Point(rect.Width - radii.RightBottom, rect.Height);
            Point bottomLeft = new Point(radii.LeftBottom, rect.Height);
            Point leftBottom = new Point(0, rect.Height - radii.BottomLeft);
            Point leftTop = new Point(0, radii.TopLeft);

            //
            //  check keypoints for overlap and resolve by partitioning radii according to
            //  the percentage of each one.  
            //

            //  top edge is handled here
            if (topLeft.X > topRight.X)
            {
                double v = (radii.LeftTop) / (radii.LeftTop + radii.RightTop) * rect.Width;
                topLeft.X = v;
                topRight.X = v;
            }

            //  right edge
            if (rightTop.Y > rightBottom.Y)
            {
                double v = (radii.TopRight) / (radii.TopRight + radii.BottomRight) * rect.Height;
                rightTop.Y = v;
                rightBottom.Y = v;
            }

            //  bottom edge
            if (bottomRight.X < bottomLeft.X)
            {
                double v = (radii.LeftBottom) / (radii.LeftBottom + radii.RightBottom) * rect.Width;
                bottomRight.X = v;
                bottomLeft.X = v;
            }

            // left edge
            if (leftBottom.Y < leftTop.Y)
            {
                double v = (radii.TopLeft) / (radii.TopLeft + radii.BottomLeft) * rect.Height;
                leftBottom.Y = v;
                leftTop.Y = v;
            }

            //
            //  add on offsets
            //

            Vector offset = new Vector(rect.TopLeft.X, rect.TopLeft.Y);
            topLeft += offset;
            topRight += offset;
            rightTop += offset;
            rightBottom += offset;
            bottomRight += offset;
            bottomLeft += offset;
            leftBottom += offset;
            leftTop += offset;

            //
            //  create the border geometry
            //
            ctx.BeginFigure(topLeft, true /* is filled */, true /* is closed */);

            // Top line
            ctx.LineTo(topRight, true /* is stroked */, false /* is smooth join */);

            // Upper-right corner
            double radiusX = rect.TopRight.X - topRight.X;
            double radiusY = rightTop.Y - rect.TopRight.Y;
            if (!DoubleUtil.IsZero(radiusX)
                || !DoubleUtil.IsZero(radiusY))
            {
                ctx.ArcTo(rightTop, new Size(radiusX, radiusY), 0, false, SweepDirection.Clockwise, true, false);
            }

            // Right line
            ctx.LineTo(rightBottom, true /* is stroked */, false /* is smooth join */);

            // Lower-right corner
            radiusX = rect.BottomRight.X - bottomRight.X;
            radiusY = rect.BottomRight.Y - rightBottom.Y;
            if (!DoubleUtil.IsZero(radiusX)
                || !DoubleUtil.IsZero(radiusY))
            {
                ctx.ArcTo(bottomRight, new Size(radiusX, radiusY), 0, false, SweepDirection.Clockwise, true, false);
            }

            // Bottom line
            ctx.LineTo(bottomLeft, true /* is stroked */, false /* is smooth join */);

            // Lower-left corner
            radiusX = bottomLeft.X - rect.BottomLeft.X;
            radiusY = rect.BottomLeft.Y - leftBottom.Y;
            if (!DoubleUtil.IsZero(radiusX)
                || !DoubleUtil.IsZero(radiusY))
            {
                ctx.ArcTo(leftBottom, new Size(radiusX, radiusY), 0, false, SweepDirection.Clockwise, true, false);
            }

            // Left line
            ctx.LineTo(leftTop, true /* is stroked */, false /* is smooth join */);

            // Upper-left corner
            radiusX = topLeft.X - rect.TopLeft.X;
            radiusY = leftTop.Y - rect.TopLeft.Y;
            if (!DoubleUtil.IsZero(radiusX)
                || !DoubleUtil.IsZero(radiusY))
            {
                ctx.ArcTo(topLeft, new Size(radiusX, radiusY), 0, false, SweepDirection.Clockwise, true, false);
            }
        }
Example #8
0
        /// <summary>
        /// In addition to the child, Border renders a background + border.  The background is drawn inside the border.
        /// </summary>
        protected override void OnRender(DrawingContext dc)
        {           
            bool useLayoutRounding = this.UseLayoutRounding;

            if (_useComplexRenderCodePath)
            {
                Brush brush;
                StreamGeometry borderGeometry = BorderGeometryCache;
                if (    borderGeometry != null
                    &&  (brush = BorderBrush) != null   )
                {
                    dc.DrawGeometry(brush, null, borderGeometry);
                }

                StreamGeometry backgroundGeometry = BackgroundGeometryCache;
                if (    backgroundGeometry != null
                    &&  (brush = Background) != null    )
                {
                    dc.DrawGeometry(brush, null, backgroundGeometry);
                }
            }
            else
            {
                Thickness border = BorderThickness;
                Brush borderBrush;

                CornerRadius cornerRadius = CornerRadius;
                double outerCornerRadius = cornerRadius.TopLeft; // Already validated that all corners have the same radius
                bool roundedCorners = !DoubleUtil.IsZero(outerCornerRadius);

                // If we have a brush with which to draw the border, do so.
                // NB: We double draw corners right now.  Corner handling is tricky (bevelling, &c...) and
                //     we need a firm spec before doing "the right thing."  (greglett, ffortes)
                if (!border.IsZero
                    && (borderBrush = BorderBrush) != null)
                {
                    // Initialize the first pen.  Note that each pen is created via new()
                    // and frozen if possible.  Doing this avoids the pen 
                    // being copied when used in the DrawLine methods.
                    Pen pen = LeftPenCache;
                    if (pen == null)
                    {
                        pen = new Pen();
                        pen.Brush = borderBrush;

                        if (useLayoutRounding)
                        {
                            pen.Thickness = UIElement.RoundLayoutValue(border.Left, FrameworkElement.DpiScaleX);
                        }
                        else
                        {
                            pen.Thickness = border.Left;
                        }
                        if (borderBrush.IsFrozen)
                        {
                            pen.Freeze();
                        }

                        LeftPenCache = pen;
                    }

                    double halfThickness;
                    if (border.IsUniform)
                    {
                        halfThickness = pen.Thickness * 0.5;


                        // Create rect w/ border thickness, and round if applying layout rounding.
                        Rect rect = new Rect(new Point(halfThickness, halfThickness),
                                             new Point(RenderSize.Width - halfThickness, RenderSize.Height - halfThickness));

                        if (roundedCorners)
                        {
                            dc.DrawRoundedRectangle(
                                null,
                                pen,
                                rect,
                                outerCornerRadius,
                                outerCornerRadius);
                        }
                        else
                        {
                            dc.DrawRectangle(
                                null,
                                pen,
                                rect);
                        }
                    }
                    else
                    {
                        // Nonuniform border; stroke each edge.
                        if (DoubleUtil.GreaterThan(border.Left, 0))
                        {

                            halfThickness = pen.Thickness * 0.5;
                            dc.DrawLine(
                                pen,
                                new Point(halfThickness, 0),
                                new Point(halfThickness, RenderSize.Height));
                        }

                        if (DoubleUtil.GreaterThan(border.Right, 0))
                        {
                            pen = RightPenCache;
                            if (pen == null)
                            {
                                pen = new Pen();
                                pen.Brush = borderBrush;

                                if (useLayoutRounding)
                                {
                                    pen.Thickness = UIElement.RoundLayoutValue(border.Right, FrameworkElement.DpiScaleX);
                                }
                                else
                                {
                                    pen.Thickness = border.Right;
                                }

                                if (borderBrush.IsFrozen)
                                {
                                    pen.Freeze();
                                }

                                RightPenCache = pen;
                            }

                            halfThickness = pen.Thickness * 0.5;
                            dc.DrawLine(
                                pen,
                                new Point(RenderSize.Width - halfThickness, 0),
                                new Point(RenderSize.Width - halfThickness, RenderSize.Height));

                        }

                        if (DoubleUtil.GreaterThan(border.Top, 0))
                        {
                            pen = TopPenCache;
                            if (pen == null)
                            {
                                pen = new Pen();
                                pen.Brush = borderBrush;
                                if (useLayoutRounding)
                                {
                                    pen.Thickness = UIElement.RoundLayoutValue(border.Top, FrameworkElement.DpiScaleY);
                                }
                                else
                                {
                                    pen.Thickness = border.Top;
                                }

                                if (borderBrush.IsFrozen)
                                {
                                    pen.Freeze();
                                }

                                TopPenCache = pen;
                            }

                            halfThickness = pen.Thickness * 0.5;
                            dc.DrawLine(
                                pen,
                                new Point(0, halfThickness),
                                new Point(RenderSize.Width, halfThickness));
                        }

                        if (DoubleUtil.GreaterThan(border.Bottom, 0))
                        {
                            pen = BottomPenCache;
                            if (pen == null)
                            {
                                pen = new Pen();
                                pen.Brush = borderBrush;
                                if (useLayoutRounding)
                                {
                                    pen.Thickness = UIElement.RoundLayoutValue(border.Bottom, FrameworkElement.DpiScaleY);
                                }
                                else
                                {
                                    pen.Thickness = border.Bottom;
                                }
                                if (borderBrush.IsFrozen)
                                {
                                    pen.Freeze();
                                }

                                BottomPenCache = pen;
                            }

                            halfThickness = pen.Thickness * 0.5;
                            dc.DrawLine(
                                pen,
                                new Point(0, RenderSize.Height - halfThickness),
                                new Point(RenderSize.Width, RenderSize.Height - halfThickness));
                        }
                    }
                }

                // Draw background in rectangle inside border.
                Brush background = Background;
                if (background != null)
                {
                    // Intialize background 
                    Point ptTL, ptBR;

                    if (useLayoutRounding)
                    {
                        ptTL = new Point(UIElement.RoundLayoutValue(border.Left, FrameworkElement.DpiScaleX), 
                                         UIElement.RoundLayoutValue(border.Top, FrameworkElement.DpiScaleY));
                        ptBR = new Point(UIElement.RoundLayoutValue(RenderSize.Width - border.Right, FrameworkElement.DpiScaleX),
                                         UIElement.RoundLayoutValue(RenderSize.Height - border.Bottom, FrameworkElement.DpiScaleY));
                    }
                    else
                    {
                        ptTL = new Point(border.Left, border.Top); 
                        ptBR = new Point(RenderSize.Width - border.Right, RenderSize.Height - border.Bottom);
                    }

                    // Do not draw background if the borders are so large that they overlap.
                    if (ptBR.X > ptTL.X && ptBR.Y > ptTL.Y)
                    {
                        if (roundedCorners)
                        {
                            Radii innerRadii = new Radii(cornerRadius, border, false); // Determine the inner edge radius
                            double innerCornerRadius = innerRadii.TopLeft;  // Already validated that all corners have the same radius
                            dc.DrawRoundedRectangle(background, null, new Rect(ptTL, ptBR), innerCornerRadius, innerCornerRadius);
                        }
                        else
                        {
                            dc.DrawRectangle(background, null, new Rect(ptTL, ptBR));
                        }
                    }
                }
            }
        }
Example #9
0
        /// <summary>
        /// Border computes the position of its single child and applies its child's alignments to the child.
        /// 
        /// </summary>
        /// <param name="finalSize">The size reserved for this element by the parent</param>
        /// <returns>The actual ink area of the element, typically the same as finalSize</returns>
        protected override Size ArrangeOverride(Size finalSize)
        {
            Thickness borders = BorderThickness;
            Rect boundRect = new Rect(finalSize);
            Rect innerRect = HelperDeflateRect(boundRect, borders);

            //  arrange child
            UIElement child = Child;
            if (child != null)
            {
                Rect childRect = HelperDeflateRect(innerRect, Padding);
                child.Arrange(childRect);
            }

            CornerRadius radii = CornerRadius;
            Brush borderBrush = BorderBrush;
            bool uniformCorners = AreUniformCorners(radii);

            //  decide which code path to execute. complex (geometry path based) rendering 
            //  is used if one of the following is true:

            //  1. there are non-uniform rounded corners
            _useComplexRenderCodePath = !uniformCorners;

            if (    !_useComplexRenderCodePath
                &&  borderBrush != null )
            {
                SolidColorBrush originIndependentBrush = borderBrush as SolidColorBrush;

                bool uniformBorders = borders.IsUniform;

                _useComplexRenderCodePath = 
                //  2. the border brush is origin dependent (the only origin independent brush is a solid color brush)
                        (originIndependentBrush == null)
                //  3. the border brush is semi-transtarent solid color brush AND border thickness is not uniform
                //     (for uniform semi-transparent border Border.OnRender draws rectangle outline - so it works fine)
                    || ((originIndependentBrush.Color.A < 0xff) && !uniformBorders)
                //  4. there are rounded corners AND the border thickness is not uniform
                    || (!DoubleUtil.IsZero(radii.TopLeft) && !uniformBorders);
            }

            if (_useComplexRenderCodePath)
            {
                Radii innerRadii = new Radii(radii, borders, false);

                StreamGeometry backgroundGeometry = null;

                //  calculate border / background rendering geometry
                if (!DoubleUtil.IsZero(innerRect.Width) && !DoubleUtil.IsZero(innerRect.Height))
                {
                    backgroundGeometry = new StreamGeometry();

                    using (StreamGeometryContext ctx = backgroundGeometry.Open())
                    {
                        GenerateGeometry(ctx, innerRect, innerRadii);
                    }

                    backgroundGeometry.Freeze();
                    BackgroundGeometryCache = backgroundGeometry;
                }
                else
                {
                    BackgroundGeometryCache = null;
                }

                if (!DoubleUtil.IsZero(boundRect.Width) && !DoubleUtil.IsZero(boundRect.Height))
                {
                    Radii outerRadii = new Radii(radii, borders, true);
                    StreamGeometry borderGeometry = new StreamGeometry();

                    using (StreamGeometryContext ctx = borderGeometry.Open())
                    {
                        GenerateGeometry(ctx, boundRect, outerRadii);

                        if (backgroundGeometry != null)
                        {
                            GenerateGeometry(ctx, innerRect, innerRadii);
                        }
                    }

                    borderGeometry.Freeze();
                    BorderGeometryCache = borderGeometry;
                }
                else
                {
                    BorderGeometryCache = null;
                }
            }
            else 
            {
                BackgroundGeometryCache = null;
                BorderGeometryCache = null;
            }

            return (finalSize);
        }
 public Element()
 {
     this.RadiusConstants = new Radii(this);
 }
Example #11
0
 public RainbowCircleSudoku()
 {
     Alphabet   = Enumerable.Range(1, 12);
     Cells      = Angles.SelectMany(t => Radii.Select(r => $"{t}{r}"));
     Conditions = Rings.Concat(Wedges).Concat(Across);
 }
Example #12
0
        /// <summary>
        /// Border computes the position of its single child and applies its child's alignments to the child.
        /// </summary>
        /// <param name="finalSize">The size reserved for this element by the parent</param>
        /// <returns>The actual ink area of the element, typically the same as finalSize</returns>
        protected override Size ArrangeOverride(Size finalSize)
        {
            var borders = BorderThickness;

            if (UseLayoutRounding)
            {
                var dpi = DpiUtil.GetDpi(this);
                borders = new Thickness(UIElementUtil.RoundLayoutValue(borders.Left, dpi.DpiScaleX), UIElementUtil.RoundLayoutValue(borders.Top, dpi.DpiScaleY),
                                        UIElementUtil.RoundLayoutValue(borders.Right, dpi.DpiScaleX), UIElementUtil.RoundLayoutValue(borders.Bottom, dpi.DpiScaleY));
            }

            var boundRect = new Rect(finalSize);
            var innerRect = RectUtil.Deflate(boundRect, borders);

            //  arrange child
            var child = Child;

            if (child != null)
            {
                Rect childRect = RectUtil.Deflate(innerRect, Padding);
                child.Arrange(childRect);
            }

            var radius = CornerRadius;

            useComplexRender        = !CornerRadiusUtil.IsUniform(radius) || !ThicknessUtil.IsUniform(borders);
            backgroundGeometryCache = upperLeftCache = upperRightCache = lowerRightCache = lowerLeftCache = null;

            if (useComplexRender)
            {
                //  calculate border / background rendering geometry
                if (!DoubleUtil.IsZero(boundRect.Width) && !DoubleUtil.IsZero(boundRect.Height))
                {
                    var outerRadii = new Radii(boundRect, radius, borders, true);

                    // Upper-right corner
                    var radiusX = boundRect.TopRight.X - outerRadii.TopRight.X;
                    var radiusY = outerRadii.RightTop.Y - boundRect.TopRight.Y;
                    if (!DoubleUtil.IsZero(radiusX) || !DoubleUtil.IsZero(radiusY))
                    {
                        upperRightCache = GenerateRoundedGeometry(outerRadii.TopRight, outerRadii.RightTop, new Size(radiusX, radiusY));
                    }

                    // Lower-right corner
                    radiusX = boundRect.BottomRight.X - outerRadii.BottomRight.X;
                    radiusY = boundRect.BottomRight.Y - outerRadii.RightBottom.Y;
                    if (!DoubleUtil.IsZero(radiusX) || !DoubleUtil.IsZero(radiusY))
                    {
                        lowerRightCache = GenerateRoundedGeometry(outerRadii.RightBottom, outerRadii.BottomRight, new Size(radiusX, radiusY));
                    }

                    // Lower-left corner
                    radiusX = outerRadii.BottomLeft.X - boundRect.BottomLeft.X;
                    radiusY = boundRect.BottomLeft.Y - outerRadii.LeftBottom.Y;
                    if (!DoubleUtil.IsZero(radiusX) || !DoubleUtil.IsZero(radiusY))
                    {
                        lowerLeftCache = GenerateRoundedGeometry(outerRadii.BottomLeft, outerRadii.LeftBottom, new Size(radiusX, radiusY));
                    }

                    // Upper-left corner
                    radiusX = outerRadii.TopLeft.X - boundRect.TopLeft.X;
                    radiusY = outerRadii.LeftTop.Y - boundRect.TopLeft.Y;
                    if (!DoubleUtil.IsZero(radiusX) || !DoubleUtil.IsZero(radiusY))
                    {
                        upperLeftCache = GenerateRoundedGeometry(outerRadii.LeftTop, outerRadii.TopLeft, new Size(radiusX, radiusY));
                    }
                }

                if (!DoubleUtil.IsZero(innerRect.Width) && !DoubleUtil.IsZero(innerRect.Height))
                {
                    var innerRadii         = new Radii(innerRect, radius, borders, false);
                    var backgroundGeometry = new StreamGeometry();

                    using (StreamGeometryContext sc = backgroundGeometry.Open())
                    {
                        //  create the border geometry
                        sc.BeginFigure(innerRadii.TopLeft, true /* is filled */, true /* is closed */);

                        // Top line
                        sc.LineTo(innerRadii.TopRight, true /* is stroked */, false /* is smooth join */);

                        // Upper-right corners
                        var radiusX = innerRect.TopRight.X - innerRadii.TopRight.X;
                        var radiusY = innerRadii.RightTop.Y - innerRect.TopRight.Y;
                        if (!DoubleUtil.IsZero(radiusX) || !DoubleUtil.IsZero(radiusY))
                        {
                            sc.ArcTo(innerRadii.RightTop, new Size(radiusX, radiusY), 0, false, SweepDirection.Clockwise, true, false);
                        }

                        // Right line
                        sc.LineTo(innerRadii.RightBottom, true /* is stroked */, false /* is smooth join */);

                        // Lower-right corners
                        radiusX = innerRect.BottomRight.X - innerRadii.BottomRight.X;
                        radiusY = innerRect.BottomRight.Y - innerRadii.RightBottom.Y;
                        if (!DoubleUtil.IsZero(radiusX) || !DoubleUtil.IsZero(radiusY))
                        {
                            sc.ArcTo(innerRadii.BottomRight, new Size(radiusX, radiusY), 0, false, SweepDirection.Clockwise, true, false);
                        }

                        // Bottom line
                        sc.LineTo(innerRadii.BottomLeft, true /* is stroked */, false /* is smooth join */);

                        // Lower-left corners
                        radiusX = innerRadii.BottomLeft.X - innerRect.BottomLeft.X;
                        radiusY = innerRect.BottomLeft.Y - innerRadii.LeftBottom.Y;
                        if (!DoubleUtil.IsZero(radiusX) || !DoubleUtil.IsZero(radiusY))
                        {
                            sc.ArcTo(innerRadii.LeftBottom, new Size(radiusX, radiusY), 0, false, SweepDirection.Clockwise, true, false);
                        }

                        // Left line
                        sc.LineTo(innerRadii.LeftTop, true /* is stroked */, false /* is smooth join */);

                        // Upper-left corners
                        radiusX = innerRadii.TopLeft.X - innerRect.TopLeft.X;
                        radiusY = innerRadii.LeftTop.Y - innerRect.TopLeft.Y;
                        if (!DoubleUtil.IsZero(radiusX) || !DoubleUtil.IsZero(radiusY))
                        {
                            sc.ArcTo(innerRadii.TopLeft, new Size(radiusX, radiusY), 0, false, SweepDirection.Clockwise, true, false);
                        }
                    }

                    backgroundGeometry.Freeze();
                    backgroundGeometryCache = backgroundGeometry;
                }
            }

            return(finalSize);
        }