Sfoglia il codice sorgente

Merge branch 'feature/textbox-fix-right-click' of https://github.com/Deadpikle/Avalonia into feature/textbox-fix-right-click

Deadpikle 5 anni fa
parent
commit
f0286b4164

+ 18 - 1
samples/ControlCatalog/Pages/ImagePage.xaml

@@ -7,7 +7,7 @@
       <TextBlock Classes="h2">Displays an image</TextBlock>
     </StackPanel>
 
-    <Grid ColumnDefinitions="*,*" RowDefinitions="Auto,*" Margin="64">
+    <Grid ColumnDefinitions="*,*,*" RowDefinitions="Auto,*" Margin="64">
       
       <DockPanel Grid.Column="0" Grid.Row="1" Margin="16">
         <TextBlock DockPanel.Dock="Top" Classes="h3" Margin="0 8">Bitmap</TextBlock>
@@ -22,6 +22,23 @@
       </DockPanel>
 
       <DockPanel Grid.Column="1" Grid.Row="1" Margin="16">
+        <TextBlock DockPanel.Dock="Top" Classes="h3" Margin="0 8">Crop</TextBlock>
+        <ComboBox Name="bitmapCrop" DockPanel.Dock="Top" SelectedIndex="2" SelectionChanged="BitmapCropChanged">
+          <ComboBoxItem>None</ComboBoxItem>
+          <ComboBoxItem>Center</ComboBoxItem>
+          <ComboBoxItem>TopLeft</ComboBoxItem>
+          <ComboBoxItem>TopRight</ComboBoxItem>
+          <ComboBoxItem>BottomLeft</ComboBoxItem>
+          <ComboBoxItem>BottomRight</ComboBoxItem>
+        </ComboBox>
+        <Image Name="croppedImage">
+          <Image.Source>
+            <CroppedBitmap  Source="/Assets/delicate-arch-896885_640.jpg" SourceRect="0 0 320 240"/>  
+          </Image.Source>
+        </Image>
+      </DockPanel>
+
+      <DockPanel Grid.Column="2" Grid.Row="1" Margin="16">
         <TextBlock DockPanel.Dock="Top" Classes="h3" Margin="0 8">Drawing</TextBlock>
         <ComboBox Name="drawingStretch" DockPanel.Dock="Top" SelectedIndex="2" SelectionChanged="DrawingStretchChanged">
           <ComboBoxItem>None</ComboBoxItem>

+ 33 - 0
samples/ControlCatalog/Pages/ImagePage.xaml.cs

@@ -1,6 +1,10 @@
+using System;
+using Avalonia;
 using Avalonia.Controls;
 using Avalonia.Markup.Xaml;
 using Avalonia.Media;
+using Avalonia.Media.Imaging;
+using Avalonia.Platform;
 
 namespace ControlCatalog.Pages
 {
@@ -8,12 +12,14 @@ namespace ControlCatalog.Pages
     {
         private readonly Image _bitmapImage;
         private readonly Image _drawingImage;
+        private readonly Image _croppedImage;
 
         public ImagePage()
         {
             InitializeComponent();
             _bitmapImage = this.FindControl<Image>("bitmapImage");
             _drawingImage = this.FindControl<Image>("drawingImage");
+            _croppedImage = this.FindControl<Image>("croppedImage");
         }
 
         private void InitializeComponent()
@@ -38,5 +44,32 @@ namespace ControlCatalog.Pages
                 _drawingImage.Stretch = (Stretch)comboxBox.SelectedIndex;
             }
         }
+
+        public void BitmapCropChanged(object sender, SelectionChangedEventArgs e)
+        {
+            if (_croppedImage != null)
+            {
+                var comboxBox = (ComboBox)sender;
+                var croppedBitmap = _croppedImage.Source as CroppedBitmap;
+                croppedBitmap.SourceRect = GetCropRect(comboxBox.SelectedIndex);
+            }
+        }
+
+        private PixelRect GetCropRect(int index)
+        {
+            var bitmapWidth = 640;
+            var bitmapHeight = 426;
+            var cropSize = new PixelSize(320, 240);
+            return index switch
+            {
+                1 => new PixelRect(new PixelPoint((bitmapWidth - cropSize.Width) / 2, (bitmapHeight - cropSize.Width) / 2), cropSize),
+                2 => new PixelRect(new PixelPoint(0, 0), cropSize),
+                3 => new PixelRect(new PixelPoint(bitmapWidth - cropSize.Width, 0), cropSize),
+                4 => new PixelRect(new PixelPoint(0, bitmapHeight - cropSize.Height), cropSize),
+                5 => new PixelRect(new PixelPoint(bitmapWidth - cropSize.Width, bitmapHeight - cropSize.Height), cropSize),
+                _ => PixelRect.Empty
+            };
+            
+        }
     }
 }

+ 6 - 3
src/Avalonia.Styling/Styling/Activators/StyleClassActivator.cs

@@ -14,6 +14,7 @@ namespace Avalonia.Styling.Activators
     {
         private readonly IList<string> _match;
         private readonly IAvaloniaReadOnlyList<string> _classes;
+        private NotifyCollectionChangedEventHandler? _classesChangedHandler;
 
         public StyleClassActivator(IAvaloniaReadOnlyList<string> classes, IList<string> match)
         {
@@ -21,6 +22,9 @@ namespace Avalonia.Styling.Activators
             _match = match;
         }
 
+        private NotifyCollectionChangedEventHandler ClassesChangedHandler =>
+            _classesChangedHandler ??= ClassesChanged;
+
         public static bool AreClassesMatching(IReadOnlyList<string> classes, IList<string> toMatch)
         {
             int remainingMatches = toMatch.Count;
@@ -51,16 +55,15 @@ namespace Avalonia.Styling.Activators
             return remainingMatches == 0;
         }
 
-
         protected override void Initialize()
         {
             PublishNext(IsMatching());
-            _classes.CollectionChanged += ClassesChanged;
+            _classes.CollectionChanged += ClassesChangedHandler;
         }
 
         protected override void Deinitialize()
         {
-            _classes.CollectionChanged -= ClassesChanged;
+            _classes.CollectionChanged -= ClassesChangedHandler;
         }
 
         private void ClassesChanged(object sender, NotifyCollectionChangedEventArgs e)

+ 96 - 0
src/Avalonia.Visuals/Media/Imaging/CroppedBitmap.cs

@@ -0,0 +1,96 @@
+using System;
+using Avalonia.Visuals.Media.Imaging;
+
+namespace Avalonia.Media.Imaging
+{
+    /// <summary>
+    /// Crops a Bitmap.
+    /// </summary>
+    public class CroppedBitmap : AvaloniaObject, IImage, IAffectsRender, IDisposable
+    {
+        /// <summary>
+        /// Defines the <see cref="Source"/> property.
+        /// </summary>
+        public static readonly StyledProperty<IImage> SourceProperty =
+            AvaloniaProperty.Register<CroppedBitmap, IImage>(nameof(Source));
+
+        /// <summary>
+        /// Defines the <see cref="SourceRect"/> property.
+        /// </summary>
+        public static readonly StyledProperty<PixelRect> SourceRectProperty =
+            AvaloniaProperty.Register<CroppedBitmap, PixelRect>(nameof(SourceRect));
+
+        public event EventHandler Invalidated;
+
+        static CroppedBitmap()
+        {
+            SourceRectProperty.Changed.AddClassHandler<CroppedBitmap>((x, e) => x.SourceRectChanged(e));
+            SourceProperty.Changed.AddClassHandler<CroppedBitmap>((x, e) => x.SourceChanged(e));
+        }
+
+        /// <summary>
+        /// Gets or sets the source for the bitmap.
+        /// </summary>
+        public IImage Source
+        {
+            get => GetValue(SourceProperty);
+            set => SetValue(SourceProperty, value);
+        }
+
+        /// <summary>
+        /// Gets or sets the rectangular area that the bitmap is cropped to.
+        /// </summary>
+        public PixelRect SourceRect
+        {
+            get => GetValue(SourceRectProperty);
+            set => SetValue(SourceRectProperty, value);
+        }
+
+        public CroppedBitmap()
+        {
+            Source = null;
+            SourceRect = default;
+        }
+
+        public CroppedBitmap(IImage source, PixelRect sourceRect)
+        {
+            Source = source;
+            SourceRect = sourceRect;
+        }
+
+        private void SourceChanged(AvaloniaPropertyChangedEventArgs e)
+        {
+            if (e.NewValue == null)
+                return;
+            if (!(e.NewValue is IBitmap))
+                throw new ArgumentException("Only IBitmap supported as source");
+            Invalidated?.Invoke(this, e);
+        }
+
+        private void SourceRectChanged(AvaloniaPropertyChangedEventArgs e) => Invalidated?.Invoke(this, e);
+
+        public virtual void Dispose()
+        {
+            (Source as IBitmap)?.Dispose();
+        }
+
+        public Size Size {
+            get
+            {
+                if (Source == null)
+                    return Size.Empty;
+                if (SourceRect.IsEmpty)
+                    return Source.Size;
+                return SourceRect.Size.ToSizeWithDpi((Source as IBitmap).Dpi);
+            }
+        }
+
+        public void Draw(DrawingContext context, Rect sourceRect, Rect destRect, BitmapInterpolationMode bitmapInterpolationMode)
+        {
+            if (Source == null)
+                return;
+            var topLeft = SourceRect.TopLeft.ToPointWithDpi((Source as IBitmap).Dpi);
+            Source.Draw(context, sourceRect.Translate(new Vector(topLeft.X, topLeft.Y)), destRect, bitmapInterpolationMode);           
+        }
+    }
+}

+ 1 - 0
src/Avalonia.Visuals/Properties/AssemblyInfo.cs

@@ -8,6 +8,7 @@ using Avalonia.Metadata;
 [assembly: InternalsVisibleTo("Avalonia.Visuals.UnitTests")]
 [assembly: XmlnsDefinition("https://github.com/avaloniaui", "Avalonia.Animation")]
 [assembly: XmlnsDefinition("https://github.com/avaloniaui", "Avalonia.Media")]
+[assembly: XmlnsDefinition("https://github.com/avaloniaui", "Avalonia.Media.Imaging")]
 [assembly: XmlnsDefinition("https://github.com/avaloniaui", "Avalonia")]
 
 [assembly: InternalsVisibleTo("Avalonia.Direct2D1.RenderTests")]

+ 8 - 2
src/Avalonia.Visuals/Rendering/DeferredRenderer.cs

@@ -355,15 +355,21 @@ namespace Avalonia.Rendering
 
                     node.BeginRender(context, isLayerRoot);
 
-                    foreach (var operation in node.DrawOperations)
+                    var drawOperations = node.DrawOperations;
+                    var drawOperationsCount = drawOperations.Count;
+                    for (int i = 0; i < drawOperationsCount; i++)
                     {
+                        var operation = drawOperations[i];
                         _currentDraw = operation;
                         operation.Item.Render(context);
                         _currentDraw = null;
                     }
 
-                    foreach (var child in node.Children)
+                    var children = node.Children;
+                    var childrenCount = children.Count;
+                    for (int i = 0; i < childrenCount; i++)
                     {
+                        var child = children[i];
                         Render(context, (VisualNode)child, layer, clipBounds);
                     }