diff --git a/.gitignore b/.gitignore index 583a2b8a2b..32acee4c90 100644 --- a/.gitignore +++ b/.gitignore @@ -165,6 +165,11 @@ $RECYCLE.BIN/ ################# .idea +################# +## VS Code +################# +.vscode/ + ################# ## Cake ################# diff --git a/samples/BindingDemo/MainWindow.xaml b/samples/BindingDemo/MainWindow.xaml index a69fb75742..95713dc22f 100644 --- a/samples/BindingDemo/MainWindow.xaml +++ b/samples/BindingDemo/MainWindow.xaml @@ -18,18 +18,18 @@ - + - + - + !BooleanString @@ -37,13 +37,13 @@ - + - + @@ -52,7 +52,7 @@ - + @@ -68,11 +68,11 @@ - + - + @@ -87,16 +87,16 @@ - + - + - + @@ -104,7 +104,7 @@ - + @@ -25,7 +25,7 @@ - + @@ -33,4 +33,4 @@ - \ No newline at end of file + diff --git a/samples/ControlCatalog/Pages/ButtonSpinnerPage.xaml b/samples/ControlCatalog/Pages/ButtonSpinnerPage.xaml index 1797fb48bc..fba15f6e77 100644 --- a/samples/ControlCatalog/Pages/ButtonSpinnerPage.xaml +++ b/samples/ControlCatalog/Pages/ButtonSpinnerPage.xaml @@ -1,11 +1,11 @@  - + ButtonSpinner The ButtonSpinner control allows you to add button spinners to any element and then respond to the Spin event to manipulate that element. - + AllowSpin ShowButtonSpinner - \ No newline at end of file + diff --git a/samples/ControlCatalog/Pages/CalendarPage.xaml b/samples/ControlCatalog/Pages/CalendarPage.xaml index a433fd1add..c47fd766fb 100644 --- a/samples/ControlCatalog/Pages/CalendarPage.xaml +++ b/samples/ControlCatalog/Pages/CalendarPage.xaml @@ -1,13 +1,13 @@ - + Calendar A calendar control for selecting dates + Spacing="16"> - \ No newline at end of file + diff --git a/samples/ControlCatalog/Pages/CanvasPage.xaml b/samples/ControlCatalog/Pages/CanvasPage.xaml index f934f57c22..10a38895a2 100644 --- a/samples/ControlCatalog/Pages/CanvasPage.xaml +++ b/samples/ControlCatalog/Pages/CanvasPage.xaml @@ -1,5 +1,5 @@ - + Canvas A panel which lays out its children by explicit coordinates @@ -31,4 +31,4 @@ - \ No newline at end of file + diff --git a/samples/ControlCatalog/Pages/CarouselPage.xaml b/samples/ControlCatalog/Pages/CarouselPage.xaml index 3468b71fd8..cf9b13c00c 100644 --- a/samples/ControlCatalog/Pages/CarouselPage.xaml +++ b/samples/ControlCatalog/Pages/CarouselPage.xaml @@ -1,9 +1,9 @@ - + Carousel An items control that displays its items as pages that fill the control. - + @@ -20,7 +20,7 @@ - + Transition None @@ -29,7 +29,7 @@ - + Orientation Horizontal @@ -38,4 +38,4 @@ - \ No newline at end of file + diff --git a/samples/ControlCatalog/Pages/CheckBoxPage.xaml b/samples/ControlCatalog/Pages/CheckBoxPage.xaml index a00b3a7bef..154a6254a4 100644 --- a/samples/ControlCatalog/Pages/CheckBoxPage.xaml +++ b/samples/ControlCatalog/Pages/CheckBoxPage.xaml @@ -1,15 +1,15 @@ - + CheckBox A check box control + Spacing="16"> + Spacing="16"> Unchecked Checked Indeterminate @@ -17,7 +17,7 @@ + Spacing="16"> Three State: Unchecked Three State: Checked Three State: Indeterminate @@ -25,4 +25,4 @@ - \ No newline at end of file + diff --git a/samples/ControlCatalog/Pages/ContextMenuPage.xaml b/samples/ControlCatalog/Pages/ContextMenuPage.xaml index 3af823befc..37eeaeb2ac 100644 --- a/samples/ControlCatalog/Pages/ContextMenuPage.xaml +++ b/samples/ControlCatalog/Pages/ContextMenuPage.xaml @@ -1,12 +1,12 @@ - + Context Menu A right click menu that can be applied to any control. + Spacing="16"> @@ -33,4 +33,4 @@ - \ No newline at end of file + diff --git a/samples/ControlCatalog/Pages/DatePickerPage.xaml b/samples/ControlCatalog/Pages/DatePickerPage.xaml index 92cfa7e178..2c34460fce 100644 --- a/samples/ControlCatalog/Pages/DatePickerPage.xaml +++ b/samples/ControlCatalog/Pages/DatePickerPage.xaml @@ -1,13 +1,13 @@ - + DatePicker A control for selecting dates with a calendar drop-down + Spacing="16"> @@ -43,4 +43,4 @@ - \ No newline at end of file + diff --git a/samples/ControlCatalog/Pages/DialogsPage.xaml b/samples/ControlCatalog/Pages/DialogsPage.xaml index c3e9435630..710d791f3a 100644 --- a/samples/ControlCatalog/Pages/DialogsPage.xaml +++ b/samples/ControlCatalog/Pages/DialogsPage.xaml @@ -1,5 +1,5 @@ - + @@ -9,4 +9,4 @@ - \ No newline at end of file + diff --git a/samples/ControlCatalog/Pages/DragAndDropPage.xaml b/samples/ControlCatalog/Pages/DragAndDropPage.xaml index af679d2f9a..1f3cd3ff71 100644 --- a/samples/ControlCatalog/Pages/DragAndDropPage.xaml +++ b/samples/ControlCatalog/Pages/DragAndDropPage.xaml @@ -1,12 +1,12 @@ - + Drag+Drop Example of Drag+Drop capabilities + Spacing="16"> Drag Me @@ -16,4 +16,4 @@ - \ No newline at end of file + diff --git a/samples/ControlCatalog/Pages/DropDownPage.xaml b/samples/ControlCatalog/Pages/DropDownPage.xaml index 0a7a88e331..5e2a3102e7 100644 --- a/samples/ControlCatalog/Pages/DropDownPage.xaml +++ b/samples/ControlCatalog/Pages/DropDownPage.xaml @@ -1,9 +1,9 @@ - + DropDown A drop-down list. - + Inline Items Inline Item 2 @@ -28,4 +28,4 @@ - \ No newline at end of file + diff --git a/samples/ControlCatalog/Pages/ExpanderPage.xaml b/samples/ControlCatalog/Pages/ExpanderPage.xaml index e32fa1caf1..91440929f5 100644 --- a/samples/ControlCatalog/Pages/ExpanderPage.xaml +++ b/samples/ControlCatalog/Pages/ExpanderPage.xaml @@ -1,12 +1,12 @@ - + Expander Expands to show nested content + Spacing="16"> Expanded content @@ -29,4 +29,4 @@ - \ No newline at end of file + diff --git a/samples/ControlCatalog/Pages/ImagePage.xaml b/samples/ControlCatalog/Pages/ImagePage.xaml index dc93808f27..78fbf90192 100644 --- a/samples/ControlCatalog/Pages/ImagePage.xaml +++ b/samples/ControlCatalog/Pages/ImagePage.xaml @@ -1,12 +1,12 @@ - + Image Displays an image + Spacing="16"> No Stretch - + Menu A window menu + Spacing="16"> diff --git a/samples/ControlCatalog/Pages/NumericUpDownPage.xaml b/samples/ControlCatalog/Pages/NumericUpDownPage.xaml index a5c911f47d..305bcd177c 100644 --- a/samples/ControlCatalog/Pages/NumericUpDownPage.xaml +++ b/samples/ControlCatalog/Pages/NumericUpDownPage.xaml @@ -1,6 +1,6 @@  - + Numeric up-down control Numeric up-down control provides a TextBox with button spinners that allow incrementing and decrementing numeric values by using the spinner buttons, keyboard up/down arrows, or mouse wheel. @@ -26,7 +26,7 @@ VerticalAlignment="Center" Margin="2"> - + @@ -69,7 +69,7 @@ - + Usage of NumericUpDown: - + ProgressBar A progress bar control @@ -7,8 +7,8 @@ - + Spacing="16"> + diff --git a/samples/ControlCatalog/Pages/RadioButtonPage.xaml b/samples/ControlCatalog/Pages/RadioButtonPage.xaml index d382b94f2c..0882817a9a 100644 --- a/samples/ControlCatalog/Pages/RadioButtonPage.xaml +++ b/samples/ControlCatalog/Pages/RadioButtonPage.xaml @@ -1,22 +1,22 @@ - + RadioButton Allows the selection of a single option of many + Spacing="16"> + Spacing="16"> Option 1 Option 2 Option 3 Disabled + Spacing="16"> Three States: Option 1 Three States: Option 2 Three States: Option 3 diff --git a/samples/ControlCatalog/Pages/SliderPage.xaml b/samples/ControlCatalog/Pages/SliderPage.xaml index e43968cb8e..6db71b5fcc 100644 --- a/samples/ControlCatalog/Pages/SliderPage.xaml +++ b/samples/ControlCatalog/Pages/SliderPage.xaml @@ -1,9 +1,9 @@ - + Slider A control that lets the user select from a range of values by moving a Thumb control along a Track. - + - + TextBox A control into which the user can input text - + Spacing="16"> + @@ -26,13 +26,13 @@ - + - + diff --git a/samples/ControlCatalog/Pages/ToolTipPage.xaml b/samples/ControlCatalog/Pages/ToolTipPage.xaml index aa7d60bd11..ad832b9b82 100644 --- a/samples/ControlCatalog/Pages/ToolTipPage.xaml +++ b/samples/ControlCatalog/Pages/ToolTipPage.xaml @@ -1,6 +1,6 @@ + Spacing="4"> ToolTip A control which pops up a hint when a control is hovered diff --git a/samples/ControlCatalog/Pages/TreeViewPage.xaml b/samples/ControlCatalog/Pages/TreeViewPage.xaml index 5806e58c27..1ab49dbb30 100644 --- a/samples/ControlCatalog/Pages/TreeViewPage.xaml +++ b/samples/ControlCatalog/Pages/TreeViewPage.xaml @@ -1,12 +1,12 @@ - + TreeView Displays a hierachical tree of data. + Spacing="16"> diff --git a/samples/VirtualizationDemo/MainWindow.xaml b/samples/VirtualizationDemo/MainWindow.xaml index eb94253d27..730b61ed54 100644 --- a/samples/VirtualizationDemo/MainWindow.xaml +++ b/samples/VirtualizationDemo/MainWindow.xaml @@ -6,7 +6,7 @@ + Spacing="4"> /// Displays a image. /// @@ -68,7 +67,9 @@ namespace Avalonia.Controls Rect sourceRect = new Rect(sourceSize) .CenterRect(new Rect(destRect.Size / scale)); - context.DrawImage(source, 1, sourceRect, destRect); + var interpolationMode = RenderOptions.GetBitmapInterpolationMode(this); + + context.DrawImage(source, 1, sourceRect, destRect, interpolationMode); } } @@ -100,4 +101,4 @@ namespace Avalonia.Controls } } } -} \ No newline at end of file +} diff --git a/src/Avalonia.Controls/Primitives/SelectingItemsControl.cs b/src/Avalonia.Controls/Primitives/SelectingItemsControl.cs index eb3fbde8f2..c8425a0f80 100644 --- a/src/Avalonia.Controls/Primitives/SelectingItemsControl.cs +++ b/src/Avalonia.Controls/Primitives/SelectingItemsControl.cs @@ -376,7 +376,7 @@ namespace Avalonia.Controls.Primitives break; case NotifyCollectionChangedAction.Reset: - SelectedIndex = IndexOf(e.NewItems, SelectedItem); + SelectedIndex = IndexOf(Items, SelectedItem); break; } } diff --git a/src/Avalonia.Controls/Slider.cs b/src/Avalonia.Controls/Slider.cs index 2ef0af2852..31113812d1 100644 --- a/src/Avalonia.Controls/Slider.cs +++ b/src/Avalonia.Controls/Slider.cs @@ -17,7 +17,7 @@ namespace Avalonia.Controls /// Defines the property. /// public static readonly StyledProperty OrientationProperty = - AvaloniaProperty.Register(nameof(Orientation), Orientation.Horizontal); + ScrollBar.OrientationProperty.AddOwner(); /// /// Defines the property. @@ -41,8 +41,7 @@ namespace Avalonia.Controls /// static Slider() { - PseudoClass(OrientationProperty, o => o == Avalonia.Controls.Orientation.Vertical, ":vertical"); - PseudoClass(OrientationProperty, o => o == Avalonia.Controls.Orientation.Horizontal, ":horizontal"); + OrientationProperty.OverrideDefaultValue(typeof(Slider), Orientation.Horizontal); Thumb.DragStartedEvent.AddClassHandler(x => x.OnThumbDragStarted, RoutingStrategies.Bubble); Thumb.DragDeltaEvent.AddClassHandler(x => x.OnThumbDragDelta, RoutingStrategies.Bubble); Thumb.DragCompletedEvent.AddClassHandler(x => x.OnThumbDragCompleted, RoutingStrategies.Bubble); diff --git a/src/Avalonia.Controls/StackPanel.cs b/src/Avalonia.Controls/StackPanel.cs index d404e6913b..b0ccd8a3d1 100644 --- a/src/Avalonia.Controls/StackPanel.cs +++ b/src/Avalonia.Controls/StackPanel.cs @@ -13,10 +13,10 @@ namespace Avalonia.Controls public class StackPanel : Panel, INavigableContainer { /// - /// Defines the property. + /// Defines the property. /// - public static readonly StyledProperty GapProperty = - AvaloniaProperty.Register(nameof(Gap)); + public static readonly StyledProperty SpacingProperty = + AvaloniaProperty.Register(nameof(Spacing)); /// /// Defines the property. @@ -29,17 +29,17 @@ namespace Avalonia.Controls /// static StackPanel() { - AffectsMeasure(GapProperty); + AffectsMeasure(SpacingProperty); AffectsMeasure(OrientationProperty); } /// - /// Gets or sets the size of the gap to place between child controls. + /// Gets or sets the size of the spacing to place between child controls. /// - public double Gap + public double Spacing { - get { return GetValue(GapProperty); } - set { SetValue(GapProperty, value); } + get { return GetValue(SpacingProperty); } + set { SetValue(SpacingProperty, value); } } /// @@ -152,7 +152,7 @@ namespace Avalonia.Controls double measuredWidth = 0; double measuredHeight = 0; - double gap = Gap; + double spacing = Spacing; bool hasVisibleChild = Children.Any(c => c.IsVisible); foreach (Control child in Children) @@ -162,23 +162,23 @@ namespace Avalonia.Controls if (Orientation == Orientation.Vertical) { - measuredHeight += size.Height + (child.IsVisible ? gap : 0); + measuredHeight += size.Height + (child.IsVisible ? spacing : 0); measuredWidth = Math.Max(measuredWidth, size.Width); } else { - measuredWidth += size.Width + (child.IsVisible ? gap : 0); + measuredWidth += size.Width + (child.IsVisible ? spacing : 0); measuredHeight = Math.Max(measuredHeight, size.Height); } } if (Orientation == Orientation.Vertical) { - measuredHeight -= (hasVisibleChild ? gap : 0); + measuredHeight -= (hasVisibleChild ? spacing : 0); } else { - measuredWidth -= (hasVisibleChild ? gap : 0); + measuredWidth -= (hasVisibleChild ? spacing : 0); } return new Size(measuredWidth, measuredHeight); @@ -194,7 +194,7 @@ namespace Avalonia.Controls var orientation = Orientation; double arrangedWidth = finalSize.Width; double arrangedHeight = finalSize.Height; - double gap = Gap; + double spacing = Spacing; bool hasVisibleChild = Children.Any(c => c.IsVisible); if (Orientation == Orientation.Vertical) @@ -217,25 +217,25 @@ namespace Avalonia.Controls Rect childFinal = new Rect(0, arrangedHeight, width, childHeight); ArrangeChild(child, childFinal, finalSize, orientation); arrangedWidth = Math.Max(arrangedWidth, childWidth); - arrangedHeight += childHeight + (child.IsVisible ? gap : 0); + arrangedHeight += childHeight + (child.IsVisible ? spacing : 0); } else { double height = Math.Max(childHeight, arrangedHeight); Rect childFinal = new Rect(arrangedWidth, 0, childWidth, height); ArrangeChild(child, childFinal, finalSize, orientation); - arrangedWidth += childWidth + (child.IsVisible ? gap : 0); + arrangedWidth += childWidth + (child.IsVisible ? spacing : 0); arrangedHeight = Math.Max(arrangedHeight, childHeight); } } if (orientation == Orientation.Vertical) { - arrangedHeight = Math.Max(arrangedHeight - (hasVisibleChild ? gap : 0), finalSize.Height); + arrangedHeight = Math.Max(arrangedHeight - (hasVisibleChild ? spacing : 0), finalSize.Height); } else { - arrangedWidth = Math.Max(arrangedWidth - (hasVisibleChild ? gap : 0), finalSize.Width); + arrangedWidth = Math.Max(arrangedWidth - (hasVisibleChild ? spacing : 0), finalSize.Width); } return new Size(arrangedWidth, arrangedHeight); @@ -250,4 +250,4 @@ namespace Avalonia.Controls child.Arrange(rect); } } -} \ No newline at end of file +} diff --git a/src/Avalonia.Controls/VirtualizingStackPanel.cs b/src/Avalonia.Controls/VirtualizingStackPanel.cs index dee537029c..5f7b63c57a 100644 --- a/src/Avalonia.Controls/VirtualizingStackPanel.cs +++ b/src/Avalonia.Controls/VirtualizingStackPanel.cs @@ -200,7 +200,7 @@ namespace Avalonia.Controls private void UpdateAdd(IControl child) { var bounds = Bounds; - var gap = Gap; + var spacing = Spacing; child.Measure(_availableSpace); ++_averageCount; @@ -208,13 +208,13 @@ namespace Avalonia.Controls if (Orientation == Orientation.Vertical) { var height = child.DesiredSize.Height; - _takenSpace += height + gap; + _takenSpace += height + spacing; AddToAverageItemSize(height); } else { var width = child.DesiredSize.Width; - _takenSpace += width + gap; + _takenSpace += width + spacing; AddToAverageItemSize(width); } } @@ -222,18 +222,18 @@ namespace Avalonia.Controls private void UpdateRemove(IControl child) { var bounds = Bounds; - var gap = Gap; + var spacing = Spacing; if (Orientation == Orientation.Vertical) { var height = child.DesiredSize.Height; - _takenSpace -= height + gap; + _takenSpace -= height + spacing; RemoveFromAverageItemSize(height); } else { var width = child.DesiredSize.Width; - _takenSpace -= width + gap; + _takenSpace -= width + spacing; RemoveFromAverageItemSize(width); } diff --git a/src/Avalonia.Controls/Window.cs b/src/Avalonia.Controls/Window.cs index d1a023c42c..7e1d8f18f0 100644 --- a/src/Avalonia.Controls/Window.cs +++ b/src/Avalonia.Controls/Window.cs @@ -302,17 +302,23 @@ namespace Avalonia.Controls internal void Close(bool ignoreCancel) { + bool close = true; + try { if (!ignoreCancel && HandleClosing()) { + close = false; return; } } finally { - PlatformImpl?.Dispose(); - HandleClosed(); + if (close) + { + PlatformImpl?.Dispose(); + HandleClosed(); + } } } diff --git a/src/Avalonia.Controls/WindowCollection.cs b/src/Avalonia.Controls/WindowCollection.cs index c21a12f05b..df79c3e3c8 100644 --- a/src/Avalonia.Controls/WindowCollection.cs +++ b/src/Avalonia.Controls/WindowCollection.cs @@ -96,7 +96,7 @@ namespace Avalonia { while (_windows.Count > 0) { - _windows[0].Close(); + _windows[0].Close(true); } } @@ -131,4 +131,4 @@ namespace Avalonia } } } -} \ No newline at end of file +} diff --git a/src/Avalonia.DesignerSupport/Avalonia.DesignerSupport.csproj b/src/Avalonia.DesignerSupport/Avalonia.DesignerSupport.csproj index 9f54137e47..5ccb98b64d 100644 --- a/src/Avalonia.DesignerSupport/Avalonia.DesignerSupport.csproj +++ b/src/Avalonia.DesignerSupport/Avalonia.DesignerSupport.csproj @@ -1,7 +1,12 @@  netstandard2.0 - false + + 0.7.0 true @@ -37,11 +42,6 @@ - - - Properties\SharedAssemblyInfo.cs - - \ No newline at end of file diff --git a/src/Avalonia.Diagnostics/DevTools.xaml b/src/Avalonia.Diagnostics/DevTools.xaml index bb1b2e841e..844670e794 100644 --- a/src/Avalonia.Diagnostics/DevTools.xaml +++ b/src/Avalonia.Diagnostics/DevTools.xaml @@ -7,7 +7,7 @@ - + Hold Ctrl+Shift over a control to inspect. Focused: @@ -17,4 +17,4 @@ - \ No newline at end of file + diff --git a/src/Avalonia.Diagnostics/Views/TreePageView.xaml b/src/Avalonia.Diagnostics/Views/TreePageView.xaml index a715ca6fc5..57398851ad 100644 --- a/src/Avalonia.Diagnostics/Views/TreePageView.xaml +++ b/src/Avalonia.Diagnostics/Views/TreePageView.xaml @@ -5,7 +5,7 @@ - + @@ -21,4 +21,4 @@ - \ No newline at end of file + diff --git a/src/Avalonia.Visuals/Media/DrawingContext.cs b/src/Avalonia.Visuals/Media/DrawingContext.cs index 962f2c1ba8..60a7a2e518 100644 --- a/src/Avalonia.Visuals/Media/DrawingContext.cs +++ b/src/Avalonia.Visuals/Media/DrawingContext.cs @@ -2,9 +2,10 @@ using System; using System.Collections.Generic; using Avalonia.Media.Imaging; using Avalonia.Platform; +using Avalonia.Visuals.Media.Imaging; namespace Avalonia.Media -{ +{ public sealed class DrawingContext : IDisposable { private int _currentLevel; @@ -68,11 +69,12 @@ namespace Avalonia.Media /// The opacity to draw with. /// The rect in the image to draw. /// The rect in the output to draw to. - public void DrawImage(IBitmap source, double opacity, Rect sourceRect, Rect destRect) + /// The bitmap interpolation mode. + public void DrawImage(IBitmap source, double opacity, Rect sourceRect, Rect destRect, BitmapInterpolationMode bitmapInterpolationMode = default) { Contract.Requires(source != null); - PlatformImpl.DrawImage(source.PlatformImpl, opacity, sourceRect, destRect); + PlatformImpl.DrawImage(source.PlatformImpl, opacity, sourceRect, destRect, bitmapInterpolationMode); } /// @@ -309,4 +311,4 @@ namespace Avalonia.Media return pen?.Brush != null && pen.Thickness > 0; } } -} \ No newline at end of file +} diff --git a/src/Avalonia.Visuals/Media/ITileBrush.cs b/src/Avalonia.Visuals/Media/ITileBrush.cs index 8e2349f506..5cffe02193 100644 --- a/src/Avalonia.Visuals/Media/ITileBrush.cs +++ b/src/Avalonia.Visuals/Media/ITileBrush.cs @@ -1,5 +1,10 @@ -namespace Avalonia.Media -{ +// 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 Avalonia.Visuals.Media.Imaging; + +namespace Avalonia.Media +{ /// /// A brush which displays a repeating image. /// @@ -35,5 +40,13 @@ /// Gets the brush's tile mode. /// TileMode TileMode { get; } + + /// + /// Gets the bitmap interpolation mode. + /// + /// + /// The bitmap interpolation mode. + /// + BitmapInterpolationMode BitmapInterpolationMode { get; } } -} \ No newline at end of file +} diff --git a/src/Avalonia.Visuals/Media/Imaging/BitmapInterpolationMode.cs b/src/Avalonia.Visuals/Media/Imaging/BitmapInterpolationMode.cs new file mode 100644 index 0000000000..7e6d330618 --- /dev/null +++ b/src/Avalonia.Visuals/Media/Imaging/BitmapInterpolationMode.cs @@ -0,0 +1,31 @@ +// 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. + +namespace Avalonia.Visuals.Media.Imaging +{ + /// + /// Controls the performance and quality of bitmap scaling. + /// + public enum BitmapInterpolationMode + { + /// + /// Uses the default behavior of the underling render backend. + /// + Default, + + /// + /// The best performance but worst image quality. + /// + LowQuality, + + /// + /// Good performance and decent image quality. + /// + MediumQuality, + + /// + /// Highest quality but worst performance. + /// + HighQuality + } +} diff --git a/src/Avalonia.Visuals/Media/Immutable/ImmutableImageBrush.cs b/src/Avalonia.Visuals/Media/Immutable/ImmutableImageBrush.cs index 678f99c20d..15da8f8b43 100644 --- a/src/Avalonia.Visuals/Media/Immutable/ImmutableImageBrush.cs +++ b/src/Avalonia.Visuals/Media/Immutable/ImmutableImageBrush.cs @@ -1,5 +1,5 @@ -using System; -using Avalonia.Media.Imaging; +using Avalonia.Media.Imaging; +using Avalonia.Visuals.Media.Imaging; namespace Avalonia.Media.Immutable { @@ -21,6 +21,7 @@ namespace Avalonia.Media.Immutable /// How the source rectangle will be stretched to fill the destination rect. /// /// The tile mode. + /// The bitmap interpolation mode. public ImmutableImageBrush( IBitmap source, AlignmentX alignmentX = AlignmentX.Center, @@ -29,7 +30,8 @@ namespace Avalonia.Media.Immutable double opacity = 1, RelativeRect? sourceRect = null, Stretch stretch = Stretch.Uniform, - TileMode tileMode = TileMode.None) + TileMode tileMode = TileMode.None, + BitmapInterpolationMode bitmapInterpolationMode = BitmapInterpolationMode.Default) : base( alignmentX, alignmentY, @@ -37,7 +39,8 @@ namespace Avalonia.Media.Immutable opacity, sourceRect ?? RelativeRect.Fill, stretch, - tileMode) + tileMode, + bitmapInterpolationMode) { Source = source; } diff --git a/src/Avalonia.Visuals/Media/Immutable/ImmutableTileBrush.cs b/src/Avalonia.Visuals/Media/Immutable/ImmutableTileBrush.cs index 37c391040f..c3dd159d04 100644 --- a/src/Avalonia.Visuals/Media/Immutable/ImmutableTileBrush.cs +++ b/src/Avalonia.Visuals/Media/Immutable/ImmutableTileBrush.cs @@ -1,4 +1,7 @@ -using System; +// 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 Avalonia.Visuals.Media.Imaging; namespace Avalonia.Media.Immutable { @@ -19,6 +22,7 @@ namespace Avalonia.Media.Immutable /// How the source rectangle will be stretched to fill the destination rect. /// /// The tile mode. + /// The bitmap interpolation mode. protected ImmutableTileBrush( AlignmentX alignmentX, AlignmentY alignmentY, @@ -26,7 +30,8 @@ namespace Avalonia.Media.Immutable double opacity, RelativeRect sourceRect, Stretch stretch, - TileMode tileMode) + TileMode tileMode, + BitmapInterpolationMode bitmapInterpolationMode) { AlignmentX = alignmentX; AlignmentY = alignmentY; @@ -35,6 +40,7 @@ namespace Avalonia.Media.Immutable SourceRect = sourceRect; Stretch = stretch; TileMode = tileMode; + BitmapInterpolationMode = bitmapInterpolationMode; } /// @@ -49,7 +55,8 @@ namespace Avalonia.Media.Immutable source.Opacity, source.SourceRect, source.Stretch, - source.TileMode) + source.TileMode, + source.BitmapInterpolationMode) { } @@ -73,5 +80,8 @@ namespace Avalonia.Media.Immutable /// public TileMode TileMode { get; } + + /// + public BitmapInterpolationMode BitmapInterpolationMode { get; } } } diff --git a/src/Avalonia.Visuals/Media/Immutable/ImmutableVisualBrush.cs b/src/Avalonia.Visuals/Media/Immutable/ImmutableVisualBrush.cs index b07d98867c..f1f61a6e65 100644 --- a/src/Avalonia.Visuals/Media/Immutable/ImmutableVisualBrush.cs +++ b/src/Avalonia.Visuals/Media/Immutable/ImmutableVisualBrush.cs @@ -1,4 +1,7 @@ -using System; +// 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 Avalonia.Visuals.Media.Imaging; using Avalonia.VisualTree; namespace Avalonia.Media.Immutable @@ -21,6 +24,7 @@ namespace Avalonia.Media.Immutable /// How the source rectangle will be stretched to fill the destination rect. /// /// The tile mode. + /// Controls the quality of interpolation. public ImmutableVisualBrush( IVisual visual, AlignmentX alignmentX = AlignmentX.Center, @@ -29,7 +33,8 @@ namespace Avalonia.Media.Immutable double opacity = 1, RelativeRect? sourceRect = null, Stretch stretch = Stretch.Uniform, - TileMode tileMode = TileMode.None) + TileMode tileMode = TileMode.None, + BitmapInterpolationMode bitmapInterpolationMode = BitmapInterpolationMode.Default) : base( alignmentX, alignmentY, @@ -37,7 +42,8 @@ namespace Avalonia.Media.Immutable opacity, sourceRect ?? RelativeRect.Fill, stretch, - tileMode) + tileMode, + bitmapInterpolationMode) { Visual = visual; } diff --git a/src/Avalonia.Visuals/Media/RenderOptions.cs b/src/Avalonia.Visuals/Media/RenderOptions.cs new file mode 100644 index 0000000000..180863f9e8 --- /dev/null +++ b/src/Avalonia.Visuals/Media/RenderOptions.cs @@ -0,0 +1,39 @@ +// 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 Avalonia.Visuals.Media.Imaging; + +namespace Avalonia.Media +{ + public class RenderOptions + { + /// + /// Defines the property. + /// + public static readonly StyledProperty BitmapInterpolationModeProperty = + AvaloniaProperty.RegisterAttached( + "BitmapInterpolationMode", + BitmapInterpolationMode.MediumQuality, + inherits: true); + + /// + /// Gets the value of the BitmapInterpolationMode attached property for a control. + /// + /// The control. + /// The control's left coordinate. + public static BitmapInterpolationMode GetBitmapInterpolationMode(AvaloniaObject element) + { + return element.GetValue(BitmapInterpolationModeProperty); + } + + /// + /// Sets the value of the BitmapInterpolationMode attached property for a control. + /// + /// The control. + /// The left value. + public static void SetBitmapInterpolationMode(AvaloniaObject element, BitmapInterpolationMode value) + { + element.SetValue(BitmapInterpolationModeProperty, value); + } + } +} diff --git a/src/Avalonia.Visuals/Media/TileBrush.cs b/src/Avalonia.Visuals/Media/TileBrush.cs index 3a7f9d9920..2033754137 100644 --- a/src/Avalonia.Visuals/Media/TileBrush.cs +++ b/src/Avalonia.Visuals/Media/TileBrush.cs @@ -1,6 +1,8 @@ // 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 Avalonia.Visuals.Media.Imaging; + namespace Avalonia.Media { /// @@ -75,6 +77,11 @@ namespace Avalonia.Media public static readonly StyledProperty TileModeProperty = AvaloniaProperty.Register(nameof(TileMode)); + static TileBrush() + { + RenderOptions.BitmapInterpolationModeProperty.OverrideDefaultValue(BitmapInterpolationMode.Default); + } + /// /// Gets or sets the horizontal alignment of a tile in the destination. /// @@ -129,5 +136,17 @@ namespace Avalonia.Media get { return (TileMode)GetValue(TileModeProperty); } set { SetValue(TileModeProperty, value); } } + + /// + /// Gets or sets the bitmap interpolation mode. + /// + /// + /// The bitmap interpolation mode. + /// + public BitmapInterpolationMode BitmapInterpolationMode + { + get { return RenderOptions.GetBitmapInterpolationMode(this); } + set { RenderOptions.SetBitmapInterpolationMode(this, value); } + } } } diff --git a/src/Avalonia.Visuals/Platform/IDrawingContextImpl.cs b/src/Avalonia.Visuals/Platform/IDrawingContextImpl.cs index 04bbe713f2..b11d9f52ab 100644 --- a/src/Avalonia.Visuals/Platform/IDrawingContextImpl.cs +++ b/src/Avalonia.Visuals/Platform/IDrawingContextImpl.cs @@ -4,6 +4,7 @@ using System; using Avalonia.Media; using Avalonia.Utilities; +using Avalonia.Visuals.Media.Imaging; namespace Avalonia.Platform { @@ -30,7 +31,8 @@ namespace Avalonia.Platform /// The opacity to draw with. /// The rect in the image to draw. /// The rect in the output to draw to. - void DrawImage(IRef source, double opacity, Rect sourceRect, Rect destRect); + /// The bitmap interpolation mode. + void DrawImage(IRef source, double opacity, Rect sourceRect, Rect destRect, BitmapInterpolationMode bitmapInterpolationMode = BitmapInterpolationMode.Default); /// /// Draws a bitmap image. diff --git a/src/Avalonia.Visuals/Rendering/SceneGraph/DeferredDrawingContextImpl.cs b/src/Avalonia.Visuals/Rendering/SceneGraph/DeferredDrawingContextImpl.cs index f3dbfbd8fb..42ecde6a6d 100644 --- a/src/Avalonia.Visuals/Rendering/SceneGraph/DeferredDrawingContextImpl.cs +++ b/src/Avalonia.Visuals/Rendering/SceneGraph/DeferredDrawingContextImpl.cs @@ -7,6 +7,7 @@ using Avalonia.Media; using Avalonia.Platform; using Avalonia.Utilities; using Avalonia.VisualTree; +using Avalonia.Visuals.Media.Imaging; namespace Avalonia.Rendering.SceneGraph { @@ -114,13 +115,13 @@ namespace Avalonia.Rendering.SceneGraph } /// - public void DrawImage(IRef source, double opacity, Rect sourceRect, Rect destRect) + public void DrawImage(IRef source, double opacity, Rect sourceRect, Rect destRect, BitmapInterpolationMode bitmapInterpolationMode) { var next = NextDrawAs(); - if (next == null || !next.Item.Equals(Transform, source, opacity, sourceRect, destRect)) + if (next == null || !next.Item.Equals(Transform, source, opacity, sourceRect, destRect, bitmapInterpolationMode)) { - Add(new ImageNode(Transform, source, opacity, sourceRect, destRect)); + Add(new ImageNode(Transform, source, opacity, sourceRect, destRect, bitmapInterpolationMode)); } else { diff --git a/src/Avalonia.Visuals/Rendering/SceneGraph/ImageNode.cs b/src/Avalonia.Visuals/Rendering/SceneGraph/ImageNode.cs index 06fdb3f86c..9e8fca5f84 100644 --- a/src/Avalonia.Visuals/Rendering/SceneGraph/ImageNode.cs +++ b/src/Avalonia.Visuals/Rendering/SceneGraph/ImageNode.cs @@ -4,6 +4,7 @@ using System; using Avalonia.Platform; using Avalonia.Utilities; +using Avalonia.Visuals.Media.Imaging; namespace Avalonia.Rendering.SceneGraph { @@ -20,7 +21,8 @@ namespace Avalonia.Rendering.SceneGraph /// The draw opacity. /// The source rect. /// The destination rect. - public ImageNode(Matrix transform, IRef source, double opacity, Rect sourceRect, Rect destRect) + /// The bitmap interpolation mode. + public ImageNode(Matrix transform, IRef source, double opacity, Rect sourceRect, Rect destRect, BitmapInterpolationMode bitmapInterpolationMode) : base(destRect, transform, null) { Transform = transform; @@ -28,7 +30,8 @@ namespace Avalonia.Rendering.SceneGraph Opacity = opacity; SourceRect = sourceRect; DestRect = destRect; - } + BitmapInterpolationMode = bitmapInterpolationMode; + } /// /// Gets the transform with which the node will be drawn. @@ -55,6 +58,14 @@ namespace Avalonia.Rendering.SceneGraph /// public Rect DestRect { get; } + /// + /// Gets the bitmap interpolation mode. + /// + /// + /// The scaling mode. + /// + public BitmapInterpolationMode BitmapInterpolationMode { get; } + /// /// Determines if this draw operation equals another. /// @@ -63,18 +74,20 @@ namespace Avalonia.Rendering.SceneGraph /// The opacity of the other draw operation. /// The source rect of the other draw operation. /// The dest rect of the other draw operation. + /// The bitmap interpolation mode. /// True if the draw operations are the same, otherwise false. /// /// The properties of the other draw operation are passed in as arguments to prevent /// allocation of a not-yet-constructed draw operation object. /// - public bool Equals(Matrix transform, IRef source, double opacity, Rect sourceRect, Rect destRect) + public bool Equals(Matrix transform, IRef source, double opacity, Rect sourceRect, Rect destRect, BitmapInterpolationMode bitmapInterpolationMode) { return transform == Transform && Equals(source.Item, Source.Item) && opacity == Opacity && sourceRect == SourceRect && - destRect == DestRect; + destRect == DestRect && + bitmapInterpolationMode == BitmapInterpolationMode; } /// @@ -83,7 +96,7 @@ namespace Avalonia.Rendering.SceneGraph // TODO: Probably need to introduce some kind of locking mechanism in the case of // WriteableBitmap. context.Transform = Transform; - context.DrawImage(Source, Opacity, SourceRect, DestRect); + context.DrawImage(Source, Opacity, SourceRect, DestRect, BitmapInterpolationMode); } /// diff --git a/src/Gtk/Avalonia.Gtk3/KeyTransform.cs b/src/Gtk/Avalonia.Gtk3/KeyTransform.cs index 5a34db2e04..69c5a1bf5f 100644 --- a/src/Gtk/Avalonia.Gtk3/KeyTransform.cs +++ b/src/Gtk/Avalonia.Gtk3/KeyTransform.cs @@ -33,17 +33,24 @@ namespace Avalonia.Gtk.Common { GdkKey.Prior, Key.Prior }, //{ GdkKey.?, Key.PageDown } { GdkKey.End, Key.End }, + { GdkKey.KP_End, Key.End }, { GdkKey.Home, Key.Home }, + { GdkKey.KP_Home, Key.Home }, { GdkKey.Left, Key.Left }, + { GdkKey.KP_Left, Key.Left }, { GdkKey.Up, Key.Up }, + { GdkKey.KP_Up, Key.Up }, { GdkKey.Right, Key.Right }, + { GdkKey.KP_Right, Key.Right }, { GdkKey.Down, Key.Down }, + { GdkKey.KP_Down, Key.Down }, { GdkKey.Select, Key.Select }, { GdkKey.Print, Key.Print }, { GdkKey.Execute, Key.Execute }, //{ GdkKey.?, Key.Snapshot } { GdkKey.Insert, Key.Insert }, { GdkKey.Delete, Key.Delete }, + { GdkKey.KP_Delete, Key.Delete }, { GdkKey.Help, Key.Help }, //{ GdkKey.?, Key.D0 } //{ GdkKey.?, Key.D1 } diff --git a/src/Skia/Avalonia.Skia/DrawingContextImpl.cs b/src/Skia/Avalonia.Skia/DrawingContextImpl.cs index d2c4bd0aa1..685987ae80 100644 --- a/src/Skia/Avalonia.Skia/DrawingContextImpl.cs +++ b/src/Skia/Avalonia.Skia/DrawingContextImpl.cs @@ -10,6 +10,7 @@ using Avalonia.Platform; using Avalonia.Rendering; using Avalonia.Rendering.Utilities; using Avalonia.Utilities; +using Avalonia.Visuals.Media.Imaging; using SkiaSharp; namespace Avalonia.Skia @@ -95,24 +96,46 @@ namespace Avalonia.Skia } /// - public void DrawImage(IRef source, double opacity, Rect sourceRect, Rect destRect) + public void DrawImage(IRef source, double opacity, Rect sourceRect, Rect destRect, BitmapInterpolationMode bitmapInterpolationMode) { - var drawableImage = (IDrawableBitmapImpl) source.Item; + var drawableImage = (IDrawableBitmapImpl)source.Item; var s = sourceRect.ToSKRect(); var d = destRect.ToSKRect(); using (var paint = - new SKPaint {Color = new SKColor(255, 255, 255, (byte) (255 * opacity * _currentOpacity))}) + new SKPaint + { + Color = new SKColor(255, 255, 255, (byte)(255 * opacity * _currentOpacity)) + }) { + paint.FilterQuality = GetInterpolationMode(bitmapInterpolationMode); + drawableImage.Draw(this, s, d, paint); } } + private static SKFilterQuality GetInterpolationMode(BitmapInterpolationMode interpolationMode) + { + switch (interpolationMode) + { + case BitmapInterpolationMode.LowQuality: + return SKFilterQuality.Low; + case BitmapInterpolationMode.MediumQuality: + return SKFilterQuality.Medium; + case BitmapInterpolationMode.HighQuality: + return SKFilterQuality.High; + case BitmapInterpolationMode.Default: + return SKFilterQuality.None; + default: + throw new ArgumentOutOfRangeException(nameof(interpolationMode), interpolationMode, null); + } + } + /// public void DrawImage(IRef source, IBrush opacityMask, Rect opacityMaskRect, Rect destRect) { PushOpacityMask(opacityMask, opacityMaskRect); - DrawImage(source, 1, new Rect(0, 0, source.Item.PixelWidth, source.Item.PixelHeight), destRect); + DrawImage(source, 1, new Rect(0, 0, source.Item.PixelWidth, source.Item.PixelHeight), destRect, BitmapInterpolationMode.Default); PopOpacityMask(); } @@ -357,6 +380,7 @@ namespace Avalonia.Skia /// Target size. /// Tile brush to use. /// Tile brush image. + /// The bitmap interpolation mode. private void ConfigureTileBrush(ref PaintWrapper paintWrapper, Size targetSize, ITileBrush tileBrush, IDrawableBitmapImpl tileBrushImage) { var calc = new TileBrushCalculator(tileBrush, @@ -375,7 +399,7 @@ namespace Avalonia.Skia context.Clear(Colors.Transparent); context.PushClip(calc.IntermediateClip); context.Transform = calc.IntermediateTransform; - context.DrawImage(RefCountable.CreateUnownedNotClonable(tileBrushImage), 1, rect, rect); + context.DrawImage(RefCountable.CreateUnownedNotClonable(tileBrushImage), 1, rect, rect, tileBrush.BitmapInterpolationMode); context.PopClip(); } @@ -484,7 +508,7 @@ namespace Avalonia.Skia } else { - tileBrushImage = (IDrawableBitmapImpl) (tileBrush as IImageBrush)?.Source?.PlatformImpl.Item; + tileBrushImage = (IDrawableBitmapImpl)(tileBrush as IImageBrush)?.Source?.PlatformImpl.Item; } if (tileBrush != null && tileBrushImage != null) @@ -690,4 +714,4 @@ namespace Avalonia.Skia } } } -} \ No newline at end of file +} diff --git a/src/Windows/Avalonia.Direct2D1/Media/DrawingContextImpl.cs b/src/Windows/Avalonia.Direct2D1/Media/DrawingContextImpl.cs index 479db51be4..ae5dd3ae13 100644 --- a/src/Windows/Avalonia.Direct2D1/Media/DrawingContextImpl.cs +++ b/src/Windows/Avalonia.Direct2D1/Media/DrawingContextImpl.cs @@ -10,13 +10,14 @@ using Avalonia.Utilities; using SharpDX; using SharpDX.Direct2D1; using SharpDX.Mathematics.Interop; +using BitmapInterpolationMode = Avalonia.Visuals.Media.Imaging.BitmapInterpolationMode; namespace Avalonia.Direct2D1.Media { /// /// Draws using Direct2D1. /// - public class DrawingContextImpl : IDrawingContextImpl, IDisposable + public class DrawingContextImpl : IDrawingContextImpl { private readonly IVisualBrushRenderer _visualBrushRenderer; private readonly ILayerFactory _layerFactory; @@ -100,19 +101,37 @@ namespace Avalonia.Direct2D1.Media /// The opacity to draw with. /// The rect in the image to draw. /// The rect in the output to draw to. - public void DrawImage(IRef source, double opacity, Rect sourceRect, Rect destRect) + /// The bitmap interpolation mode. + public void DrawImage(IRef source, double opacity, Rect sourceRect, Rect destRect, BitmapInterpolationMode bitmapInterpolationMode) { using (var d2d = ((BitmapImpl)source.Item).GetDirect2DBitmap(_renderTarget)) { + var interpolationMode = GetInterpolationMode(bitmapInterpolationMode); + _renderTarget.DrawBitmap( d2d.Value, destRect.ToSharpDX(), (float)opacity, - BitmapInterpolationMode.Linear, + interpolationMode, sourceRect.ToSharpDX()); } } + private static SharpDX.Direct2D1.BitmapInterpolationMode GetInterpolationMode(BitmapInterpolationMode interpolationMode) + { + switch (interpolationMode) + { + case BitmapInterpolationMode.LowQuality: + return SharpDX.Direct2D1.BitmapInterpolationMode.NearestNeighbor; + case BitmapInterpolationMode.MediumQuality: + case BitmapInterpolationMode.HighQuality: + case BitmapInterpolationMode.Default: + return SharpDX.Direct2D1.BitmapInterpolationMode.Linear; + default: + throw new ArgumentOutOfRangeException(nameof(interpolationMode), interpolationMode, null); + } + } + /// /// Draws a bitmap image. /// diff --git a/src/Windows/Avalonia.Direct2D1/Media/ImageBrushImpl.cs b/src/Windows/Avalonia.Direct2D1/Media/ImageBrushImpl.cs index 75b397edd6..3fc8760a9e 100644 --- a/src/Windows/Avalonia.Direct2D1/Media/ImageBrushImpl.cs +++ b/src/Windows/Avalonia.Direct2D1/Media/ImageBrushImpl.cs @@ -1,7 +1,6 @@ // 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 Avalonia.Media; using Avalonia.Rendering.Utilities; using Avalonia.Utilities; @@ -11,7 +10,9 @@ namespace Avalonia.Direct2D1.Media { public sealed class ImageBrushImpl : BrushImpl { - OptionalDispose _bitmap; + private readonly OptionalDispose _bitmap; + + private readonly Visuals.Media.Imaging.BitmapInterpolationMode _bitmapInterpolationMode; public ImageBrushImpl( ITileBrush brush, @@ -41,6 +42,8 @@ namespace Avalonia.Direct2D1.Media GetBrushProperties(brush, calc.DestinationRect)); } } + + _bitmapInterpolationMode = brush.BitmapInterpolationMode; } public override void Dispose() @@ -102,7 +105,7 @@ namespace Avalonia.Direct2D1.Media context.PushClip(calc.IntermediateClip); context.Transform = calc.IntermediateTransform; - context.DrawImage(RefCountable.CreateUnownedNotClonable(bitmap), 1, rect, rect); + context.DrawImage(RefCountable.CreateUnownedNotClonable(bitmap), 1, rect, rect, _bitmapInterpolationMode); context.PopClip(); } diff --git a/tests/Avalonia.Controls.UnitTests/Primitives/SelectingItemsControlTests.cs b/tests/Avalonia.Controls.UnitTests/Primitives/SelectingItemsControlTests.cs index c7a3465ac4..14e1b15ebc 100644 --- a/tests/Avalonia.Controls.UnitTests/Primitives/SelectingItemsControlTests.cs +++ b/tests/Avalonia.Controls.UnitTests/Primitives/SelectingItemsControlTests.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Collections.ObjectModel; +using System.Collections.Specialized; using System.Linq; using Avalonia.Collections; using Avalonia.Controls.Presenters; @@ -13,6 +14,7 @@ using Avalonia.Input; using Avalonia.Interactivity; using Avalonia.Markup.Data; using Avalonia.UnitTests; +using Moq; using Xunit; namespace Avalonia.Controls.UnitTests.Primitives @@ -686,6 +688,26 @@ namespace Avalonia.Controls.UnitTests.Primitives Assert.Null(KeyboardNavigation.GetTabOnceActiveElement((InputElement)panel)); } + [Fact] + public void Resetting_Items_Collection_Should_Retain_Selection() + { + var itemsMock = new Mock>(); + var itemsMockAsINCC = itemsMock.As(); + + itemsMock.Object.AddRange(new[] { "Foo", "Bar", "Baz" }); + var target = new SelectingItemsControl + { + Items = itemsMock.Object + }; + + target.SelectedIndex = 1; + + itemsMockAsINCC.Raise(e => e.CollectionChanged += null, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset)); + + Assert.True(target.SelectedIndex == 1); + } + + private FuncControlTemplate Template() { return new FuncControlTemplate(control => diff --git a/tests/Avalonia.Controls.UnitTests/SliderTests.cs b/tests/Avalonia.Controls.UnitTests/SliderTests.cs new file mode 100644 index 0000000000..dc47d9eb89 --- /dev/null +++ b/tests/Avalonia.Controls.UnitTests/SliderTests.cs @@ -0,0 +1,39 @@ +using System; +using System.Collections.Generic; +using System.Text; +using Xunit; + +namespace Avalonia.Controls.UnitTests +{ + public class SliderTests + { + [Fact] + public void Default_Orientation_Should_Be_Horizontal() + { + var slider = new Slider(); + Assert.Equal(Orientation.Horizontal, slider.Orientation); + } + + [Fact] + public void Should_Set_Horizontal_Class() + { + var slider = new Slider + { + Orientation = Orientation.Horizontal + }; + + Assert.Contains(slider.Classes, ":horizontal".Equals); + } + + [Fact] + public void Should_Set_Vertical_Class() + { + var slider = new Slider + { + Orientation = Orientation.Vertical + }; + + Assert.Contains(slider.Classes, ":vertical".Equals); + } + } +} diff --git a/tests/Avalonia.Controls.UnitTests/StackPanelTests.cs b/tests/Avalonia.Controls.UnitTests/StackPanelTests.cs index dca2c5df35..ba2716775a 100644 --- a/tests/Avalonia.Controls.UnitTests/StackPanelTests.cs +++ b/tests/Avalonia.Controls.UnitTests/StackPanelTests.cs @@ -54,11 +54,11 @@ namespace Avalonia.Controls.UnitTests } [Fact] - public void Lays_Out_Children_Vertically_With_Gap() + public void Lays_Out_Children_Vertically_With_Spacing() { var target = new StackPanel { - Gap = 10, + Spacing = 10, Children = { new Border { Height = 20, Width = 120 }, @@ -77,11 +77,11 @@ namespace Avalonia.Controls.UnitTests } [Fact] - public void Lays_Out_Children_Horizontally_With_Gap() + public void Lays_Out_Children_Horizontally_With_Spacing() { var target = new StackPanel { - Gap = 10, + Spacing = 10, Orientation = Orientation.Horizontal, Children = { @@ -150,11 +150,11 @@ namespace Avalonia.Controls.UnitTests [Theory] [InlineData(Orientation.Horizontal)] [InlineData(Orientation.Vertical)] - public void Gap_Not_Added_For_Invisible_Children(Orientation orientation) + public void Spacing_Not_Added_For_Invisible_Children(Orientation orientation) { var targetThreeChildrenOneInvisble = new StackPanel { - Gap = 40, + Spacing = 40, Orientation = orientation, Children = { @@ -165,7 +165,7 @@ namespace Avalonia.Controls.UnitTests }; var targetTwoChildrenNoneInvisible = new StackPanel { - Gap = 40, + Spacing = 40, Orientation = orientation, Children = { diff --git a/tests/Avalonia.Visuals.UnitTests/Rendering/DeferredRendererTests.cs b/tests/Avalonia.Visuals.UnitTests/Rendering/DeferredRendererTests.cs index 7821f60a51..2350a31d5c 100644 --- a/tests/Avalonia.Visuals.UnitTests/Rendering/DeferredRendererTests.cs +++ b/tests/Avalonia.Visuals.UnitTests/Rendering/DeferredRendererTests.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.Linq; using System.Reactive.Subjects; + using Avalonia.Controls; using Avalonia.Data; using Avalonia.Media; @@ -10,8 +11,11 @@ using Avalonia.Rendering; using Avalonia.Rendering.SceneGraph; using Avalonia.Threading; using Avalonia.UnitTests; +using Avalonia.Visuals.Media.Imaging; using Avalonia.VisualTree; + using Moq; + using Xunit; namespace Avalonia.Visuals.UnitTests.Rendering @@ -336,7 +340,7 @@ namespace Avalonia.Visuals.UnitTests.Rendering var context = Mock.Get(target.RenderTarget.CreateDrawingContext(null)); var borderLayer = target.Layers[border].Bitmap; - context.Verify(x => x.DrawImage(borderLayer, 0.5, It.IsAny(), It.IsAny())); + context.Verify(x => x.DrawImage(borderLayer, 0.5, It.IsAny(), It.IsAny(), BitmapInterpolationMode.Default)); } private DeferredRenderer CreateTargetAndRunFrame( diff --git a/tests/Avalonia.Visuals.UnitTests/Rendering/SceneGraph/DrawOperationTests.cs b/tests/Avalonia.Visuals.UnitTests/Rendering/SceneGraph/DrawOperationTests.cs index 8c905dab2f..2060cc7170 100644 --- a/tests/Avalonia.Visuals.UnitTests/Rendering/SceneGraph/DrawOperationTests.cs +++ b/tests/Avalonia.Visuals.UnitTests/Rendering/SceneGraph/DrawOperationTests.cs @@ -1,13 +1,13 @@ -using System; -using Avalonia.Media; +using Avalonia.Media; using Avalonia.Platform; using Avalonia.Rendering.SceneGraph; using Avalonia.Utilities; +using Avalonia.Visuals.Media.Imaging; using Moq; using Xunit; namespace Avalonia.Visuals.UnitTests.Rendering.SceneGraph -{ +{ public class DrawOperationTests { [Fact] @@ -46,7 +46,13 @@ namespace Avalonia.Visuals.UnitTests.Rendering.SceneGraph public void Image_Node_Releases_Reference_To_Bitmap_On_Dispose() { var bitmap = RefCountable.Create(Mock.Of()); - var imageNode = new ImageNode(Matrix.Identity, bitmap, 1, new Rect(1,1,1,1), new Rect(1,1,1,1)); + var imageNode = new ImageNode( + Matrix.Identity, + bitmap, + 1, + new Rect(1, 1, 1, 1), + new Rect(1, 1, 1, 1), + BitmapInterpolationMode.Default); Assert.Equal(2, bitmap.RefCount);