Browse Source

Merge branch 'master' into master

Steven Kirk 6 years ago
parent
commit
3a9c7d861c

+ 1 - 1
src/Avalonia.Controls/Button.cs

@@ -217,7 +217,7 @@ namespace Avalonia.Controls
             var e = new RoutedEventArgs(ClickEvent);
             RaiseEvent(e);
 
-            if (Command != null)
+            if (!e.Handled && Command?.CanExecute(CommandParameter) == true)
             {
                 Command.Execute(CommandParameter);
                 e.Handled = true;

+ 69 - 7
src/Avalonia.Controls/DropDown.cs

@@ -56,6 +56,7 @@ namespace Avalonia.Controls
         private bool _isDropDownOpen;
         private Popup _popup;
         private object _selectionBoxItem;
+        private IDisposable _subscriptionsOnOpen;
 
         /// <summary>
         /// Initializes static members of the <see cref="DropDown"/> class.
@@ -149,16 +150,12 @@ namespace Avalonia.Controls
             {
                 if (e.Key == Key.Down)
                 {
-                    if (++SelectedIndex >= ItemCount)
-                        SelectedIndex = 0;
-
+                    SelectNext();
                     e.Handled = true;
                 }
                 else if (e.Key == Key.Up)
                 {
-                    if (--SelectedIndex < 0)
-                        SelectedIndex = ItemCount - 1;
-
+                    SelectPrev();
                     e.Handled = true;
                 }
             }
@@ -174,6 +171,32 @@ namespace Avalonia.Controls
             }
         }
 
+        /// <inheritdoc/>
+        protected override void OnPointerWheelChanged(PointerWheelEventArgs e)
+        {
+            base.OnPointerWheelChanged(e);
+
+            if (!e.Handled)
+            {
+                if (!IsDropDownOpen)
+                {
+                    if (IsFocused)
+                    {
+                        if (e.Delta.Y < 0)
+                            SelectNext();
+                        else
+                            SelectPrev();
+
+                        e.Handled = true;
+                    }
+                }
+                else
+                {
+                    e.Handled = true;
+                }
+            }
+        }
+
         /// <inheritdoc/>
         protected override void OnPointerPressed(PointerPressedEventArgs e)
         {
@@ -223,6 +246,9 @@ namespace Avalonia.Controls
 
         private void PopupClosed(object sender, EventArgs e)
         {
+            _subscriptionsOnOpen?.Dispose();
+            _subscriptionsOnOpen = null;
+
             if (CanFocus(this))
             {
                 Focus();
@@ -232,6 +258,22 @@ namespace Avalonia.Controls
         private void PopupOpened(object sender, EventArgs e)
         {
             TryFocusSelectedItem();
+
+            _subscriptionsOnOpen?.Dispose();
+            _subscriptionsOnOpen = null;
+
+            var toplevel = this.GetVisualRoot() as TopLevel;
+            if (toplevel != null)
+            {
+                _subscriptionsOnOpen = toplevel.AddHandler(PointerWheelChangedEvent, (s, ev) =>
+                {
+                    //eat wheel scroll event outside dropdown popup while it's open
+                    if (IsDropDownOpen && (ev.Source as IVisual).GetVisualRoot() == toplevel)
+                    {
+                        ev.Handled = true;
+                    }
+                }, Interactivity.RoutingStrategies.Tunnel);
+            }
         }
 
         private void SelectedItemChanged(AvaloniaPropertyChangedEventArgs e)
@@ -247,7 +289,7 @@ namespace Avalonia.Controls
             {
                 var container = ItemContainerGenerator.ContainerFromIndex(selectedIndex);
 
-                if(container == null && SelectedItems.Count > 0)
+                if (container == null && SelectedItems.Count > 0)
                 {
                     ScrollIntoView(SelectedItems[0]);
                     container = ItemContainerGenerator.ContainerFromIndex(selectedIndex);
@@ -307,5 +349,25 @@ namespace Avalonia.Controls
                 }
             }
         }
+
+        private void SelectNext()
+        {
+            int next = SelectedIndex + 1;
+
+            if (next >= ItemCount)
+                next = 0;
+
+            SelectedIndex = next;
+        }
+
+        private void SelectPrev()
+        {
+            int prev = SelectedIndex - 1;
+
+            if (prev < 0)
+                prev = ItemCount - 1;
+
+            SelectedIndex = prev;
+        }
     }
 }

+ 17 - 0
src/Avalonia.Controls/Image.cs

@@ -99,5 +99,22 @@ namespace Avalonia.Controls
                 return new Size();
             }
         }
+
+        /// <inheritdoc/>
+        protected override Size ArrangeOverride(Size finalSize)
+        {
+            var source = Source;
+
+            if (source != null)
+            {
+                var sourceSize = new Size(source.PixelSize.Width, source.PixelSize.Height);
+                var result = Stretch.CalculateSize(finalSize, sourceSize);
+                return result;
+            }
+            else
+            {
+                return new Size();
+            }
+        }
     }
 }

+ 1 - 1
src/Avalonia.Controls/MenuItem.cs

@@ -287,7 +287,7 @@ namespace Avalonia.Controls
         /// <param name="e">The click event args.</param>
         protected virtual void OnClick(RoutedEventArgs e)
         {
-            if (Command != null)
+            if (!e.Handled && Command?.CanExecute(CommandParameter) == true)
             {
                 Command.Execute(CommandParameter);
                 e.Handled = true;

+ 56 - 0
tests/Avalonia.Controls.UnitTests/ImageTests.cs

@@ -61,5 +61,61 @@ namespace Avalonia.Controls.UnitTests
 
             Assert.Equal(new Size(50, 50), target.DesiredSize);
         }
+
+        [Fact]
+        public void Arrange_Should_Return_Correct_Size_For_No_Stretch()
+        {
+            var bitmap = Mock.Of<IBitmap>(x => x.PixelSize == new PixelSize(50, 100));
+            var target = new Image();
+            target.Stretch = Stretch.None;
+            target.Source = bitmap;
+
+            target.Measure(new Size(50, 50));
+            target.Arrange(new Rect(0, 0, 100, 400));
+
+            Assert.Equal(new Size(50, 100), target.Bounds.Size);
+        }
+
+        [Fact]
+        public void Arrange_Should_Return_Correct_Size_For_Fill_Stretch()
+        {
+            var bitmap = Mock.Of<IBitmap>(x => x.PixelSize == new PixelSize(50, 100));
+            var target = new Image();
+            target.Stretch = Stretch.Fill;
+            target.Source = bitmap;
+
+            target.Measure(new Size(50, 50));
+            target.Arrange(new Rect(0, 0, 25, 100));
+
+            Assert.Equal(new Size(25, 100), target.Bounds.Size);
+        }
+
+        [Fact]
+        public void Arrange_Should_Return_Correct_Size_For_Uniform_Stretch()
+        {
+            var bitmap = Mock.Of<IBitmap>(x => x.PixelSize == new PixelSize(50, 100));
+            var target = new Image();
+            target.Stretch = Stretch.Uniform;
+            target.Source = bitmap;
+
+            target.Measure(new Size(50, 50));
+            target.Arrange(new Rect(0, 0, 25, 100));
+
+            Assert.Equal(new Size(25, 50), target.Bounds.Size);
+        }
+
+        [Fact]
+        public void Arrange_Should_Return_Correct_Size_For_UniformToFill_Stretch()
+        {
+            var bitmap = Mock.Of<IBitmap>(x => x.PixelSize == new PixelSize(50, 100));
+            var target = new Image();
+            target.Stretch = Stretch.UniformToFill;
+            target.Source = bitmap;
+
+            target.Measure(new Size(50, 50));
+            target.Arrange(new Rect(0, 0, 25, 100));
+
+            Assert.Equal(new Size(25, 100), target.Bounds.Size);
+        }
     }
 }