<commit_before>// Copyright (c) The Avalonia Project. All rights reserved.
// Licensed under the MIT license. See licence.md file in the project root for full license information.

using System;
using System.Reflection;
using Avalonia.Collections;
using Avalonia.Controls;
using Avalonia.Media;

namespace Avalonia.Controls.Shapes
{
    public abstract class Shape : Control
    {
        public static readonly StyledProperty<IBrush> FillProperty =
            AvaloniaProperty.Register<Shape, IBrush>("Fill");

        public static readonly StyledProperty<Stretch> StretchProperty =
            AvaloniaProperty.Register<Shape, Stretch>("Stretch");

        public static readonly StyledProperty<IBrush> StrokeProperty =
            AvaloniaProperty.Register<Shape, IBrush>("Stroke");

        public static readonly StyledProperty<AvaloniaList<double>> StrokeDashArrayProperty =
            AvaloniaProperty.Register<Shape, AvaloniaList<double>>("StrokeDashArray");

        public static readonly StyledProperty<double> StrokeThicknessProperty =
            AvaloniaProperty.Register<Shape, double>("StrokeThickness");

        private Matrix _transform = Matrix.Identity;
        private Geometry _definingGeometry;
        private Geometry _renderedGeometry;

        static Shape()
        {
            AffectsMeasure(StretchProperty, StrokeThicknessProperty);
            AffectsRender(FillProperty, StrokeProperty, StrokeDashArrayProperty);
        }

        public Geometry DefiningGeometry
        {
            get
            {
                if (_definingGeometry == null)
                {
                    _definingGeometry = CreateDefiningGeometry();
                }

                return _definingGeometry;
            }
        }

        public IBrush Fill
        {
            get { return GetValue(FillProperty); }
            set { SetValue(FillProperty, value); }
        }

        public Geometry RenderedGeometry
        {
            get
            {
                if (_renderedGeometry == null)
                {
                    if (DefiningGeometry != null)
                    {
                        _renderedGeometry = DefiningGeometry.Clone();
                        _renderedGeometry.Transform = new MatrixTransform(_transform);
                    }
                }

                return _renderedGeometry;
            }
        }

        public Stretch Stretch
        {
            get { return GetValue(StretchProperty); }
            set { SetValue(StretchProperty, value); }
        }

        public IBrush Stroke
        {
            get { return GetValue(StrokeProperty); }
            set { SetValue(StrokeProperty, value); }
        }

        public AvaloniaList<double> StrokeDashArray
        {
            get { return GetValue(StrokeDashArrayProperty); }
            set { SetValue(StrokeDashArrayProperty, value); }
        }

        public double StrokeThickness
        {
            get { return GetValue(StrokeThicknessProperty); }
            set { SetValue(StrokeThicknessProperty, value); }
        }

        public PenLineCap StrokeDashCap { get; set; } = PenLineCap.Flat;

        public PenLineCap StrokeStartLineCap { get; set; } = PenLineCap.Flat;

        public PenLineCap StrokeEndLineCap { get; set; } = PenLineCap.Flat;

        public PenLineJoin StrokeJoin { get; set; } = PenLineJoin.Miter;

        public override void Render(DrawingContext context)
        {
            var geometry = RenderedGeometry;

            if (geometry != null)
            {
                var pen = new Pen(Stroke, StrokeThickness, new DashStyle(StrokeDashArray), 
                    StrokeDashCap, StrokeStartLineCap, StrokeEndLineCap, StrokeJoin);
                context.DrawGeometry(Fill, pen, geometry);
            }
        }

        /// <summary>
        /// Marks a property as affecting the shape's geometry.
        /// </summary>
        /// <param name="properties">The properties.</param>
        /// <remarks>
        /// After a call to this method in a control's static constructor, any change to the
        /// property will cause <see cref="InvalidateGeometry"/> to be called on the element.
        /// </remarks>
        protected static void AffectsGeometry<TShape>(params AvaloniaProperty[] properties)
            where TShape : Shape
        {
            foreach (var property in properties)
            {
                property.Changed.Subscribe(e =>
                {
                    var senderType = e.Sender.GetType().GetTypeInfo();
                    var affectedType = typeof(TShape).GetTypeInfo();

                    if (affectedType.IsAssignableFrom(senderType))
                    {
                        AffectsGeometryInvalidate(e);
                    }
                });
            }
        }

        protected abstract Geometry CreateDefiningGeometry();

        protected void InvalidateGeometry()
        {
            this._renderedGeometry = null;
            this._definingGeometry = null;
            InvalidateMeasure();
        }

        protected override Size MeasureOverride(Size availableSize)
        {
            // This should probably use GetRenderBounds(strokeThickness) but then the calculations
            // will multiply the stroke thickness as well, which isn't correct.
            var (size, transform) = CalculateSizeAndTransform(availableSize, DefiningGeometry.Bounds, Stretch);
            
            if (_transform != transform)
            {
                _transform = transform;
                _renderedGeometry = null;
            }

            return size;<commit_msg>Fix sizing behavior of Shape class<commit_after>// Copyright (c) The Avalonia Project. All rights reserved.
// Licensed under the MIT license. See licence.md file in the project root for full license information.

using System;
using System.Reflection;
using Avalonia.Collections;
using Avalonia.Controls;
using Avalonia.Media;

namespace Avalonia.Controls.Shapes
{
    public abstract class Shape : Control
    {
        public static readonly StyledProperty<IBrush> FillProperty =
            AvaloniaProperty.Register<Shape, IBrush>("Fill");

        public static readonly StyledProperty<Stretch> StretchProperty =
            AvaloniaProperty.Register<Shape, Stretch>("Stretch");

        public static readonly StyledProperty<IBrush> StrokeProperty =
            AvaloniaProperty.Register<Shape, IBrush>("Stroke");

        public static readonly StyledProperty<AvaloniaList<double>> StrokeDashArrayProperty =
            AvaloniaProperty.Register<Shape, AvaloniaList<double>>("StrokeDashArray");

        public static readonly StyledProperty<double> StrokeThicknessProperty =
            AvaloniaProperty.Register<Shape, double>("StrokeThickness");

        private Matrix _transform = Matrix.Identity;
        private Geometry _definingGeometry;
        private Geometry _renderedGeometry;
        bool _calculateTransformOnArrange = false;


        static Shape()
        {
            AffectsMeasure(StretchProperty, StrokeThicknessProperty);
            AffectsRender(FillProperty, StrokeProperty, StrokeDashArrayProperty);
        }

        public Geometry DefiningGeometry
        {
            get
            {
                if (_definingGeometry == null)
                {
                    _definingGeometry = CreateDefiningGeometry();
                }

                return _definingGeometry;
            }
        }

        public IBrush Fill
        {
            get { return GetValue(FillProperty); }
            set { SetValue(FillProperty, value); }
        }

        public Geometry RenderedGeometry
        {
            get
            {
                if (_renderedGeometry == null)
                {
                    if (DefiningGeometry != null)
                    {
                        _renderedGeometry = DefiningGeometry.Clone();
                        _renderedGeometry.Transform = new MatrixTransform(_transform);
                    }
                }

                return _renderedGeometry;
            }
        }

        public Stretch Stretch
        {
            get { return GetValue(StretchProperty); }
            set { SetValue(StretchProperty, value); }
        }

        public IBrush Stroke
        {
            get { return GetValue(StrokeProperty); }
            set { SetValue(StrokeProperty, value); }
        }

        public AvaloniaList<double> StrokeDashArray
        {
            get { return GetValue(StrokeDashArrayProperty); }
            set { SetValue(StrokeDashArrayProperty, value); }
        }

        public double StrokeThickness
        {
            get { return GetValue(StrokeThicknessProperty); }
            set { SetValue(StrokeThicknessProperty, value); }
        }

        public PenLineCap StrokeDashCap { get; set; } = PenLineCap.Flat;

        public PenLineCap StrokeStartLineCap { get; set; } = PenLineCap.Flat;

        public PenLineCap StrokeEndLineCap { get; set; } = PenLineCap.Flat;

        public PenLineJoin StrokeJoin { get; set; } = PenLineJoin.Miter;

        public override void Render(DrawingContext context)
        {
            var geometry = RenderedGeometry;

            if (geometry != null)
            {
                var pen = new Pen(Stroke, StrokeThickness, new DashStyle(StrokeDashArray), 
                    StrokeDashCap, StrokeStartLineCap, StrokeEndLineCap, StrokeJoin);
                context.DrawGeometry(Fill, pen, geometry);
            }
        }

        /// <summary>
        /// Marks a property as affecting the shape's geometry.
        /// </summary>
        /// <param name="properties">The properties.</param>
        /// <remarks>
        /// After a call to this method in a control's static constructor, any change to the
        /// property will cause <see cref="InvalidateGeometry"/> to be called on the element.
        /// </remarks>
        protected static void AffectsGeometry<TShape>(params AvaloniaProperty[] properties)
            where TShape : Shape
        {
            foreach (var property in properties)
            {
                property.Changed.Subscribe(e =>
                {
                    var senderType = e.Sender.GetType().GetTypeInfo();
                    var affectedType = typeof(TShape).GetTypeInfo();

                    if (affectedType.IsAssignableFrom(senderType))
                    {
                        AffectsGeometryInvalidate(e);
                    }
                });
            }
        }

        protected abstract Geometry CreateDefiningGeometry();

        protected void InvalidateGeometry()
        {
            this._renderedGeometry = null;
            this._definingGeometry = null;
            InvalidateMeasure();
        }
        
        protected override Size MeasureOverride(Size availableSize)
        {
            bool deferCalculateTransform;
            switch (Stretch)
            {
                case Stretch.Fill:
                case Stretch.UniformToFill:
                    deferCalculateTransform = double.IsInfinity(availableSize.Width) || double.IsInfinity(availableSize.Height);
                    break;
                case Stretch.Uniform:
                    deferCalculateTransform = double.IsInfinity(availableSize.Width) && double.IsInfinity(availableSize.Height);
                    break;
                case Stretch.None:
                default:
                    deferCalculateTransform = false;
                    break;
            }

            if (deferCalculateTransform)
            {
                _calculateTransformOnArrange = true;
                return DefiningGeometry.Bounds.Size;
            }
            else
            {
                _calculateTransformOnArrange = false;
                return CalculateShapeSizeAndSetTransform(availableSize);
            }
        }
        
        protected override Size ArrangeOverride(Size finalSize)
        {
            if(_calculateTransformOnArrange)
            {
                _calculateTransformOnArrange = false;
                CalculateShapeSizeAndSetTransform(finalSize);
            }

            return finalSize;
        }
        private Size CalculateShapeSizeAndSetTransform(Size availableSize)
        {
            // This should probably use GetRenderBounds(strokeThickness) but then the calculations
            // will multiply the stroke thickness as well, which isn't correct.
            var (size, transform) = CalculateSizeAndTransform(availableSize, DefiningGeometry.Bounds, Stretch);

            if (_transform != transform)
            {
                _transform = transform;
                _renderedGeometry = null;
            }

            return size;
{'fraction_non_alphanumeric': 0.07304116865869854, 'fraction_numerical': 0.0, 'mean_word_length': 1.7436776682383197, 'pattern_counts': {'":': 0, '<': 45, '<?xml version=': 0, '>': 47, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6597463', 'n_tokens_mistral': 3186, 'n_tokens_neox': 2942, 'n_words': 721}