diff --git a/Stubs/Xamarin.Forms.Platform.cs b/Stubs/Xamarin.Forms.Platform.cs index 3e8331b88c5..6941b1964cd 100644 --- a/Stubs/Xamarin.Forms.Platform.cs +++ b/Stubs/Xamarin.Forms.Platform.cs @@ -174,6 +174,23 @@ internal class _RefreshViewRenderer { } [RenderWith(typeof(SwipeViewRenderer))] internal class _SwipeViewRenderer { } + +#if !TIZEN4_0 + [RenderWith(typeof(EllipseRenderer))] + internal class _EllipseRenderer { } + + [RenderWith(typeof(LineRenderer))] + internal class _LineRenderer { } + + [RenderWith(typeof(PolylineRenderer))] + internal class _PolylineRenderer { } + + [RenderWith(typeof(PolygonRenderer))] + internal class _PolygonRenderer { } + + [RenderWith(typeof(RectangleRenderer))] + internal class _RectangleRenderer { } +#endif } diff --git a/Xamarin.Forms.ControlGallery.Android/StaggeredCollectionViewRenderer.cs b/Xamarin.Forms.ControlGallery.Android/StaggeredCollectionViewRenderer.cs index 2b27c4f3a41..58d193450f8 100644 --- a/Xamarin.Forms.ControlGallery.Android/StaggeredCollectionViewRenderer.cs +++ b/Xamarin.Forms.ControlGallery.Android/StaggeredCollectionViewRenderer.cs @@ -1,6 +1,5 @@ using System; using Android.Content; -using Android.Graphics; #if __ANDROID_29__ using AndroidX.AppCompat.Widget; using AndroidX.RecyclerView.Widget; @@ -11,6 +10,7 @@ using Xamarin.Forms.ControlGallery.Android; using Xamarin.Forms.Controls.GalleryPages.CollectionViewGalleries.AlternateLayoutGalleries; using Xamarin.Forms.Platform.Android; +using ARect = Android.Graphics.Rect; using AView = Android.Views.View; [assembly: ExportRenderer(typeof(StaggeredCollectionView), typeof(StaggeredCollectionViewRenderer))] @@ -70,7 +70,7 @@ public SpacingItemDecoration(StaggeredGridItemsLayout itemsLayout) } } - public override void GetItemOffsets(Rect outRect, AView view, RecyclerView parent, RecyclerView.State state) + public override void GetItemOffsets(ARect outRect, AView view, RecyclerView parent, RecyclerView.State state) { base.GetItemOffsets(outRect, view, parent, state); diff --git a/Xamarin.Forms.ControlGallery.WPF/Renderers/Issue6693ControlRenderer.cs b/Xamarin.Forms.ControlGallery.WPF/Renderers/Issue6693ControlRenderer.cs index 124f14cba1b..c5b03607035 100644 --- a/Xamarin.Forms.ControlGallery.WPF/Renderers/Issue6693ControlRenderer.cs +++ b/Xamarin.Forms.ControlGallery.WPF/Renderers/Issue6693ControlRenderer.cs @@ -1,17 +1,11 @@ -using System; -using System.Collections.Generic; -using System.ComponentModel; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using System.Windows; +using System.Windows; using System.Windows.Media; using Xamarin.Forms.ControlGallery.WPF.Renderers; using Xamarin.Forms.Controls.Issues; using Xamarin.Forms.Platform.WPF; -using WColor = System.Windows.Media.Color; +using WRect = System.Windows.Rect; -[assembly:ExportRenderer(typeof(Issue6693Control), typeof(Issue6693ControlRenderer))] +[assembly: ExportRenderer(typeof(Issue6693Control), typeof(Issue6693ControlRenderer))] namespace Xamarin.Forms.ControlGallery.WPF.Renderers { public class Issue6693ControlRenderer:ViewRenderer @@ -35,7 +29,7 @@ public WIssue6693Control() protected override void OnRender(DrawingContext drawingContext) { - drawingContext.DrawRectangle(Brushes.LightGray, new Pen(Brushes.Black, 1), new Rect(0,0,ActualWidth, ActualHeight)); + drawingContext.DrawRectangle(Brushes.LightGray, new Pen(Brushes.Black, 1), new WRect(0,0,ActualWidth, ActualHeight)); var isEnabledText = IsEnabled ? "I'm enabled :)" : "I'm disabled :("; drawingContext.DrawText(new FormattedText(isEnabledText, System.Globalization.CultureInfo.CurrentCulture, diff --git a/Xamarin.Forms.ControlGallery.WindowsUniversal/BrokenNativeControl.cs b/Xamarin.Forms.ControlGallery.WindowsUniversal/BrokenNativeControl.cs index 6d98aefc2b1..b66d86bad62 100644 --- a/Xamarin.Forms.ControlGallery.WindowsUniversal/BrokenNativeControl.cs +++ b/Xamarin.Forms.ControlGallery.WindowsUniversal/BrokenNativeControl.cs @@ -1,10 +1,10 @@ -using Windows.Foundation; using Windows.Graphics.Display; using Windows.UI; using Windows.UI.ViewManagement; using Windows.UI.Xaml; using Windows.UI.Xaml.Controls; using Windows.UI.Xaml.Media; +using WRect = Windows.Foundation.Rect; namespace Xamarin.Forms.ControlGallery.WindowsUniversal { @@ -47,7 +47,7 @@ public string Text protected override Windows.Foundation.Size ArrangeOverride(Windows.Foundation.Size finalSize) { - _textBlock.Arrange(new Rect(0, 0, finalSize.Width, finalSize.Height)); + _textBlock.Arrange(new WRect(0, 0, finalSize.Width, finalSize.Height)); return finalSize; } @@ -57,7 +57,7 @@ protected override Windows.Foundation.Size MeasureOverride (Windows.Foundation. _textBlock.Measure (availableSize); // This deliberately does something wrong so we can demo fixing it - Rect bounds = ApplicationView.GetForCurrentView ().VisibleBounds; + WRect bounds = ApplicationView.GetForCurrentView ().VisibleBounds; double scaleFactor = DisplayInformation.GetForCurrentView ().RawPixelsPerViewPixel; var size = new Size (bounds.Width * scaleFactor, bounds.Height * scaleFactor); diff --git a/Xamarin.Forms.ControlGallery.WindowsUniversal/CustomRenderers.cs b/Xamarin.Forms.ControlGallery.WindowsUniversal/CustomRenderers.cs index 0cc317d10b8..152a42d27ff 100644 --- a/Xamarin.Forms.ControlGallery.WindowsUniversal/CustomRenderers.cs +++ b/Xamarin.Forms.ControlGallery.WindowsUniversal/CustomRenderers.cs @@ -5,10 +5,11 @@ using Windows.UI.Xaml.Controls; using Windows.UI.Xaml.Input; using Windows.UI.Xaml.Media; -using Windows.UI.Xaml.Shapes; using Xamarin.Forms.ControlGallery.WindowsUniversal; using Xamarin.Forms.Controls.Issues; using Xamarin.Forms.Platform.UWP; +using WEllipse = Windows.UI.Xaml.Shapes.Ellipse; +using WShape = Windows.UI.Xaml.Shapes.Shape; [assembly: ExportRenderer(typeof(Xamarin.Forms.Controls.Issues.Bugzilla42602.TextBoxView), typeof(Xamarin.Forms.ControlGallery.WindowsUniversal.TextBoxViewRenderer))] [assembly: ExportRenderer(typeof(Issue1683.EntryKeyboardFlags), typeof(EntryRendererKeyboardFlags))] @@ -143,7 +144,7 @@ protected override void OnElementChanged(ElementChangedEventArgs e) Children.Add(m_Canvas); //ellipse - Shape ellipse = new Ellipse() + WShape ellipse = new WEllipse() { Width = 100, Height = 100, diff --git a/Xamarin.Forms.ControlGallery.WindowsUniversal/MainPage.xaml.cs b/Xamarin.Forms.ControlGallery.WindowsUniversal/MainPage.xaml.cs index 63c56eb4f20..c844ac5fd63 100644 --- a/Xamarin.Forms.ControlGallery.WindowsUniversal/MainPage.xaml.cs +++ b/Xamarin.Forms.ControlGallery.WindowsUniversal/MainPage.xaml.cs @@ -15,7 +15,7 @@ using Xamarin.Forms.ControlGallery.WindowsUniversal; using Xamarin.Forms.Controls; using Xamarin.Forms.Platform.UWP; - +using WRect = Windows.Foundation.Rect; namespace Xamarin.Forms.ControlGallery.WindowsUniversal { @@ -119,17 +119,17 @@ void AddNativeControls(NestedNativeControlGalleryPage page) // The broken control always tries to size itself to the screen width // So figure that out and we'll know how far off it's laying itself out - Rect bounds = ApplicationView.GetForCurrentView().VisibleBounds; + WRect bounds = ApplicationView.GetForCurrentView().VisibleBounds; double scaleFactor = DisplayInformation.GetForCurrentView().RawPixelsPerViewPixel; var screenWidth = new Size(bounds.Width * scaleFactor, bounds.Height * scaleFactor); // We can re-center it by offsetting it during the Arrange call double diff = Math.Abs(screenWidth.Width - finalSize.Width) / -2; - frameworkElement.Arrange(new Rect(diff, 0, finalSize.Width - diff, finalSize.Height)); + frameworkElement.Arrange(new WRect(diff, 0, finalSize.Width - diff, finalSize.Height)); // Arranging the control to the left will make it show up past the edge of the stack layout // We can fix that by clipping it manually - var clip = new RectangleGeometry { Rect = new Rect(-diff, 0, finalSize.Width, finalSize.Height) }; + var clip = new RectangleGeometry { Rect = new WRect(-diff, 0, finalSize.Width, finalSize.Height) }; frameworkElement.Clip = clip; return finalSize; diff --git a/Xamarin.Forms.Controls/CoreGallery.cs b/Xamarin.Forms.Controls/CoreGallery.cs index d6cd97e7944..d9a384ddc0e 100644 --- a/Xamarin.Forms.Controls/CoreGallery.cs +++ b/Xamarin.Forms.Controls/CoreGallery.cs @@ -18,6 +18,7 @@ using Xamarin.Forms.Controls.GalleryPages.AppThemeGalleries; using Xamarin.Forms.Controls.GalleryPages.ExpanderGalleries; using Xamarin.Forms.Controls.GalleryPages.RadioButtonGalleries; +using Xamarin.Forms.Controls.GalleryPages.ShapesGalleries; namespace Xamarin.Forms.Controls { @@ -360,6 +361,7 @@ public override string ToString() new GalleryPageFactory(() => new ScrollGallery(ScrollOrientation.Horizontal), "ScrollView Gallery Horizontal"), new GalleryPageFactory(() => new ScrollGallery(ScrollOrientation.Both), "ScrollView Gallery 2D"), new GalleryPageFactory(() => new SearchBarCoreGalleryPage(), "SearchBar Gallery"), + new GalleryPageFactory(() => new ShapesGallery(), "Shapes Gallery"), new GalleryPageFactory(() => new SliderCoreGalleryPage(), "Slider Gallery"), new GalleryPageFactory(() => new StepperCoreGalleryPage(), "Stepper Gallery"), new GalleryPageFactory(() => new SwitchCoreGalleryPage(), "Switch Gallery"), diff --git a/Xamarin.Forms.Controls/GalleryPages/MapElementsGallery.xaml.cs b/Xamarin.Forms.Controls/GalleryPages/MapElementsGallery.xaml.cs index bc1acfe1324..3700d1efbaa 100644 --- a/Xamarin.Forms.Controls/GalleryPages/MapElementsGallery.xaml.cs +++ b/Xamarin.Forms.Controls/GalleryPages/MapElementsGallery.xaml.cs @@ -1,12 +1,8 @@ using System; -using System.Collections.Generic; using System.Linq; -using System.Text; -using System.Threading.Tasks; - -using Xamarin.Forms; -using Xamarin.Forms.Maps; using Xamarin.Forms.Xaml; +using Xamarin.Forms.Maps; +using Map = Xamarin.Forms.Maps; namespace Xamarin.Forms.Controls.GalleryPages { @@ -22,9 +18,9 @@ enum SelectedElementType SelectedElementType _selectedType; - Polyline _polyline; - Polygon _polygon; - Circle _circle; + Map.Polyline _polyline; + Map.Polygon _polygon; + Map.Circle _circle; Random _random = new Random(); @@ -37,7 +33,7 @@ public MapElementsGallery() new Position(39.828152, -98.569817), Distance.FromMiles(1681))); - _polyline = new Polyline + _polyline = new Maps.Polyline { Geopath = { @@ -47,7 +43,7 @@ public MapElementsGallery() } }; - _polygon = new Polygon + _polygon = new Maps.Polygon { StrokeColor = Color.FromHex("#002868"), FillColor = Color.FromHex("#88BF0A30"), @@ -108,10 +104,10 @@ void AddClicked(object sender, EventArgs e) switch (_selectedType) { case SelectedElementType.Polyline: - Map.MapElements.Add(_polyline = new Polyline()); + Map.MapElements.Add(_polyline = new Maps.Polyline()); break; case SelectedElementType.Polygon: - Map.MapElements.Add(_polygon = new Polygon()); + Map.MapElements.Add(_polygon = new Maps.Polygon()); break; case SelectedElementType.Circle: Map.MapElements.Add(_circle = new Circle()); @@ -125,18 +121,18 @@ void RemoveClicked(object sender, EventArgs e) { case SelectedElementType.Polyline: Map.MapElements.Remove(_polyline); - _polyline = Map.MapElements.OfType().LastOrDefault(); + _polyline = Map.MapElements.OfType().LastOrDefault(); if (_polyline == null) - Map.MapElements.Add(_polyline = new Polyline()); + Map.MapElements.Add(_polyline = new Maps.Polyline()); break; case SelectedElementType.Polygon: Map.MapElements.Remove(_polygon); - _polygon = Map.MapElements.OfType().LastOrDefault(); + _polygon = Map.MapElements.OfType().LastOrDefault(); if (_polygon == null) - Map.MapElements.Add(_polygon = new Polygon()); + Map.MapElements.Add(_polygon = new Maps.Polygon()); break; case SelectedElementType.Circle: diff --git a/Xamarin.Forms.Controls/GalleryPages/ShapesGalleries/AutoSizeShapesGallery.xaml b/Xamarin.Forms.Controls/GalleryPages/ShapesGalleries/AutoSizeShapesGallery.xaml new file mode 100644 index 00000000000..7156726613e --- /dev/null +++ b/Xamarin.Forms.Controls/GalleryPages/ShapesGalleries/AutoSizeShapesGallery.xaml @@ -0,0 +1,32 @@ + + + + + + + + + + + diff --git a/Xamarin.Forms.Controls/GalleryPages/ShapesGalleries/AutoSizeShapesGallery.xaml.cs b/Xamarin.Forms.Controls/GalleryPages/ShapesGalleries/AutoSizeShapesGallery.xaml.cs new file mode 100644 index 00000000000..cd3bb6f14ad --- /dev/null +++ b/Xamarin.Forms.Controls/GalleryPages/ShapesGalleries/AutoSizeShapesGallery.xaml.cs @@ -0,0 +1,10 @@ +namespace Xamarin.Forms.Controls.GalleryPages.ShapesGalleries +{ + public partial class AutoSizeShapesGallery : ContentPage + { + public AutoSizeShapesGallery() + { + InitializeComponent(); + } + } +} \ No newline at end of file diff --git a/Xamarin.Forms.Controls/GalleryPages/ShapesGalleries/EllipseGallery.xaml b/Xamarin.Forms.Controls/GalleryPages/ShapesGalleries/EllipseGallery.xaml new file mode 100644 index 00000000000..e3ea3904ea7 --- /dev/null +++ b/Xamarin.Forms.Controls/GalleryPages/ShapesGalleries/EllipseGallery.xaml @@ -0,0 +1,59 @@ + + + + + + + + + + + + + + + + diff --git a/Xamarin.Forms.Controls/GalleryPages/ShapesGalleries/EllipseGallery.xaml.cs b/Xamarin.Forms.Controls/GalleryPages/ShapesGalleries/EllipseGallery.xaml.cs new file mode 100644 index 00000000000..007bd6c1bf9 --- /dev/null +++ b/Xamarin.Forms.Controls/GalleryPages/ShapesGalleries/EllipseGallery.xaml.cs @@ -0,0 +1,13 @@ +using Xamarin.Forms.Internals; + +namespace Xamarin.Forms.Controls.GalleryPages.ShapesGalleries +{ + [Preserve(AllMembers = true)] + public partial class EllipseGallery : ContentPage + { + public EllipseGallery() + { + InitializeComponent(); + } + } +} diff --git a/Xamarin.Forms.Controls/GalleryPages/ShapesGalleries/LineCapGallery.xaml b/Xamarin.Forms.Controls/GalleryPages/ShapesGalleries/LineCapGallery.xaml new file mode 100644 index 00000000000..97c40019c53 --- /dev/null +++ b/Xamarin.Forms.Controls/GalleryPages/ShapesGalleries/LineCapGallery.xaml @@ -0,0 +1,46 @@ + + + + + + + + + + + + + + diff --git a/Xamarin.Forms.Controls/GalleryPages/ShapesGalleries/LineCapGallery.xaml.cs b/Xamarin.Forms.Controls/GalleryPages/ShapesGalleries/LineCapGallery.xaml.cs new file mode 100644 index 00000000000..8ce6df00349 --- /dev/null +++ b/Xamarin.Forms.Controls/GalleryPages/ShapesGalleries/LineCapGallery.xaml.cs @@ -0,0 +1,10 @@ +namespace Xamarin.Forms.Controls.GalleryPages.ShapesGalleries +{ + public partial class LineCapGallery : ContentPage + { + public LineCapGallery() + { + InitializeComponent(); + } + } +} \ No newline at end of file diff --git a/Xamarin.Forms.Controls/GalleryPages/ShapesGalleries/LineGallery.xaml b/Xamarin.Forms.Controls/GalleryPages/ShapesGalleries/LineGallery.xaml new file mode 100644 index 00000000000..2f5a00c7141 --- /dev/null +++ b/Xamarin.Forms.Controls/GalleryPages/ShapesGalleries/LineGallery.xaml @@ -0,0 +1,39 @@ + + + + + + + diff --git a/Xamarin.Forms.Controls/GalleryPages/ShapesGalleries/LineGallery.xaml.cs b/Xamarin.Forms.Controls/GalleryPages/ShapesGalleries/LineGallery.xaml.cs new file mode 100644 index 00000000000..b37796366f7 --- /dev/null +++ b/Xamarin.Forms.Controls/GalleryPages/ShapesGalleries/LineGallery.xaml.cs @@ -0,0 +1,13 @@ +using Xamarin.Forms.Internals; + +namespace Xamarin.Forms.Controls.GalleryPages.ShapesGalleries +{ + [Preserve(AllMembers = true)] + public partial class LineGallery : ContentPage + { + public LineGallery() + { + InitializeComponent(); + } + } +} diff --git a/Xamarin.Forms.Controls/GalleryPages/ShapesGalleries/LineJoinGallery.xaml b/Xamarin.Forms.Controls/GalleryPages/ShapesGalleries/LineJoinGallery.xaml new file mode 100644 index 00000000000..90047bd93bb --- /dev/null +++ b/Xamarin.Forms.Controls/GalleryPages/ShapesGalleries/LineJoinGallery.xaml @@ -0,0 +1,43 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Xamarin.Forms.Controls/GalleryPages/ShapesGalleries/LineJoinGallery.xaml.cs b/Xamarin.Forms.Controls/GalleryPages/ShapesGalleries/LineJoinGallery.xaml.cs new file mode 100644 index 00000000000..8aedd63c7d1 --- /dev/null +++ b/Xamarin.Forms.Controls/GalleryPages/ShapesGalleries/LineJoinGallery.xaml.cs @@ -0,0 +1,10 @@ +namespace Xamarin.Forms.Controls.GalleryPages.ShapesGalleries +{ + public partial class LineJoinGallery : ContentPage + { + public LineJoinGallery() + { + InitializeComponent(); + } + } +} \ No newline at end of file diff --git a/Xamarin.Forms.Controls/GalleryPages/ShapesGalleries/PolygonGallery.xaml b/Xamarin.Forms.Controls/GalleryPages/ShapesGalleries/PolygonGallery.xaml new file mode 100644 index 00000000000..52410a709f0 --- /dev/null +++ b/Xamarin.Forms.Controls/GalleryPages/ShapesGalleries/PolygonGallery.xaml @@ -0,0 +1,75 @@ + + + + + + + + + + + + + + + + + + diff --git a/Xamarin.Forms.Controls/GalleryPages/ShapesGalleries/PolygonGallery.xaml.cs b/Xamarin.Forms.Controls/GalleryPages/ShapesGalleries/PolygonGallery.xaml.cs new file mode 100644 index 00000000000..909f29e65dd --- /dev/null +++ b/Xamarin.Forms.Controls/GalleryPages/ShapesGalleries/PolygonGallery.xaml.cs @@ -0,0 +1,13 @@ +using Xamarin.Forms.Internals; + +namespace Xamarin.Forms.Controls.GalleryPages.ShapesGalleries +{ + [Preserve(AllMembers = true)] + public partial class PolygonGallery : ContentPage + { + public PolygonGallery() + { + InitializeComponent(); + } + } +} diff --git a/Xamarin.Forms.Controls/GalleryPages/ShapesGalleries/PolylineGallery.xaml b/Xamarin.Forms.Controls/GalleryPages/ShapesGalleries/PolylineGallery.xaml new file mode 100644 index 00000000000..923d8c9e939 --- /dev/null +++ b/Xamarin.Forms.Controls/GalleryPages/ShapesGalleries/PolylineGallery.xaml @@ -0,0 +1,29 @@ + + + + + + + diff --git a/Xamarin.Forms.Controls/GalleryPages/ShapesGalleries/PolylineGallery.xaml.cs b/Xamarin.Forms.Controls/GalleryPages/ShapesGalleries/PolylineGallery.xaml.cs new file mode 100644 index 00000000000..be9186e615e --- /dev/null +++ b/Xamarin.Forms.Controls/GalleryPages/ShapesGalleries/PolylineGallery.xaml.cs @@ -0,0 +1,13 @@ +using Xamarin.Forms.Internals; + +namespace Xamarin.Forms.Controls.GalleryPages.ShapesGalleries +{ + [Preserve(AllMembers = true)] + public partial class PolylineGallery : ContentPage + { + public PolylineGallery() + { + InitializeComponent(); + } + } +} diff --git a/Xamarin.Forms.Controls/GalleryPages/ShapesGalleries/RectangleGallery.xaml b/Xamarin.Forms.Controls/GalleryPages/ShapesGalleries/RectangleGallery.xaml new file mode 100644 index 00000000000..83ac8130701 --- /dev/null +++ b/Xamarin.Forms.Controls/GalleryPages/ShapesGalleries/RectangleGallery.xaml @@ -0,0 +1,67 @@ + + + + + + + + + + + + + + + + diff --git a/Xamarin.Forms.Controls/GalleryPages/ShapesGalleries/RectangleGallery.xaml.cs b/Xamarin.Forms.Controls/GalleryPages/ShapesGalleries/RectangleGallery.xaml.cs new file mode 100644 index 00000000000..14318a7d0dd --- /dev/null +++ b/Xamarin.Forms.Controls/GalleryPages/ShapesGalleries/RectangleGallery.xaml.cs @@ -0,0 +1,13 @@ +using Xamarin.Forms.Internals; + +namespace Xamarin.Forms.Controls.GalleryPages.ShapesGalleries +{ + [Preserve(AllMembers = true)] + public partial class RectangleGallery : ContentPage + { + public RectangleGallery() + { + InitializeComponent(); + } + } +} diff --git a/Xamarin.Forms.Controls/GalleryPages/ShapesGalleries/ShapesGallery.cs b/Xamarin.Forms.Controls/GalleryPages/ShapesGalleries/ShapesGallery.cs new file mode 100644 index 00000000000..fbd380967eb --- /dev/null +++ b/Xamarin.Forms.Controls/GalleryPages/ShapesGalleries/ShapesGallery.cs @@ -0,0 +1,47 @@ +using Xamarin.Forms.Internals; + +namespace Xamarin.Forms.Controls.GalleryPages.ShapesGalleries +{ + [Preserve(AllMembers = true)] + public class ShapesGallery : ContentPage + { + public ShapesGallery() + { + Title = "Shapes Gallery"; + + var button = new Button + { + Text = "Enable Shapes", + AutomationId = "EnableShapes" + }; + button.Clicked += ButtonClicked; + + Content = new StackLayout + { + Children = + { + button, + GalleryBuilder.NavButton("Ellipse Gallery", () => new EllipseGallery(), Navigation), + GalleryBuilder.NavButton("Line Gallery", () => new LineGallery(), Navigation), + GalleryBuilder.NavButton("Polygon Gallery", () => new PolygonGallery(), Navigation), + GalleryBuilder.NavButton("Polyline Gallery", () => new PolylineGallery(), Navigation), + GalleryBuilder.NavButton("Rectangle Gallery", () => new RectangleGallery(), Navigation), + GalleryBuilder.NavButton("LineCap Gallery", () => new LineCapGallery(), Navigation), + GalleryBuilder.NavButton("LineJoin Gallery", () => new LineJoinGallery(), Navigation), + GalleryBuilder.NavButton("AutoSize Shapes Gallery", () => new AutoSizeShapesGallery(), Navigation) + } + }; + } + + void ButtonClicked(object sender, System.EventArgs e) + { + var button = sender as Button; + + button.Text = "Shapes Enabled!"; + button.TextColor = Color.Black; + button.IsEnabled = false; + + Device.SetFlags(new[] { ExperimentalFlags.ShapesExperimental }); + } + } +} \ No newline at end of file diff --git a/Xamarin.Forms.Core.UnitTests/LineTests.cs b/Xamarin.Forms.Core.UnitTests/LineTests.cs new file mode 100644 index 00000000000..cac5000c1c1 --- /dev/null +++ b/Xamarin.Forms.Core.UnitTests/LineTests.cs @@ -0,0 +1,44 @@ +using NUnit.Framework; +using Xamarin.Forms.Shapes; + +namespace Xamarin.Forms.Core.UnitTests +{ + public class LineTests : BaseTestFixture + { + [SetUp] + public override void Setup() + { + base.Setup(); + + Device.SetFlags(new[] { ExperimentalFlags.ShapesExperimental }); + } + + [Test] + public void XPointCanBeSetFromStyle() + { + var line = new Line(); + + Assert.AreEqual(0.0, line.X1); + line.SetValue(Line.X1Property, 1.0, true); + Assert.AreEqual(1.0, line.X1); + + Assert.AreEqual(0.0, line.X2); + line.SetValue(Line.X2Property, 100.0, true); + Assert.AreEqual(100.0, line.X2); + } + + [Test] + public void YPointCanBeSetFromStyle() + { + var line = new Line(); + + Assert.AreEqual(0.0, line.Y1); + line.SetValue(Line.Y1Property, 1.0, true); + Assert.AreEqual(1.0, line.Y1); + + Assert.AreEqual(0.0, line.Y2); + line.SetValue(Line.Y2Property, 10.0, true); + Assert.AreEqual(10.0, line.Y2); + } + } +} \ No newline at end of file diff --git a/Xamarin.Forms.Core.UnitTests/Markup/DefaultBindablePropertiesTests.cs b/Xamarin.Forms.Core.UnitTests/Markup/DefaultBindablePropertiesTests.cs index 5ba3ee99340..655724cf48d 100644 --- a/Xamarin.Forms.Core.UnitTests/Markup/DefaultBindablePropertiesTests.cs +++ b/Xamarin.Forms.Core.UnitTests/Markup/DefaultBindablePropertiesTests.cs @@ -7,6 +7,7 @@ namespace Xamarin.Forms.Markup.UnitTests { + using Xamarin.Forms.Shapes; using XamarinFormsMarkupUnitTestsDefaultBindablePropertiesViews; [TestFixture(true)] @@ -77,7 +78,14 @@ public void AllBindableElementsInCoreHaveDefaultBindablePropertyOrAreExcluded() { typeof(ShellItem), tbd }, { typeof(ShellSection), tbd }, { typeof(Tab), tbd }, - { typeof(TabBar), tbd } + { typeof(TabBar), tbd }, + + { typeof(Ellipse), tbd }, + { typeof(Line), tbd }, + { typeof(Polygon), tbd }, + { typeof(Polyline), tbd }, + { typeof(Rectangle), tbd }, + { typeof(Shape), tbd } }; var failMessage = new StringBuilder(); diff --git a/Xamarin.Forms.Core.UnitTests/PolygonTests.cs b/Xamarin.Forms.Core.UnitTests/PolygonTests.cs new file mode 100644 index 00000000000..9343627bf1f --- /dev/null +++ b/Xamarin.Forms.Core.UnitTests/PolygonTests.cs @@ -0,0 +1,35 @@ +using NUnit.Framework; +using Xamarin.Forms.Shapes; + +namespace Xamarin.Forms.Core.UnitTests +{ + public class PolygonTests : BaseTestFixture + { + PointCollectionConverter _pointCollectionConverter; + + [SetUp] + public override void Setup() + { + base.Setup(); + + Device.SetFlags(new[] { ExperimentalFlags.ShapesExperimental }); + + _pointCollectionConverter = new PointCollectionConverter(); + } + + [Test] + public void CreatePolygonFromStringPointCollectionTest() + { + PointCollection points = _pointCollectionConverter.ConvertFromInvariantString("0 48, 0 144, 96 150, 100 0, 192 0, 192 96, 50 96, 48 192, 150 200 144 48") as PointCollection; + + Polygon polygon = new Polygon + { + Points = points + }; + + Assert.IsNotNull(points); + Assert.IsNotNull(polygon); + Assert.AreEqual(10, points.Count); + } + } +} \ No newline at end of file diff --git a/Xamarin.Forms.Core.UnitTests/PolylineTests.cs b/Xamarin.Forms.Core.UnitTests/PolylineTests.cs new file mode 100644 index 00000000000..de6f3fc012a --- /dev/null +++ b/Xamarin.Forms.Core.UnitTests/PolylineTests.cs @@ -0,0 +1,35 @@ +using NUnit.Framework; +using Xamarin.Forms.Shapes; + +namespace Xamarin.Forms.Core.UnitTests +{ + public class PolylineTests : BaseTestFixture + { + PointCollectionConverter _pointCollectionConverter; + + [SetUp] + public override void Setup() + { + base.Setup(); + + Device.SetFlags(new[] { ExperimentalFlags.ShapesExperimental }); + + _pointCollectionConverter = new PointCollectionConverter(); + } + + [Test] + public void CreatePolylineFromStringPointCollectionTest() + { + PointCollection points = _pointCollectionConverter.ConvertFromInvariantString("0 48, 0 144, 96 150, 100 0, 192 0, 192 96, 50 96, 48 192, 150 200 144 48") as PointCollection; + + Polyline polyline = new Polyline + { + Points = points + }; + + Assert.IsNotNull(points); + Assert.IsNotNull(polyline); + Assert.AreEqual(10, points.Count); + } + } +} \ No newline at end of file diff --git a/Xamarin.Forms.Core.UnitTests/RectangleTests.cs b/Xamarin.Forms.Core.UnitTests/RectangleTests.cs new file mode 100644 index 00000000000..5e37dce7a0d --- /dev/null +++ b/Xamarin.Forms.Core.UnitTests/RectangleTests.cs @@ -0,0 +1,31 @@ +using NUnit.Framework; +using Rect = Xamarin.Forms.Shapes.Rectangle; + +namespace Xamarin.Forms.Core.UnitTests +{ + [TestFixture] + public class RectTests : BaseTestFixture + { + [SetUp] + public override void Setup() + { + base.Setup(); + + Device.SetFlags(new[] { ExperimentalFlags.ShapesExperimental }); + } + + [Test] + public void RadiusCanBeSetFromStyle() + { + var rectangle = new Rect(); + + Assert.AreEqual(0.0, rectangle.RadiusX); + rectangle.SetValue(Rect.RadiusXProperty, 10.0, true); + Assert.AreEqual(10.0, rectangle.RadiusX); + + Assert.AreEqual(0.0, rectangle.RadiusY); + rectangle.SetValue(Rect.RadiusYProperty, 10.0, true); + Assert.AreEqual(10.0, rectangle.RadiusY); + } + } +} \ No newline at end of file diff --git a/Xamarin.Forms.Core.UnitTests/Xamarin.Forms.Core.UnitTests.csproj b/Xamarin.Forms.Core.UnitTests/Xamarin.Forms.Core.UnitTests.csproj index 0316f616f32..5f7dceadb18 100644 --- a/Xamarin.Forms.Core.UnitTests/Xamarin.Forms.Core.UnitTests.csproj +++ b/Xamarin.Forms.Core.UnitTests/Xamarin.Forms.Core.UnitTests.csproj @@ -241,6 +241,10 @@ + + + + diff --git a/Xamarin.Forms.Core/DoubleCollection.cs b/Xamarin.Forms.Core/DoubleCollection.cs new file mode 100644 index 00000000000..b054e63c058 --- /dev/null +++ b/Xamarin.Forms.Core/DoubleCollection.cs @@ -0,0 +1,10 @@ +using System.Collections.ObjectModel; + +namespace Xamarin.Forms +{ + [TypeConverter(typeof(DoubleCollectionConverter))] + public sealed class DoubleCollection : ObservableCollection + { + + } +} \ No newline at end of file diff --git a/Xamarin.Forms.Core/DoubleCollectionConverter.cs b/Xamarin.Forms.Core/DoubleCollectionConverter.cs new file mode 100644 index 00000000000..31c0131067d --- /dev/null +++ b/Xamarin.Forms.Core/DoubleCollectionConverter.cs @@ -0,0 +1,24 @@ +using System; +using System.Globalization; + +namespace Xamarin.Forms +{ + public class DoubleCollectionConverter : TypeConverter + { + public override object ConvertFromInvariantString(string value) + { + string[] doubles = value.Split(new char[] { ' ', ',' }, StringSplitOptions.RemoveEmptyEntries); + var doubleCollection = new DoubleCollection(); + + foreach (string d in doubles) + { + if (double.TryParse(d, NumberStyles.Number, CultureInfo.InvariantCulture, out double number)) + doubleCollection.Add(number); + else + throw new InvalidOperationException(string.Format("Cannot convert \"{0}\" into {1}", d, typeof(double))); + } + + return doubleCollection; + } + } +} \ No newline at end of file diff --git a/Xamarin.Forms.Core/ExperimentalFlags.cs b/Xamarin.Forms.Core/ExperimentalFlags.cs index d68bd5ae1a1..6037df3383e 100644 --- a/Xamarin.Forms.Core/ExperimentalFlags.cs +++ b/Xamarin.Forms.Core/ExperimentalFlags.cs @@ -19,6 +19,7 @@ internal static class ExperimentalFlags internal const string AppThemeExperimental = "AppTheme_Experimental"; internal const string ExpanderExperimental = "Expander_Experimental"; internal const string RadioButtonExperimental = "RadioButton_Experimental"; + internal const string ShapesExperimental = "Shapes_Experimental"; [EditorBrowsable(EditorBrowsableState.Never)] public static void VerifyFlagEnabled( diff --git a/Xamarin.Forms.Core/FillRule.cs b/Xamarin.Forms.Core/FillRule.cs new file mode 100644 index 00000000000..f120bc5c40f --- /dev/null +++ b/Xamarin.Forms.Core/FillRule.cs @@ -0,0 +1,8 @@ +namespace Xamarin.Forms +{ + public enum FillRule + { + EvenOdd, + Nonzero + } +} \ No newline at end of file diff --git a/Xamarin.Forms.Core/PenLineCap.cs b/Xamarin.Forms.Core/PenLineCap.cs new file mode 100644 index 00000000000..461e38ae7eb --- /dev/null +++ b/Xamarin.Forms.Core/PenLineCap.cs @@ -0,0 +1,9 @@ +namespace Xamarin.Forms +{ + public enum PenLineCap + { + Flat, + Square, + Round + } +} diff --git a/Xamarin.Forms.Core/PenLineJoin.cs b/Xamarin.Forms.Core/PenLineJoin.cs new file mode 100644 index 00000000000..ba909071017 --- /dev/null +++ b/Xamarin.Forms.Core/PenLineJoin.cs @@ -0,0 +1,9 @@ +namespace Xamarin.Forms +{ + public enum PenLineJoin + { + Miter, + Bevel, + Round + } +} \ No newline at end of file diff --git a/Xamarin.Forms.Core/Properties/AssemblyInfo.cs b/Xamarin.Forms.Core/Properties/AssemblyInfo.cs index 4c184f301e0..983dd4f00fc 100644 --- a/Xamarin.Forms.Core/Properties/AssemblyInfo.cs +++ b/Xamarin.Forms.Core/Properties/AssemblyInfo.cs @@ -36,7 +36,9 @@ [assembly: InternalsVisibleTo("Xamarin.Forms.DualScreen.UnitTests")] [assembly: Preserve] +[assembly: XmlnsDefinition("http://xamarin.com/schemas/2014/forms", "Xamarin.Forms.Shapes")] [assembly: XmlnsDefinition("http://xamarin.com/schemas/2014/forms", "Xamarin.Forms")] +[assembly: XmlnsDefinition("http://xamarin.com/schemas/2014/forms/design", "Xamarin.Forms.Shapes")] [assembly: XmlnsDefinition("http://xamarin.com/schemas/2014/forms/design", "Xamarin.Forms")] [assembly: XmlnsPrefix("http://xamarin.com/schemas/2014/forms", "xf")] [assembly: XmlnsPrefix("http://xamarin.com/schemas/2014/forms/design", "d")] diff --git a/Xamarin.Forms.Core/Shapes/Ellipse.cs b/Xamarin.Forms.Core/Shapes/Ellipse.cs new file mode 100644 index 00000000000..71bf5559e20 --- /dev/null +++ b/Xamarin.Forms.Core/Shapes/Ellipse.cs @@ -0,0 +1,13 @@ +using Xamarin.Forms.Platform; + +namespace Xamarin.Forms.Shapes +{ + [RenderWith(typeof(_EllipseRenderer))] + public sealed class Ellipse : Shape + { + public Ellipse() + { + Aspect = Stretch.Fill; + } + } +} \ No newline at end of file diff --git a/Xamarin.Forms.Core/Shapes/Line.cs b/Xamarin.Forms.Core/Shapes/Line.cs new file mode 100644 index 00000000000..ba025bdeeb8 --- /dev/null +++ b/Xamarin.Forms.Core/Shapes/Line.cs @@ -0,0 +1,44 @@ +using Xamarin.Forms.Platform; + +namespace Xamarin.Forms.Shapes +{ + [RenderWith(typeof(_LineRenderer))] + public sealed class Line : Shape + { + public static readonly BindableProperty X1Property = + BindableProperty.Create(nameof(X1), typeof(double), typeof(Line), 0.0d); + + public static readonly BindableProperty Y1Property = + BindableProperty.Create(nameof(Y1), typeof(double), typeof(Line), 0.0d); + + public static readonly BindableProperty X2Property = + BindableProperty.Create(nameof(X2), typeof(double), typeof(Line), 0.0d); + + public static readonly BindableProperty Y2Property = + BindableProperty.Create(nameof(Y2), typeof(double), typeof(Line), 0.0d); + + public double X1 + { + set { SetValue(X1Property, value); } + get { return (double)GetValue(X1Property); } + } + + public double Y1 + { + set { SetValue(Y1Property, value); } + get { return (double)GetValue(Y1Property); } + } + + public double X2 + { + set { SetValue(X2Property, value); } + get { return (double)GetValue(X2Property); } + } + + public double Y2 + { + set { SetValue(Y2Property, value); } + get { return (double)GetValue(Y2Property); } + } + } +} \ No newline at end of file diff --git a/Xamarin.Forms.Core/Shapes/PointCollection.cs b/Xamarin.Forms.Core/Shapes/PointCollection.cs new file mode 100644 index 00000000000..86f1d16cdca --- /dev/null +++ b/Xamarin.Forms.Core/Shapes/PointCollection.cs @@ -0,0 +1,10 @@ +using System.Collections.ObjectModel; + +namespace Xamarin.Forms.Shapes +{ + [TypeConverter(typeof(PointCollectionConverter))] + public sealed class PointCollection : ObservableCollection + { + + } +} \ No newline at end of file diff --git a/Xamarin.Forms.Core/Shapes/PointCollectionConverter.cs b/Xamarin.Forms.Core/Shapes/PointCollectionConverter.cs new file mode 100644 index 00000000000..c65a01a116e --- /dev/null +++ b/Xamarin.Forms.Core/Shapes/PointCollectionConverter.cs @@ -0,0 +1,44 @@ +using System; +using System.Globalization; + +namespace Xamarin.Forms.Shapes +{ + public class PointCollectionConverter : TypeConverter + { + public override object ConvertFromInvariantString(string value) + { + string[] points = value.Split(new char[] { ' ', ',' }); + var pointCollection = new PointCollection(); + double x = 0; + bool hasX = false; + + foreach (string point in points) + { + if (string.IsNullOrWhiteSpace(point)) + continue; + + if (double.TryParse(point, NumberStyles.Number, CultureInfo.InvariantCulture, out double number)) + { + if (!hasX) + { + x = number; + hasX = true; + } + else + { + pointCollection.Add(new Point(x, number)); + hasX = false; + } + } + else + throw new InvalidOperationException(string.Format("Cannot convert \"{0}\" into {1}", point, typeof(double))); + } + + if (hasX) + throw new InvalidOperationException(string.Format("Cannot convert string into PointCollection")); + + return pointCollection; + + } + } +} \ No newline at end of file diff --git a/Xamarin.Forms.Core/Shapes/Polygon.cs b/Xamarin.Forms.Core/Shapes/Polygon.cs new file mode 100644 index 00000000000..2d7d2cc8ad1 --- /dev/null +++ b/Xamarin.Forms.Core/Shapes/Polygon.cs @@ -0,0 +1,27 @@ +using Xamarin.Forms.Platform; + +namespace Xamarin.Forms.Shapes +{ + [RenderWith(typeof(_PolygonRenderer))] + public sealed class Polygon : Shape + { + public static readonly BindableProperty PointsProperty = + BindableProperty.Create(nameof(Points), typeof(PointCollection), typeof(Polygon), null, defaultValueCreator: bindable => new PointCollection()); + + public static readonly BindableProperty FillRuleProperty = + BindableProperty.Create(nameof(FillRule), typeof(FillRule), typeof(Polygon), FillRule.EvenOdd); + + public PointCollection Points + { + set { SetValue(PointsProperty, value); } + get { return (PointCollection)GetValue(PointsProperty); } + } + + public FillRule FillRule + { + set { SetValue(FillRuleProperty, value); } + get { return (FillRule)GetValue(FillRuleProperty); } + + } + } +} \ No newline at end of file diff --git a/Xamarin.Forms.Core/Shapes/Polyline.cs b/Xamarin.Forms.Core/Shapes/Polyline.cs new file mode 100644 index 00000000000..ed7152ef2a9 --- /dev/null +++ b/Xamarin.Forms.Core/Shapes/Polyline.cs @@ -0,0 +1,26 @@ +using Xamarin.Forms.Platform; + +namespace Xamarin.Forms.Shapes +{ + [RenderWith(typeof(_PolylineRenderer))] + public sealed class Polyline : Shape + { + public static readonly BindableProperty PointsProperty = + BindableProperty.Create(nameof(Points), typeof(PointCollection), typeof(Polyline), null, defaultValueCreator: bindable => new PointCollection()); + + public static readonly BindableProperty FillRuleProperty = + BindableProperty.Create(nameof(FillRule), typeof(FillRule), typeof(Polyline), FillRule.EvenOdd); + + public PointCollection Points + { + set { SetValue(PointsProperty, value); } + get { return (PointCollection)GetValue(PointsProperty); } + } + + public FillRule FillRule + { + set { SetValue(FillRuleProperty, value); } + get { return (FillRule)GetValue(FillRuleProperty); } + } + } +} \ No newline at end of file diff --git a/Xamarin.Forms.Core/Shapes/Rect.cs b/Xamarin.Forms.Core/Shapes/Rect.cs new file mode 100644 index 00000000000..9e9fb2187ac --- /dev/null +++ b/Xamarin.Forms.Core/Shapes/Rect.cs @@ -0,0 +1,31 @@ +using Xamarin.Forms.Platform; + +namespace Xamarin.Forms.Shapes +{ + [RenderWith(typeof(_RectangleRenderer))] + public sealed class Rectangle : Shape + { + public Rectangle() + { + Aspect = Stretch.Fill; + } + + public static readonly BindableProperty RadiusXProperty = + BindableProperty.Create(nameof(RadiusX), typeof(double), typeof(Rectangle), 0.0d); + + public static readonly BindableProperty RadiusYProperty = + BindableProperty.Create(nameof(RadiusY), typeof(double), typeof(Rectangle), 0.0d); + + public double RadiusX + { + set { SetValue(RadiusXProperty, value); } + get { return (double)GetValue(RadiusXProperty); } + } + + public double RadiusY + { + set { SetValue(RadiusYProperty, value); } + get { return (double)GetValue(RadiusYProperty); } + } + } +} \ No newline at end of file diff --git a/Xamarin.Forms.Core/Shapes/Shape.cs b/Xamarin.Forms.Core/Shapes/Shape.cs new file mode 100644 index 00000000000..228604785d8 --- /dev/null +++ b/Xamarin.Forms.Core/Shapes/Shape.cs @@ -0,0 +1,83 @@ +namespace Xamarin.Forms.Shapes +{ + public abstract class Shape : View + { + public Shape() + { + ExperimentalFlags.VerifyFlagEnabled(nameof(Shape), ExperimentalFlags.ShapesExperimental); + } + + public static readonly BindableProperty FillProperty = + BindableProperty.Create(nameof(Fill), typeof(Color), typeof(Shape), null); + + public static readonly BindableProperty StrokeProperty = + BindableProperty.Create(nameof(Stroke), typeof(Color), typeof(Shape), null); + + public static readonly BindableProperty StrokeThicknessProperty = + BindableProperty.Create(nameof(StrokeThickness), typeof(double), typeof(Shape), 1.0); + + public static readonly BindableProperty StrokeDashArrayProperty = + BindableProperty.Create(nameof(StrokeDashArray), typeof(DoubleCollection), typeof(Shape), null, + defaultValueCreator: bindable => new DoubleCollection()); + + public static readonly BindableProperty StrokeDashOffsetProperty = + BindableProperty.Create(nameof(StrokeDashOffset), typeof(double), typeof(Shape), 0.0); + + public static readonly BindableProperty StrokeLineCapProperty = + BindableProperty.Create(nameof(StrokeLineCap), typeof(PenLineCap), typeof(Shape), PenLineCap.Flat); + + public static readonly BindableProperty StrokeLineJoinProperty = + BindableProperty.Create(nameof(StrokeLineJoin), typeof(PenLineJoin), typeof(Shape), PenLineJoin.Miter); + + public static readonly BindableProperty AspectProperty = + BindableProperty.Create(nameof(Aspect), typeof(Stretch), typeof(Shape), Stretch.None); + + public Color Fill + { + set { SetValue(FillProperty, value); } + get { return (Color)GetValue(FillProperty); } + } + + public Color Stroke + { + set { SetValue(StrokeProperty, value); } + get { return (Color)GetValue(StrokeProperty); } + } + + public double StrokeThickness + { + set { SetValue(StrokeThicknessProperty, value); } + get { return (double)GetValue(StrokeThicknessProperty); } + } + + public DoubleCollection StrokeDashArray + { + set { SetValue(StrokeDashArrayProperty, value); } + get { return (DoubleCollection)GetValue(StrokeDashArrayProperty); } + } + + public double StrokeDashOffset + { + set { SetValue(StrokeDashOffsetProperty, value); } + get { return (double)GetValue(StrokeDashOffsetProperty); } + } + + public PenLineCap StrokeLineCap + { + set { SetValue(StrokeLineCapProperty, value); } + get { return (PenLineCap)GetValue(StrokeLineCapProperty); } + } + + public PenLineJoin StrokeLineJoin + { + set { SetValue(StrokeLineJoinProperty, value); } + get { return (PenLineJoin)GetValue(StrokeLineJoinProperty); } + } + + public Stretch Aspect + { + set { SetValue(AspectProperty, value); } + get { return (Stretch)GetValue(AspectProperty); } + } + } +} \ No newline at end of file diff --git a/Xamarin.Forms.Core/Stretch.cs b/Xamarin.Forms.Core/Stretch.cs new file mode 100644 index 00000000000..0f5ba85381f --- /dev/null +++ b/Xamarin.Forms.Core/Stretch.cs @@ -0,0 +1,10 @@ +namespace Xamarin.Forms +{ + public enum Stretch + { + None, + Fill, + Uniform, + UniformToFill + } +} \ No newline at end of file diff --git a/Xamarin.Forms.Core/Xamarin.Forms.Core.csproj b/Xamarin.Forms.Core/Xamarin.Forms.Core.csproj index 4be554b2055..f4434993a6b 100644 --- a/Xamarin.Forms.Core/Xamarin.Forms.Core.csproj +++ b/Xamarin.Forms.Core/Xamarin.Forms.Core.csproj @@ -22,6 +22,7 @@ + high diff --git a/Xamarin.Forms.Maps.UWP/MapRenderer.cs b/Xamarin.Forms.Maps.UWP/MapRenderer.cs index 366d76317cb..be2855d2d97 100644 --- a/Xamarin.Forms.Maps.UWP/MapRenderer.cs +++ b/Xamarin.Forms.Maps.UWP/MapRenderer.cs @@ -10,8 +10,8 @@ using Windows.UI.Xaml; using Windows.UI.Xaml.Controls.Maps; using Windows.UI.Xaml.Media; -using Windows.UI.Xaml.Shapes; using Xamarin.Forms.Platform.UWP; +using WEllipse = Windows.UI.Xaml.Shapes.Ellipse; namespace Xamarin.Forms.Maps.UWP { @@ -121,7 +121,7 @@ protected override void Dispose(bool disposing) } bool _disposed; - Ellipse _userPositionCircle; + WEllipse _userPositionCircle; DispatcherTimer _timer; void OnPinCollectionChanged(object sender, NotifyCollectionChangedEventArgs e) @@ -516,7 +516,7 @@ void LoadUserPosition(Geocoordinate userCoordinate, bool center) if (_userPositionCircle == null) { - _userPositionCircle = new Ellipse + _userPositionCircle = new WEllipse { Stroke = new SolidColorBrush(Colors.White), Fill = new SolidColorBrush(Colors.Blue), diff --git a/Xamarin.Forms.Material.Android/MaterialFormsEditTextBase.cs b/Xamarin.Forms.Material.Android/MaterialFormsEditTextBase.cs index a8a0a51de7e..9f2b2aac592 100644 --- a/Xamarin.Forms.Material.Android/MaterialFormsEditTextBase.cs +++ b/Xamarin.Forms.Material.Android/MaterialFormsEditTextBase.cs @@ -1,5 +1,4 @@ - -using System; +using System; using Android.Content; using Android.Graphics; using Android.Views; @@ -11,6 +10,7 @@ using Android.Runtime; using Android.Util; using Xamarin.Forms.Platform.Android; +using ARect = Android.Graphics.Rect; namespace Xamarin.Forms.Material.Android { @@ -51,7 +51,7 @@ bool IDescendantFocusToggler.RequestFocus(global::Android.Views.View control, Fu return _descendantFocusToggler.RequestFocus(this, baseRequestFocus); } - public override bool RequestFocus(FocusSearchDirection direction, Rect previouslyFocusedRect) + public override bool RequestFocus(FocusSearchDirection direction, ARect previouslyFocusedRect) { return (this as IDescendantFocusToggler).RequestFocus(this, () => base.RequestFocus(direction, previouslyFocusedRect)); } diff --git a/Xamarin.Forms.Material.Android/MaterialPickerEditText.cs b/Xamarin.Forms.Material.Android/MaterialPickerEditText.cs index 9754d40637b..b79793f6fe2 100644 --- a/Xamarin.Forms.Material.Android/MaterialPickerEditText.cs +++ b/Xamarin.Forms.Material.Android/MaterialPickerEditText.cs @@ -1,11 +1,10 @@ - -using System; +using System; using Android.Content; -using Android.Graphics; using Android.Runtime; using Android.Util; using Android.Views; using Xamarin.Forms.Platform.Android; +using ARect = Android.Graphics.Rect; namespace Xamarin.Forms.Material.Android { @@ -27,7 +26,7 @@ public override bool OnTouchEvent(MotionEvent e) return base.OnTouchEvent(e); // raises the OnClick event if focus is already received } - protected override void OnFocusChanged(bool gainFocus, [GeneratedEnum] FocusSearchDirection direction, Rect previouslyFocusedRect) + protected override void OnFocusChanged(bool gainFocus, [GeneratedEnum] FocusSearchDirection direction, ARect previouslyFocusedRect) { base.OnFocusChanged(gainFocus, direction, previouslyFocusedRect); PickerManager.OnFocusChanged(gainFocus, this, (IPopupTrigger)Parent.Parent); diff --git a/Xamarin.Forms.Material.Tizen/MaterialStepperRenderer.cs b/Xamarin.Forms.Material.Tizen/MaterialStepperRenderer.cs index 0ad7fcad13f..d58ac6aafb3 100644 --- a/Xamarin.Forms.Material.Tizen/MaterialStepperRenderer.cs +++ b/Xamarin.Forms.Material.Tizen/MaterialStepperRenderer.cs @@ -1,6 +1,5 @@ using System; using System.ComponentModel; -using ElmSharp; using Tizen.NET.MaterialComponents; using Xamarin.Forms; using Xamarin.Forms.Material.Tizen; @@ -8,6 +7,7 @@ using Xamarin.Forms.Platform.Tizen.Native; using EBox = ElmSharp.Box; using EColor = ElmSharp.Color; +using ERect = ElmSharp.Rect; [assembly: ExportRenderer(typeof(Stepper), typeof(MaterialStepperRenderer), new[] { typeof(VisualMarker.MaterialVisual) })] namespace Xamarin.Forms.Material.Tizen @@ -153,12 +153,12 @@ void OnLayout() var y = Control.Geometry.Y; var w = (int)(Control.Geometry.Width - (horizontalPadding * 3)) / 2; var h = Control.Geometry.Height; - var rectL = new Rect(x, y, w, h); + var rectL = new ERect(x, y, w, h); _borderL.Draw(rectL); _buttonL.Geometry = rectL; var x2 = Control.Geometry.X + w + (horizontalPadding * 2); - var rectR = new Rect(x2, y, w, h); + var rectR = new ERect(x2, y, w, h); _borderR.Draw(rectR); _buttonR.Geometry = rectR; } diff --git a/Xamarin.Forms.Platform.Android/ButtonLayoutManager.cs b/Xamarin.Forms.Platform.Android/ButtonLayoutManager.cs index b32742b7912..e02e8acde62 100644 --- a/Xamarin.Forms.Platform.Android/ButtonLayoutManager.cs +++ b/Xamarin.Forms.Platform.Android/ButtonLayoutManager.cs @@ -13,6 +13,7 @@ using Android.Support.V7.Widget; #endif using Xamarin.Forms.Internals; +using ARect = Android.Graphics.Rect; using AView = Android.Views.View; using AButton = Android.Widget.Button; @@ -29,7 +30,7 @@ public class ButtonLayoutManager : IDisposable Button.ButtonContentLayout _imageOnlyLayout = new Button.ButtonContentLayout(Button.ButtonContentLayout.ImagePosition.Left, 0); // reuse this instance to save on allocations - Rect _drawableBounds = new Rect(); + ARect _drawableBounds = new ARect(); bool _disposed; IButtonLayoutRenderer _renderer; diff --git a/Xamarin.Forms.Platform.Android/Cells/EntryCellEditText.cs b/Xamarin.Forms.Platform.Android/Cells/EntryCellEditText.cs index ec0a25bc3de..f076bd06096 100644 --- a/Xamarin.Forms.Platform.Android/Cells/EntryCellEditText.cs +++ b/Xamarin.Forms.Platform.Android/Cells/EntryCellEditText.cs @@ -1,9 +1,8 @@ using System; -using Android.App; using Android.Content; -using Android.Graphics; using Android.Views; using Android.Widget; +using ARect = Android.Graphics.Rect; namespace Xamarin.Forms.Platform.Android { @@ -26,7 +25,7 @@ public override bool OnKeyPreIme(Keycode keyCode, KeyEvent e) return base.OnKeyPreIme(keyCode, e); } - protected override void OnFocusChanged(bool gainFocus, FocusSearchDirection direction, Rect previouslyFocusedRect) + protected override void OnFocusChanged(bool gainFocus, FocusSearchDirection direction, ARect previouslyFocusedRect) { Window window = Context.GetActivity().Window; if (gainFocus) diff --git a/Xamarin.Forms.Platform.Android/CollectionView/CarouselSpacingItemDecoration.cs b/Xamarin.Forms.Platform.Android/CollectionView/CarouselSpacingItemDecoration.cs index cfa5d6ba64c..b20e6143efd 100644 --- a/Xamarin.Forms.Platform.Android/CollectionView/CarouselSpacingItemDecoration.cs +++ b/Xamarin.Forms.Platform.Android/CollectionView/CarouselSpacingItemDecoration.cs @@ -6,6 +6,7 @@ #else using Android.Support.V7.Widget; #endif +using ARect = Android.Graphics.Rect; using AView = Android.Views.View; using FormsCarouselView = Xamarin.Forms.CarouselView; @@ -43,7 +44,7 @@ public CarouselSpacingItemDecoration(IItemsLayout itemsLayout, FormsCarouselView _carouselView = carouselView; } - public override void GetItemOffsets(Rect outRect, AView view, RecyclerView parent, RecyclerView.State state) + public override void GetItemOffsets(ARect outRect, AView view, RecyclerView parent, RecyclerView.State state) { base.GetItemOffsets(outRect, view, parent, state); diff --git a/Xamarin.Forms.Platform.Android/CollectionView/ItemsViewRenderer.cs b/Xamarin.Forms.Platform.Android/CollectionView/ItemsViewRenderer.cs index 88fa30084e4..24a19294fc6 100644 --- a/Xamarin.Forms.Platform.Android/CollectionView/ItemsViewRenderer.cs +++ b/Xamarin.Forms.Platform.Android/CollectionView/ItemsViewRenderer.cs @@ -14,6 +14,7 @@ using Xamarin.Forms.Internals; using Xamarin.Forms.Platform.Android.CollectionView; using Xamarin.Forms.Platform.Android.FastRenderers; +using ARect = Android.Graphics.Rect; namespace Xamarin.Forms.Platform.Android { @@ -65,7 +66,7 @@ public ItemsViewRenderer(Context context) : base( protected override void OnLayout(bool changed, int l, int t, int r, int b) { base.OnLayout(changed, l, t, r, b); - AViewCompat.SetClipBounds(this, new Rect(0, 0, Width, Height)); + AViewCompat.SetClipBounds(this, new ARect(0, 0, Width, Height)); // After a direct (non-animated) scroll operation, we may need to make adjustments // to align the target item; if an adjustment is pending, execute it here. diff --git a/Xamarin.Forms.Platform.Android/CollectionView/ScrollHelper.cs b/Xamarin.Forms.Platform.Android/CollectionView/ScrollHelper.cs index e741c07c53e..6e0af7a44cd 100644 --- a/Xamarin.Forms.Platform.Android/CollectionView/ScrollHelper.cs +++ b/Xamarin.Forms.Platform.Android/CollectionView/ScrollHelper.cs @@ -1,5 +1,6 @@ using System; using Android.Graphics; +using ARect = Android.Graphics.Rect; #if __ANDROID_29__ using AndroidX.AppCompat.Widget; using AndroidX.RecyclerView.Widget; @@ -127,7 +128,7 @@ public void JumpScrollToPosition(int index, ScrollToPosition scrollToPosition, b _recyclerView.ScrollToPosition(index); } - Rect GetViewRect(int index) + ARect GetViewRect(int index) { var holder = _recyclerView.FindViewHolderForAdapterPosition(index); var view = holder?.ItemView; @@ -137,7 +138,7 @@ Rect GetViewRect(int index) return null; } - var viewRect = new Rect(); + var viewRect = new ARect(); view.GetGlobalVisibleRect(viewRect); return viewRect; @@ -156,7 +157,7 @@ void AdjustVerticalScroll(int index, ScrollToPosition scrollToPosition) var offset = 0; - var rvRect = new Rect(); + var rvRect = new ARect(); _recyclerView.GetGlobalVisibleRect(rvRect); if (scrollToPosition == ScrollToPosition.Center) @@ -184,7 +185,7 @@ void AdjustHorizontalScroll(int index, ScrollToPosition scrollToPosition) var offset = 0; - var rvRect = new Rect(); + var rvRect = new ARect(); _recyclerView.GetGlobalVisibleRect(rvRect); if (scrollToPosition == ScrollToPosition.Center) diff --git a/Xamarin.Forms.Platform.Android/CollectionView/SpacingItemDecoration.cs b/Xamarin.Forms.Platform.Android/CollectionView/SpacingItemDecoration.cs index 63d444b3113..05dbb38cacf 100644 --- a/Xamarin.Forms.Platform.Android/CollectionView/SpacingItemDecoration.cs +++ b/Xamarin.Forms.Platform.Android/CollectionView/SpacingItemDecoration.cs @@ -7,6 +7,7 @@ using Android.Support.V7.Widget; #endif using AView = Android.Views.View; +using ARect = Android.Graphics.Rect; namespace Xamarin.Forms.Platform.Android { @@ -42,7 +43,7 @@ public SpacingItemDecoration(IItemsLayout itemsLayout) } } - public override void GetItemOffsets(Rect outRect, AView view, RecyclerView parent, RecyclerView.State state) + public override void GetItemOffsets(ARect outRect, AView view, RecyclerView parent, RecyclerView.State state) { base.GetItemOffsets(outRect, view, parent, state); diff --git a/Xamarin.Forms.Platform.Android/Extensions/DoubleCollectionExtensions.cs b/Xamarin.Forms.Platform.Android/Extensions/DoubleCollectionExtensions.cs new file mode 100644 index 00000000000..d82599b1db9 --- /dev/null +++ b/Xamarin.Forms.Platform.Android/Extensions/DoubleCollectionExtensions.cs @@ -0,0 +1,17 @@ +namespace Xamarin.Forms.Platform.Android +{ + public static class DoubleCollectionExtensions + { + public static float[] ToArray(this DoubleCollection doubleCollection) + { + float[] array = new float[doubleCollection.Count]; + + for (int i = 0; i < doubleCollection.Count; i++) + { + array[i] = (float)doubleCollection[i]; + } + + return array; + } + } +} \ No newline at end of file diff --git a/Xamarin.Forms.Platform.Android/Renderers/FormsEditText.cs b/Xamarin.Forms.Platform.Android/Renderers/FormsEditText.cs index b71141c91bc..67c4041a7f1 100644 --- a/Xamarin.Forms.Platform.Android/Renderers/FormsEditText.cs +++ b/Xamarin.Forms.Platform.Android/Renderers/FormsEditText.cs @@ -9,6 +9,7 @@ #else using Android.Support.V4.Graphics.Drawable; #endif +using ARect = Android.Graphics.Rect; namespace Xamarin.Forms.Platform.Android { @@ -70,7 +71,7 @@ bool IDescendantFocusToggler.RequestFocus(global::Android.Views.View control, Fu } - public override bool RequestFocus(FocusSearchDirection direction, Rect previouslyFocusedRect) + public override bool RequestFocus(FocusSearchDirection direction, ARect previouslyFocusedRect) { return (this as IDescendantFocusToggler).RequestFocus(this, () => base.RequestFocus(direction, previouslyFocusedRect)); } diff --git a/Xamarin.Forms.Platform.Android/Renderers/IFormsEditText.cs b/Xamarin.Forms.Platform.Android/Renderers/IFormsEditText.cs index 1129f16cf81..4452be4e936 100644 --- a/Xamarin.Forms.Platform.Android/Renderers/IFormsEditText.cs +++ b/Xamarin.Forms.Platform.Android/Renderers/IFormsEditText.cs @@ -1,13 +1,13 @@ -using Android.Graphics; -using Android.Views; +using Android.Views; using System; +using ARect = Android.Graphics.Rect; namespace Xamarin.Forms.Platform.Android { internal interface IFormsEditText { bool OnKeyPreIme(Keycode keyCode, KeyEvent e); - bool RequestFocus(FocusSearchDirection direction, Rect previouslyFocusedRect); + bool RequestFocus(FocusSearchDirection direction, ARect previouslyFocusedRect); event EventHandler OnKeyboardBackPressed; event EventHandler SelectionChanged; } diff --git a/Xamarin.Forms.Platform.Android/Renderers/PickerEditText.cs b/Xamarin.Forms.Platform.Android/Renderers/PickerEditText.cs index c7a7a1ad74e..947c0cff074 100644 --- a/Xamarin.Forms.Platform.Android/Renderers/PickerEditText.cs +++ b/Xamarin.Forms.Platform.Android/Renderers/PickerEditText.cs @@ -1,9 +1,7 @@ -using System; using Android.Content; -using Android.Graphics; using Android.Runtime; using Android.Views; -using Android.Widget; +using ARect = Android.Graphics.Rect; namespace Xamarin.Forms.Platform.Android { @@ -27,7 +25,7 @@ public override bool OnTouchEvent(MotionEvent e) return base.OnTouchEvent(e); // raises the OnClick event if focus is already received } - protected override void OnFocusChanged(bool gainFocus, [GeneratedEnum] FocusSearchDirection direction, Rect previouslyFocusedRect) + protected override void OnFocusChanged(bool gainFocus, [GeneratedEnum] FocusSearchDirection direction, ARect previouslyFocusedRect) { base.OnFocusChanged(gainFocus, direction, previouslyFocusedRect); PickerManager.OnFocusChanged(gainFocus, this, this); diff --git a/Xamarin.Forms.Platform.Android/Renderers/ShellRenderer.cs b/Xamarin.Forms.Platform.Android/Renderers/ShellRenderer.cs index 2687c3c35ce..2695f76a1b4 100644 --- a/Xamarin.Forms.Platform.Android/Renderers/ShellRenderer.cs +++ b/Xamarin.Forms.Platform.Android/Renderers/ShellRenderer.cs @@ -21,6 +21,7 @@ using System.Threading.Tasks; using Xamarin.Forms.Internals; using AColor = Android.Graphics.Color; +using ARect = Android.Graphics.Rect; using AView = Android.Views.View; using LP = Android.Views.ViewGroup.LayoutParams; @@ -393,9 +394,9 @@ public override void Draw(Canvas canvas) paint.Color = Color; - canvas.DrawRect(new Rect(0, 0, bounds.Right, TopSize), paint); + canvas.DrawRect(new ARect(0, 0, bounds.Right, TopSize), paint); - canvas.DrawRect(new Rect(0, bounds.Bottom - BottomSize, bounds.Right, bounds.Bottom), paint); + canvas.DrawRect(new ARect(0, bounds.Bottom - BottomSize, bounds.Right, bounds.Bottom), paint); paint.Dispose(); } diff --git a/Xamarin.Forms.Platform.Android/Shapes/EllipseRenderer.cs b/Xamarin.Forms.Platform.Android/Shapes/EllipseRenderer.cs new file mode 100644 index 00000000000..dc42d503212 --- /dev/null +++ b/Xamarin.Forms.Platform.Android/Shapes/EllipseRenderer.cs @@ -0,0 +1,39 @@ +using Android.Content; +using Xamarin.Forms.Shapes; +using APath = Android.Graphics.Path; + +namespace Xamarin.Forms.Platform.Android +{ + public class EllipseRenderer : ShapeRenderer + { + public EllipseRenderer(Context context) : base(context) + { + + } + + protected override void OnElementChanged(ElementChangedEventArgs args) + { + if (Control == null) + { + SetNativeControl(new EllipseView(Context)); + } + + base.OnElementChanged(args); + } + } + + public class EllipseView : ShapeView + { + public EllipseView(Context context) : base(context) + { + UpdateShape(); + } + + void UpdateShape() + { + var path = new APath(); + path.AddCircle(0, 0, 1, APath.Direction.Cw); + UpdateShape(path); + } + } +} \ No newline at end of file diff --git a/Xamarin.Forms.Platform.Android/Shapes/LineRenderer.cs b/Xamarin.Forms.Platform.Android/Shapes/LineRenderer.cs new file mode 100644 index 00000000000..a3107245c53 --- /dev/null +++ b/Xamarin.Forms.Platform.Android/Shapes/LineRenderer.cs @@ -0,0 +1,108 @@ +using System.ComponentModel; +using Android.Content; +using Xamarin.Forms.Shapes; +using APath = Android.Graphics.Path; + +namespace Xamarin.Forms.Platform.Android +{ + public class LineRenderer : ShapeRenderer + { + public LineRenderer(Context context) : base(context) + { + + } + + protected override void OnElementChanged(ElementChangedEventArgs args) + { + if (Control == null) + { + SetNativeControl(new LineView(Context)); + } + + base.OnElementChanged(args); + + if (args.NewElement != null) + { + UpdateX1(); + UpdateY1(); + UpdateX2(); + UpdateY2(); + } + } + + protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs args) + { + base.OnElementPropertyChanged(sender, args); + + if (args.PropertyName == Line.X1Property.PropertyName) + UpdateX1(); + else if (args.PropertyName == Line.Y1Property.PropertyName) + UpdateY1(); + else if (args.PropertyName == Line.X2Property.PropertyName) + UpdateX2(); + else if (args.PropertyName == Line.Y2Property.PropertyName) + UpdateY2(); + } + + void UpdateX1() + { + Control.UpdateX1((float)Element.X1); + } + + void UpdateY1() + { + Control.UpdateY1((float)Element.Y1); + } + + void UpdateX2() + { + Control.UpdateX2((float)Element.X2); + } + + void UpdateY2() + { + Control.UpdateY2((float)Element.Y2); + } + } + + public class LineView : ShapeView + { + float _x1, _y1, _x2, _y2; + + public LineView(Context context) : base(context) + { + } + + void UpdateShape() + { + var path = new APath(); + path.MoveTo(_x1, _y1); + path.LineTo(_x2, _y2); + UpdateShape(path); + } + + public void UpdateX1(float x1) + { + _x1 = _density * x1; + UpdateShape(); + } + + public void UpdateY1(float y1) + { + _y1 = _density * y1; + UpdateShape(); + } + + public void UpdateX2(float x2) + { + _x2 = _density * x2; + UpdateShape(); + } + + public void UpdateY2(float y2) + { + _y2 = _density * y2; + UpdateShape(); + } + } +} \ No newline at end of file diff --git a/Xamarin.Forms.Platform.Android/Shapes/PolygonRenderer.cs b/Xamarin.Forms.Platform.Android/Shapes/PolygonRenderer.cs new file mode 100644 index 00000000000..301cc4ff402 --- /dev/null +++ b/Xamarin.Forms.Platform.Android/Shapes/PolygonRenderer.cs @@ -0,0 +1,93 @@ +using System.ComponentModel; +using Android.Content; +using Xamarin.Forms.Shapes; +using static Android.Graphics.Path; +using APath = Android.Graphics.Path; + +namespace Xamarin.Forms.Platform.Android +{ + public class PolygonRenderer : ShapeRenderer + { + public PolygonRenderer(Context context) : base(context) + { + + } + + protected override void OnElementChanged(ElementChangedEventArgs args) + { + if (Control == null) + { + SetNativeControl(new PolygonView(Context)); + } + + base.OnElementChanged(args); + + if (args.NewElement != null) + { + UpdatePoints(); + UpdateFillRule(); + } + } + + protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs args) + { + base.OnElementPropertyChanged(sender, args); + + if (args.PropertyName == Polyline.PointsProperty.PropertyName) + UpdatePoints(); + else if (args.PropertyName == Polyline.FillRuleProperty.PropertyName) + UpdateFillRule(); + } + + void UpdatePoints() + { + Control.UpdatePoints(Element.Points); + } + + void UpdateFillRule() + { + Control.UpdateFillMode(Element.FillRule == FillRule.Nonzero); + } + } + + public class PolygonView : ShapeView + { + PointCollection _points; + bool _fillMode; + + public PolygonView(Context context) : base(context) + { + + } + + void UpdateShape() + { + if (_points != null && _points.Count > 1) + { + APath path = new APath(); + path.SetFillType(_fillMode ? FillType.Winding : FillType.EvenOdd); + + path.MoveTo(_density * (float)_points[0].X, _density * (float)_points[0].Y); + + for (int index = 1; index < _points.Count; index++) + path.LineTo(_density * (float)_points[index].X, _density * (float)_points[index].Y); + + path.Close(); + + UpdateShape(path); + } + } + + public void UpdatePoints(PointCollection points) + { + _points = points; + UpdateShape(); + } + + public void UpdateFillMode(bool fillMode) + { + _fillMode = fillMode; + UpdateShape(); + } + } +} diff --git a/Xamarin.Forms.Platform.Android/Shapes/PolylineRenderer.cs b/Xamarin.Forms.Platform.Android/Shapes/PolylineRenderer.cs new file mode 100644 index 00000000000..2c0ba9cdf77 --- /dev/null +++ b/Xamarin.Forms.Platform.Android/Shapes/PolylineRenderer.cs @@ -0,0 +1,90 @@ +using System.ComponentModel; +using Android.Content; +using Xamarin.Forms.Shapes; +using static Android.Graphics.Path; +using APath = Android.Graphics.Path; + +namespace Xamarin.Forms.Platform.Android +{ + public class PolylineRenderer : ShapeRenderer + { + public PolylineRenderer(Context context) : base(context) + { + + } + + protected override void OnElementChanged(ElementChangedEventArgs args) + { + if (Control == null) + { + SetNativeControl(new PolylineView(Context)); + } + + base.OnElementChanged(args); + + if (args.NewElement != null) + { + UpdatePoints(); + UpdateFillRule(); + } + } + + protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs args) + { + base.OnElementPropertyChanged(sender, args); + + if (args.PropertyName == Polyline.PointsProperty.PropertyName) + UpdatePoints(); + else if (args.PropertyName == Polyline.FillRuleProperty.PropertyName) + UpdateFillRule(); + } + + void UpdatePoints() + { + Control.UpdatePoints(Element.Points); + } + + void UpdateFillRule() + { + Control.UpdateFillMode(Element.FillRule == FillRule.Nonzero); + } + } + + public class PolylineView : ShapeView + { + PointCollection _points; + bool _fillMode; + + public PolylineView(Context context) : base(context) + { + } + + void UpdateShape() + { + if (_points != null && _points.Count > 1) + { + var path = new APath(); + path.SetFillType(_fillMode ? FillType.Winding : FillType.EvenOdd); + + path.MoveTo(_density * (float)_points[0].X, _density * (float)_points[0].Y); + + for (int index = 1; index < _points.Count; index++) + path.LineTo(_density * (float)_points[index].X, _density * (float)_points[index].Y); + + UpdateShape(path); + } + } + + public void UpdatePoints(PointCollection points) + { + _points = points; + UpdateShape(); + } + + public void UpdateFillMode(bool fillMode) + { + _fillMode = fillMode; + UpdateShape(); + } + } +} diff --git a/Xamarin.Forms.Platform.Android/Shapes/RectangleRenderer.cs b/Xamarin.Forms.Platform.Android/Shapes/RectangleRenderer.cs new file mode 100644 index 00000000000..7a7ba83967e --- /dev/null +++ b/Xamarin.Forms.Platform.Android/Shapes/RectangleRenderer.cs @@ -0,0 +1,83 @@ +using System.ComponentModel; +using Android.Content; +using Android.Graphics; +using Rect = Xamarin.Forms.Shapes.Rectangle; +using APath = Android.Graphics.Path; + +namespace Xamarin.Forms.Platform.Android +{ + public class RectangleRenderer : ShapeRenderer + { + public RectangleRenderer(Context context) : base(context) + { + + } + + protected override void OnElementChanged(ElementChangedEventArgs args) + { + if (Control == null) + { + SetNativeControl(new RectView(Context)); + } + + base.OnElementChanged(args); + + if (args.NewElement != null) + { + UpdateRadiusX(); + UpdateRadiusY(); + } + } + + protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs args) + { + base.OnElementPropertyChanged(sender, args); + + if (args.PropertyName == Rect.RadiusXProperty.PropertyName) + UpdateRadiusX(); + else if (args.PropertyName == Rect.RadiusYProperty.PropertyName) + UpdateRadiusY(); + } + + void UpdateRadiusX() + { + Control.UpdateRadiusX(Element.RadiusX / Element.WidthRequest); + } + + void UpdateRadiusY() + { + Control.UpdateRadiusY(Element.RadiusY / Element.HeightRequest); + } + } + + public class RectView : ShapeView + { + public RectView(Context context) : base(context) + { + UpdateShape(); + } + + public float RadiusX { set; get; } + + public float RadiusY { set; get; } + + void UpdateShape() + { + var path = new APath(); + path.AddRoundRect(new RectF(0, 0, 1, 1), RadiusX, RadiusY, APath.Direction.Cw); + UpdateShape(path); + } + + public void UpdateRadiusX(double radiusX) + { + RadiusX = (float)radiusX; + UpdateShape(); + } + + public void UpdateRadiusY(double radiusY) + { + RadiusY = (float)radiusY; + UpdateShape(); + } + } +} diff --git a/Xamarin.Forms.Platform.Android/Shapes/ShapeRenderer.cs b/Xamarin.Forms.Platform.Android/Shapes/ShapeRenderer.cs new file mode 100644 index 00000000000..8d1705dd58b --- /dev/null +++ b/Xamarin.Forms.Platform.Android/Shapes/ShapeRenderer.cs @@ -0,0 +1,383 @@ +using System; +using System.ComponentModel; +using Android.Content; +using Android.Graphics; +using Android.Graphics.Drawables; +using Android.Graphics.Drawables.Shapes; +using AColor = Android.Graphics.Color; +using AMatrix = Android.Graphics.Matrix; +using APath = Android.Graphics.Path; +using AView = Android.Views.View; +using Shape = Xamarin.Forms.Shapes.Shape; + +namespace Xamarin.Forms.Platform.Android +{ + public class ShapeRenderer : ViewRenderer + where TShape : Shape + where TNativeShape : ShapeView + { + double _height; + double _width; + + public ShapeRenderer(Context context) : base(context) + { + + } + + protected override void OnElementChanged(ElementChangedEventArgs args) + { + base.OnElementChanged(args); + + if (args.NewElement != null) + { + UpdateSize(); + UpdateAspect(); + UpdateFill(); + UpdateStroke(); + UpdateStrokeThickness(); + UpdateStrokeDashArray(); + UpdateStrokeLineCap(); + UpdateStrokeLineJoin(); + } + } + + protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs args) + { + base.OnElementPropertyChanged(sender, args); + + if (args.PropertyName == VisualElement.HeightProperty.PropertyName) + { + _height = Element.Height; + UpdateSize(); + } + else if (args.PropertyName == VisualElement.WidthProperty.PropertyName) + { + _width = Element.Width; + UpdateSize(); + } + else if (args.PropertyName == Shape.AspectProperty.PropertyName) + UpdateAspect(); + else if (args.PropertyName == Shape.FillProperty.PropertyName) + UpdateFill(); + else if (args.PropertyName == Shape.StrokeProperty.PropertyName) + UpdateStroke(); + else if (args.PropertyName == Shape.StrokeThicknessProperty.PropertyName) + UpdateStrokeThickness(); + else if (args.PropertyName == Shape.StrokeDashArrayProperty.PropertyName) + UpdateStrokeDashArray(); + else if (args.PropertyName == Shape.StrokeLineCapProperty.PropertyName) + UpdateStrokeLineCap(); + else if (args.PropertyName == Shape.StrokeLineJoinProperty.PropertyName) + UpdateStrokeLineJoin(); + } + + public override SizeRequest GetDesiredSize(int widthConstraint, int heightConstraint) + { + if (Element != null) + { + return Control.GetDesiredSize(); + } + + return base.GetDesiredSize(widthConstraint, heightConstraint); + } + + void UpdateSize() + { + Control.UpdateSize(_width, _height); + } + + void UpdateAspect() + { + Control.UpdateAspect(Element.Aspect); + } + + void UpdateFill() + { + Control.UpdateFill(Element.Fill.ToAndroid()); + } + + void UpdateStroke() + { + Control.UpdateStroke(Element.Stroke.ToAndroid()); + } + + void UpdateStrokeThickness() + { + Control.UpdateStrokeThickness((float)Element.StrokeThickness); + } + + void UpdateStrokeDashArray() + { + Control.UpdateStrokeDashArray(Element.StrokeDashArray.ToArray()); + } + + void UpdateStrokeLineCap() + { + PenLineCap lineCap = Element.StrokeLineCap; + Paint.Cap aLineCap = Paint.Cap.Butt; + + switch (lineCap) + { + case PenLineCap.Flat: + aLineCap = Paint.Cap.Butt; + break; + case PenLineCap.Square: + aLineCap = Paint.Cap.Square; + break; + case PenLineCap.Round: + aLineCap = Paint.Cap.Round; + break; + } + + Control.UpdateStrokeLineCap(aLineCap); + } + + void UpdateStrokeLineJoin() + { + PenLineJoin lineJoin = Element.StrokeLineJoin; + Paint.Join aLineJoin = Paint.Join.Miter; + + switch (lineJoin) + { + case PenLineJoin.Miter: + aLineJoin = Paint.Join.Miter; + break; + case PenLineJoin.Bevel: + aLineJoin = Paint.Join.Bevel; + break; + case PenLineJoin.Round: + aLineJoin = Paint.Join.Round; + break; + } + + Control.UpdateStrokeLineJoin(aLineJoin); + } + } + + public class ShapeView : AView + { + readonly ShapeDrawable _drawable; + protected float _density; + + APath _path; + readonly RectF _pathFillBounds; + readonly RectF _pathStrokeBounds; + + AColor _stroke; + AColor _fill; + + float _strokeWidth; + float[] _strokeDash; + + Stretch _aspect; + + public ShapeView(Context context) : base(context) + { + _drawable = new ShapeDrawable(null); + + _density = Resources.DisplayMetrics.Density; + + _pathFillBounds = new RectF(); + _pathStrokeBounds = new RectF(); + + _aspect = Stretch.None; + } + + protected override void OnDraw(Canvas canvas) + { + base.OnDraw(canvas); + + if (_path == null) + return; + + AMatrix transformMatrix = CreateMatrix(); + + _path.Transform(transformMatrix); + transformMatrix.MapRect(_pathFillBounds); + transformMatrix.MapRect(_pathStrokeBounds); + + if (_fill != null) + { + _drawable.Paint.SetStyle(Paint.Style.Fill); + _drawable.Paint.Color = _fill; + _drawable.Draw(canvas); + _drawable.Paint.SetShader(null); + } + + if (_stroke != null) + { + _drawable.Paint.SetStyle(Paint.Style.Stroke); + _drawable.Paint.Color = _stroke; + _drawable.Draw(canvas); + _drawable.Paint.SetShader(null); + } + + AMatrix inverseTransformMatrix = new AMatrix(); + transformMatrix.Invert(inverseTransformMatrix); + _path.Transform(inverseTransformMatrix); + inverseTransformMatrix.MapRect(_pathFillBounds); + inverseTransformMatrix.MapRect(_pathStrokeBounds); + } + + public void UpdateShape(APath path) + { + _path = path; + UpdatePathShape(); + } + + public SizeRequest GetDesiredSize() + { + if (_path != null) + { + return new SizeRequest(new Size( + Math.Max(0, _pathStrokeBounds.Right), + Math.Max(0, _pathStrokeBounds.Bottom))); + } + + return new SizeRequest(); + } + + public void UpdateAspect(Stretch aspect) + { + _aspect = aspect; + Invalidate(); + } + + public void UpdateFill(AColor fill) + { + _fill = fill; + Invalidate(); + } + + public void UpdateStroke(AColor stroke) + { + _stroke = stroke; + Invalidate(); + } + + public void UpdateStrokeThickness(float strokeWidth) + { + _strokeWidth = _density * strokeWidth; + _drawable.Paint.StrokeWidth = _strokeWidth; + UpdatePathStrokeBounds(); + } + + public void UpdateStrokeDashArray(float[] dash) + { + _strokeDash = dash; + + if (_strokeDash != null && _strokeDash.Length > 1) + { + float[] strokeDash = new float[_strokeDash.Length]; + + for (int i = 0; i < _strokeDash.Length; i++) + strokeDash[i] = _strokeDash[i] * _strokeWidth; + + _drawable.Paint.SetPathEffect(new DashPathEffect(strokeDash, 0)); + } + else + _drawable.Paint.SetPathEffect(null); + + UpdatePathStrokeBounds(); + } + + public void UpdateStrokeLineCap(Paint.Cap strokeCap) + { + _drawable.Paint.StrokeCap = strokeCap; + UpdatePathStrokeBounds(); + } + + public void UpdateStrokeLineJoin(Paint.Join strokeJoin) + { + _drawable.Paint.StrokeJoin = strokeJoin; + Invalidate(); + } + + public void UpdateSize(double width, double height) + { + _drawable.SetBounds(0, 0, (int)(width * _density), (int)(height * _density)); + UpdatePathShape(); + } + + protected void UpdatePathShape() + { + if (_path != null && !_drawable.Bounds.IsEmpty) + _drawable.Shape = new PathShape(_path, _drawable.Bounds.Width(), _drawable.Bounds.Height()); + else + _drawable.Shape = null; + + if (_path != null) + { + using (APath fillPath = new APath()) + { + _drawable.Paint.StrokeWidth = 0.01f; + _drawable.Paint.SetStyle(Paint.Style.Stroke); + _drawable.Paint.GetFillPath(_path, fillPath); + fillPath.ComputeBounds(_pathFillBounds, false); + _drawable.Paint.StrokeWidth = _strokeWidth; + } + } + else + { + _pathFillBounds.SetEmpty(); + } + + UpdatePathStrokeBounds(); + } + + AMatrix CreateMatrix() + { + AMatrix matrix = new AMatrix(); + + RectF drawableBounds = new RectF(_drawable.Bounds); + float halfStrokeWidth = _drawable.Paint.StrokeWidth / 2; + + drawableBounds.Left += halfStrokeWidth; + drawableBounds.Top += halfStrokeWidth; + drawableBounds.Right -= halfStrokeWidth; + drawableBounds.Bottom -= halfStrokeWidth; + + switch (_aspect) + { + case Stretch.None: + break; + case Stretch.Fill: + matrix.SetRectToRect(_pathFillBounds, drawableBounds, AMatrix.ScaleToFit.Fill); + break; + case Stretch.Uniform: + matrix.SetRectToRect(_pathFillBounds, drawableBounds, AMatrix.ScaleToFit.Center); + break; + case Stretch.UniformToFill: + float widthScale = drawableBounds.Width() / _pathFillBounds.Width(); + float heightScale = drawableBounds.Height() / _pathFillBounds.Height(); + float maxScale = Math.Max(widthScale, heightScale); + matrix.SetScale(maxScale, maxScale); + matrix.PostTranslate( + drawableBounds.Left - maxScale * _pathFillBounds.Left, + drawableBounds.Top - maxScale * _pathFillBounds.Top); + break; + } + + return matrix; + } + + void UpdatePathStrokeBounds() + { + if (_path != null) + { + using (APath strokePath = new APath()) + { + _drawable.Paint.SetStyle(Paint.Style.Stroke); + _drawable.Paint.GetFillPath(_path, strokePath); + strokePath.ComputeBounds(_pathStrokeBounds, false); + } + } + else + { + _pathStrokeBounds.SetEmpty(); + } + + Invalidate(); + } + } +} \ No newline at end of file diff --git a/Xamarin.Forms.Platform.Android/ViewExtensions.cs b/Xamarin.Forms.Platform.Android/ViewExtensions.cs index ad30a7e7b0a..c9a86fab4b8 100644 --- a/Xamarin.Forms.Platform.Android/ViewExtensions.cs +++ b/Xamarin.Forms.Platform.Android/ViewExtensions.cs @@ -8,6 +8,7 @@ #endif using Android.Util; using Android.Views; +using ARect = Android.Graphics.Rect; using AView = Android.Views.View; using AColor = Android.Graphics.Color; using Android.Graphics; @@ -131,7 +132,7 @@ public static void SetClipToOutline(this AView view, bool value, VisualElement e viewGroup.SetClipChildren(false); // But if IsClippedToBounds is true, they _should_ enforce clipping at their own edges - viewGroup.ClipBounds = shouldClip ? new Rect(0, 0, viewGroup.Width, viewGroup.Height) : null; + viewGroup.ClipBounds = shouldClip ? new ARect(0, 0, viewGroup.Width, viewGroup.Height) : null; } else { diff --git a/Xamarin.Forms.Platform.Android/Xamarin.Forms.Platform.Android.csproj b/Xamarin.Forms.Platform.Android/Xamarin.Forms.Platform.Android.csproj index 1b99c618a8b..a4feca2b714 100644 --- a/Xamarin.Forms.Platform.Android/Xamarin.Forms.Platform.Android.csproj +++ b/Xamarin.Forms.Platform.Android/Xamarin.Forms.Platform.Android.csproj @@ -74,4 +74,7 @@ + + + \ No newline at end of file diff --git a/Xamarin.Forms.Platform.MacOS/Properties/AssemblyInfo.cs b/Xamarin.Forms.Platform.MacOS/Properties/AssemblyInfo.cs index 9434fb423ba..3d22ea44e81 100644 --- a/Xamarin.Forms.Platform.MacOS/Properties/AssemblyInfo.cs +++ b/Xamarin.Forms.Platform.MacOS/Properties/AssemblyInfo.cs @@ -1,6 +1,8 @@ using Xamarin.Forms; using Xamarin.Forms.Internals; using Xamarin.Forms.Platform.MacOS; +using Xamarin.Forms.Shapes; +using Rectangle = Xamarin.Forms.Shapes.Rectangle; [assembly: Dependency(typeof(Deserializer))] [assembly: Dependency(typeof(ResourcesProvider))] @@ -38,6 +40,11 @@ [assembly: ExportRenderer(typeof(TableView), typeof(TableViewRenderer))] [assembly: ExportRenderer(typeof(NativeViewWrapper), typeof(NativeViewWrapperRenderer))] [assembly: ExportRenderer(typeof(Layout), typeof(LayoutRenderer))] +[assembly: ExportRenderer(typeof(Ellipse), typeof(EllipseRenderer))] +[assembly: ExportRenderer(typeof(Line), typeof(LineRenderer))] +[assembly: ExportRenderer(typeof(Polygon), typeof(PolygonRenderer))] +[assembly: ExportRenderer(typeof(Polyline), typeof(PolylineRenderer))] +[assembly: ExportRenderer(typeof(Rectangle), typeof(RectangleRenderer))] [assembly: ExportCell(typeof(Cell), typeof(CellRenderer))] [assembly: ExportCell(typeof(TextCell), typeof(TextCellRenderer))] [assembly: ExportCell(typeof(ImageCell), typeof(ImageCellRenderer))] diff --git a/Xamarin.Forms.Platform.MacOS/Xamarin.Forms.Platform.macOS.csproj b/Xamarin.Forms.Platform.MacOS/Xamarin.Forms.Platform.macOS.csproj index 5b8a7744265..97357caa496 100644 --- a/Xamarin.Forms.Platform.MacOS/Xamarin.Forms.Platform.macOS.csproj +++ b/Xamarin.Forms.Platform.MacOS/Xamarin.Forms.Platform.macOS.csproj @@ -269,6 +269,30 @@ Extensions\FontExtensions.Shared.cs + + Extensions\DoubleCollectionExtensions.cs + + + Extensions\PointCollectionExtensions.cs + + + Shapes\EllipseRenderer.cs + + + Shapes\LineRenderer.cs + + + Shapes\PolygonRenderer.cs + + + Shapes\PolylineRenderer.cs + + + Shapes\RectangleRenderer.cs + + + Shapes\ShapeRenderer.cs + @@ -285,4 +309,7 @@ + + + \ No newline at end of file diff --git a/Xamarin.Forms.Platform.Tizen/Native/Box.cs b/Xamarin.Forms.Platform.Tizen/Native/Box.cs index 515ac84698b..94c0d826732 100644 --- a/Xamarin.Forms.Platform.Tizen/Native/Box.cs +++ b/Xamarin.Forms.Platform.Tizen/Native/Box.cs @@ -1,6 +1,7 @@ using System; using ElmSharp; using EBox = ElmSharp.Box; +using ERect = ElmSharp.Rect; #if __MATERIAL__ using Tizen.NET.MaterialComponents; @@ -34,7 +35,7 @@ public Box(EvasObject parent) : base(parent) /// /// The last processed geometry of the Box which was reported from the native layer. /// - Rect _previousGeometry; + ERect _previousGeometry; /// /// Notifies that the layout has been updated. diff --git a/Xamarin.Forms.Platform.Tizen/Native/CollectionView/CollectionView.cs b/Xamarin.Forms.Platform.Tizen/Native/CollectionView/CollectionView.cs index 06fd6dc7374..0191ff1fee9 100644 --- a/Xamarin.Forms.Platform.Tizen/Native/CollectionView/CollectionView.cs +++ b/Xamarin.Forms.Platform.Tizen/Native/CollectionView/CollectionView.cs @@ -4,6 +4,7 @@ using System.Collections.Generic; using ElmSharp; using EBox = ElmSharp.Box; +using ERect = ElmSharp.Rect; using EScroller = ElmSharp.Scroller; using ESize = ElmSharp.Size; using EPoint = ElmSharp.Point; @@ -123,7 +124,7 @@ int ICollectionViewController.Count protected ESize AllocatedSize { get; set; } - Rect ViewPort => Scroller.CurrentRegion; + ERect ViewPort => Scroller.CurrentRegion; public void ScrollTo(int index, ScrollToPosition position = ScrollToPosition.MakeVisible, bool animate = true) { @@ -491,7 +492,7 @@ void OnCollectionChanged(object sender, NotifyCollectionChangedEventArgs e) RequestLayoutItems(); } - Rect _lastGeometry; + ERect _lastGeometry; void OnLayout() { if (_lastGeometry == Geometry) diff --git a/Xamarin.Forms.Platform.Tizen/Native/CollectionView/GridLayoutManager.cs b/Xamarin.Forms.Platform.Tizen/Native/CollectionView/GridLayoutManager.cs index b9fcc09365c..f5d4c78f146 100644 --- a/Xamarin.Forms.Platform.Tizen/Native/CollectionView/GridLayoutManager.cs +++ b/Xamarin.Forms.Platform.Tizen/Native/CollectionView/GridLayoutManager.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.Linq; using ElmSharp; +using ERect = ElmSharp.Rect; using ESize = ElmSharp.Size; namespace Xamarin.Forms.Platform.Tizen.Native @@ -11,7 +12,7 @@ public class GridLayoutManager : ICollectionViewLayoutManager ESize _allocatedSize; ESize _scrollCanvasSize; bool _isLayouting; - Rect _last; + ERect _last; Dictionary _realizedItem = new Dictionary(); List _itemSizes; @@ -99,7 +100,7 @@ int ColumnSize } } - bool ShouldRearrange(Rect viewport) + bool ShouldRearrange(ERect viewport) { if (_isLayouting) return false; @@ -113,7 +114,7 @@ bool ShouldRearrange(Rect viewport) return false; } - public void LayoutItems(Rect bound, bool force) + public void LayoutItems(ERect bound, bool force) { if (_allocatedSize.Width <= 0 || _allocatedSize.Height <= 0) return; @@ -241,7 +242,7 @@ public void ItemUpdated(int index) } } - public Rect GetItemBound(int index) + public ERect GetItemBound(int index) { int rowIndex = index / Span; int columnIndex = index % Span; @@ -306,8 +307,8 @@ public Rect GetItemBound(int index) } return IsHorizontal ? - new Rect(rowStartPoint, columnStartPoint, itemSize, columnSize) : - new Rect(columnStartPoint, rowStartPoint, columnSize, itemSize); + new ERect(rowStartPoint, columnStartPoint, itemSize, columnSize) : + new ERect(columnStartPoint, rowStartPoint, columnSize, itemSize); } public void Reset() @@ -365,7 +366,7 @@ void InitializeMeasureCache() { _baseItemSize = 0; _scrollCanvasSize = new ESize(0, 0); - _last = new Rect(0, 0, 0, 0); + _last = new ERect(0, 0, 0, 0); if (!_hasUnevenRows) return; @@ -463,12 +464,12 @@ int GetMaxItemSize(int index) } - int GetStartIndex(Rect bound, int itemSize) + int GetStartIndex(ERect bound, int itemSize) { return ViewPortStartPoint(bound) / itemSize * Span; } - int GetStartIndex(Rect bound) + int GetStartIndex(ERect bound) { if (!_hasUnevenRows) { @@ -478,12 +479,12 @@ int GetStartIndex(Rect bound) return FindFirstGreaterOrEqualTo(_accumulatedItemSizes, ViewPortStartPoint(bound)) * Span; } - int GetEndIndex(Rect bound, int itemSize) + int GetEndIndex(ERect bound, int itemSize) { return (int)Math.Ceiling(ViewPortEndPoint(bound) / (double)itemSize) * Span; } - int GetEndIndex(Rect bound) + int GetEndIndex(ERect bound) { if (!_hasUnevenRows) { @@ -493,17 +494,17 @@ int GetEndIndex(Rect bound) return FindFirstGreaterOrEqualTo(_accumulatedItemSizes, ViewPortEndPoint(bound)) * Span; } - int ViewPortStartPoint(Rect viewPort) + int ViewPortStartPoint(ERect viewPort) { return IsHorizontal ? viewPort.X : viewPort.Y; } - int ViewPortEndPoint(Rect viewPort) + int ViewPortEndPoint(ERect viewPort) { return ViewPortStartPoint(viewPort) + ViewPortSize(viewPort); } - int ViewPortSize(Rect viewPort) + int ViewPortSize(ERect viewPort) { return IsHorizontal ? viewPort.Width : viewPort.Height; } diff --git a/Xamarin.Forms.Platform.Tizen/Native/CollectionView/ICollectionViewLayoutManager.cs b/Xamarin.Forms.Platform.Tizen/Native/CollectionView/ICollectionViewLayoutManager.cs index 891fb17b6a9..bdb413e19c4 100644 --- a/Xamarin.Forms.Platform.Tizen/Native/CollectionView/ICollectionViewLayoutManager.cs +++ b/Xamarin.Forms.Platform.Tizen/Native/CollectionView/ICollectionViewLayoutManager.cs @@ -1,4 +1,4 @@ -using ElmSharp; +using ERect = ElmSharp.Rect; using ESize = ElmSharp.Size; namespace Xamarin.Forms.Platform.Tizen.Native @@ -13,9 +13,9 @@ public interface ICollectionViewLayoutManager ESize GetScrollCanvasSize(); - void LayoutItems(Rect bound, bool force = false); + void LayoutItems(ERect bound, bool force = false); - Rect GetItemBound(int index); + ERect GetItemBound(int index); void ItemInserted(int index); diff --git a/Xamarin.Forms.Platform.Tizen/Native/CollectionView/LinearLayoutManager.cs b/Xamarin.Forms.Platform.Tizen/Native/CollectionView/LinearLayoutManager.cs index aca667a69f1..bae21aa0eca 100644 --- a/Xamarin.Forms.Platform.Tizen/Native/CollectionView/LinearLayoutManager.cs +++ b/Xamarin.Forms.Platform.Tizen/Native/CollectionView/LinearLayoutManager.cs @@ -2,16 +2,16 @@ using System.Collections.Generic; using System.Linq; using ElmSharp; +using ERect = ElmSharp.Rect; using ESize = ElmSharp.Size; - namespace Xamarin.Forms.Platform.Tizen.Native { public class LinearLayoutManager : ICollectionViewLayoutManager { ESize _allocatedSize; bool _isLayouting; - Rect _last; + ERect _last; Dictionary _realizedItem = new Dictionary(); List _itemSizes; List _cached; @@ -94,7 +94,7 @@ int BaseItemSize int ItemWidthConstraint => IsHorizontal ? _allocatedSize.Width * 100 : _allocatedSize.Width; int ItemHeightConstraint => IsHorizontal ? _allocatedSize.Height : _allocatedSize.Height * 100; - bool ShouldRearrange(Rect viewport) + bool ShouldRearrange(ERect viewport) { if (_isLayouting) return false; @@ -108,7 +108,7 @@ bool ShouldRearrange(Rect viewport) return false; } - public void LayoutItems(Rect bound, bool force) + public void LayoutItems(ERect bound, bool force) { if (_allocatedSize.Width <= 0 || _allocatedSize.Height <= 0) return; @@ -228,7 +228,7 @@ public void ItemUpdated(int index) } } - public Rect GetItemBound(int index) + public ERect GetItemBound(int index) { int itemSize = 0; int startPoint = 0; @@ -240,7 +240,7 @@ public Rect GetItemBound(int index) } else if (index >= _itemSizes.Count) { - return new Rect(0, 0, 0, 0); + return new ERect(0, 0, 0, 0); } else if (_cached[index]) { @@ -264,8 +264,8 @@ public Rect GetItemBound(int index) } return IsHorizontal ? - new Rect(startPoint, 0, itemSize, _allocatedSize.Height) : - new Rect(0, startPoint, _allocatedSize.Width, itemSize); + new ERect(startPoint, 0, itemSize, _allocatedSize.Height) : + new ERect(0, startPoint, _allocatedSize.Width, itemSize); } public void Reset() @@ -336,12 +336,12 @@ void InitializeMeasureCache() } } - int GetStartIndex(Rect bound, int itemSize) + int GetStartIndex(ERect bound, int itemSize) { return ViewPortStartPoint(bound) / itemSize; } - int GetStartIndex(Rect bound) + int GetStartIndex(ERect bound) { if (!_hasUnevenRows) { @@ -351,12 +351,12 @@ int GetStartIndex(Rect bound) return FindFirstGreaterOrEqualTo(_accumulatedItemSizes, ViewPortStartPoint(bound)); } - int GetEndIndex(Rect bound, int itemSize) + int GetEndIndex(ERect bound, int itemSize) { return (int)Math.Ceiling(ViewPortEndPoint(bound) / (double)itemSize); } - int GetEndIndex(Rect bound) + int GetEndIndex(ERect bound) { if (!_hasUnevenRows) { @@ -366,17 +366,17 @@ int GetEndIndex(Rect bound) return FindFirstGreaterOrEqualTo(_accumulatedItemSizes, ViewPortEndPoint(bound)); } - int ViewPortStartPoint(Rect viewPort) + int ViewPortStartPoint(ERect viewPort) { return IsHorizontal ? viewPort.X : viewPort.Y; } - int ViewPortEndPoint(Rect viewPort) + int ViewPortEndPoint(ERect viewPort) { return ViewPortStartPoint(viewPort) + ViewPortSize(viewPort); } - int ViewPortSize(Rect viewPort) + int ViewPortSize(ERect viewPort) { return IsHorizontal ? viewPort.Width : viewPort.Height; } diff --git a/Xamarin.Forms.Platform.Tizen/Native/LayoutEventArgs.cs b/Xamarin.Forms.Platform.Tizen/Native/LayoutEventArgs.cs index ddad8039936..bb7196b01be 100644 --- a/Xamarin.Forms.Platform.Tizen/Native/LayoutEventArgs.cs +++ b/Xamarin.Forms.Platform.Tizen/Native/LayoutEventArgs.cs @@ -1,5 +1,5 @@ using System; -using ElmSharp; +using ERect = ElmSharp.Rect; namespace Xamarin.Forms.Platform.Tizen.Native { @@ -11,7 +11,7 @@ public class LayoutEventArgs : EventArgs /// /// Geometry of the layout area, absolute coordinate /// - public Rect Geometry + public ERect Geometry { get; internal set; diff --git a/Xamarin.Forms.Platform.Tizen/Native/ListView.cs b/Xamarin.Forms.Platform.Tizen/Native/ListView.cs index 1b5192c1061..58f483d2aa6 100644 --- a/Xamarin.Forms.Platform.Tizen/Native/ListView.cs +++ b/Xamarin.Forms.Platform.Tizen/Native/ListView.cs @@ -4,6 +4,7 @@ using System.ComponentModel; using Xamarin.Forms.Internals; using ElmSharp; +using ERect = ElmSharp.Rect; using EScroller = ElmSharp.Scroller; namespace Xamarin.Forms.Platform.Tizen.Native @@ -112,7 +113,7 @@ protected override IntPtr CreateHandle(EvasObject parent) /// /// Gets the current region in the content object that is visible through the Scroller. /// - public virtual Rect CurrentRegion => Scroller?.CurrentRegion ?? new Rect(); + public virtual ERect CurrentRegion => Scroller?.CurrentRegion ?? new ERect(); /// /// Sets or gets the value of VerticalScrollBarVisibility diff --git a/Xamarin.Forms.Platform.Tizen/Native/RoundRectangle.cs b/Xamarin.Forms.Platform.Tizen/Native/RoundRectangle.cs index 76e4a321276..4a8252b0fcc 100644 --- a/Xamarin.Forms.Platform.Tizen/Native/RoundRectangle.cs +++ b/Xamarin.Forms.Platform.Tizen/Native/RoundRectangle.cs @@ -1,10 +1,12 @@ using System; using System.Collections.Generic; using ElmSharp; +using EPolygon = ElmSharp.Polygon; +using ERect = ElmSharp.Rect; namespace Xamarin.Forms.Platform.Tizen.Native { - public class RoundRectangle : Polygon + public class RoundRectangle : EPolygon { readonly int[] _radius = new int[4]; public RoundRectangle(EvasObject parent) : base(parent) @@ -40,7 +42,7 @@ public void Draw() DrawPoints(); } - public void Draw(Rect bound) + public void Draw(ERect bound) { X = bound.X; Y = bound.Y; diff --git a/Xamarin.Forms.Platform.Tizen/Native/Scroller.cs b/Xamarin.Forms.Platform.Tizen/Native/Scroller.cs index 9838c8d92c8..ab40d0155da 100644 --- a/Xamarin.Forms.Platform.Tizen/Native/Scroller.cs +++ b/Xamarin.Forms.Platform.Tizen/Native/Scroller.cs @@ -1,5 +1,6 @@ using System.Threading.Tasks; using ElmSharp; +using ERect = ElmSharp.Rect; using EScroller = ElmSharp.Scroller; namespace Xamarin.Forms.Platform.Tizen.Native @@ -50,7 +51,7 @@ public Task ScrollToAsync(int horizontalPageIndex, int verticalPageIndex, bool a return animated && _isAnimation ? _animationTaskComplateSource.Task : Task.CompletedTask; } - public Task ScrollToAsync(Rect rect, bool animated) + public Task ScrollToAsync(ERect rect, bool animated) { CheckTaskCompletionSource(); ScrollTo(rect, animated); diff --git a/Xamarin.Forms.Platform.Tizen/Renderers/CarouselPageRenderer.cs b/Xamarin.Forms.Platform.Tizen/Renderers/CarouselPageRenderer.cs index 77e120d4726..99b521b2375 100644 --- a/Xamarin.Forms.Platform.Tizen/Renderers/CarouselPageRenderer.cs +++ b/Xamarin.Forms.Platform.Tizen/Renderers/CarouselPageRenderer.cs @@ -1,5 +1,6 @@ using System; using ElmSharp; +using ERect = ElmSharp.Rect; using ESize = ElmSharp.Size; namespace Xamarin.Forms.Platform.Tizen @@ -113,7 +114,7 @@ void OnInnerLayoutUpdate() _layoutBound = _innerContainer.Geometry.Size; int baseX = _innerContainer.Geometry.X; - Rect bound = _scroller.Geometry; + ERect bound = _scroller.Geometry; int index = 0; foreach (var page in Element.Children) { diff --git a/Xamarin.Forms.Platform.Tizen/Renderers/FrameRenderer.cs b/Xamarin.Forms.Platform.Tizen/Renderers/FrameRenderer.cs index 1db24c8328a..dd80aaab58c 100644 --- a/Xamarin.Forms.Platform.Tizen/Renderers/FrameRenderer.cs +++ b/Xamarin.Forms.Platform.Tizen/Renderers/FrameRenderer.cs @@ -1,5 +1,5 @@ -using ElmSharp; -using EColor = ElmSharp.Color; +using EColor = ElmSharp.Color; +using EPolygon = ElmSharp.Polygon; namespace Xamarin.Forms.Platform.Tizen { @@ -12,8 +12,8 @@ public class FrameRenderer : LayoutRenderer static readonly EColor s_DefaultColor = Device.Idiom == TargetIdiom.TV || Device.Idiom == TargetIdiom.Watch ? EColor.Gray : EColor.Black; static readonly EColor s_ShadowColor = EColor.FromRgba(80, 80, 80, 50); - Polygon _shadow = null; - Polygon _frame = null; + EPolygon _shadow = null; + EPolygon _frame = null; public FrameRenderer() { @@ -27,11 +27,11 @@ protected override void OnElementChanged(ElementChangedEventArgs e) { SetNativeControl(new Native.Canvas(Forms.NativeParent)); - _shadow = new Polygon(NativeView); + _shadow = new EPolygon(NativeView); _shadow.Color = s_ShadowColor; Control.Children.Add(_shadow); - _frame = new Polygon(NativeView); + _frame = new EPolygon(NativeView); _frame.Show(); Control.Children.Add(_frame); Control.LayoutUpdated += OnLayoutUpdated; @@ -51,7 +51,7 @@ protected override void Dispose(bool disposing) base.Dispose(disposing); } - static void DrawFrame(Polygon frame, int left, int top, int right, int bottom, int thickness) + static void DrawFrame(EPolygon frame, int left, int top, int right, int bottom, int thickness) { frame.ClearPoints(); if (left + thickness >= right || top + thickness >= bottom) diff --git a/Xamarin.Forms.Platform.Tizen/Renderers/IVisualElementRenderer.cs b/Xamarin.Forms.Platform.Tizen/Renderers/IVisualElementRenderer.cs index dcddd5d4120..f7bd8ed9e0f 100644 --- a/Xamarin.Forms.Platform.Tizen/Renderers/IVisualElementRenderer.cs +++ b/Xamarin.Forms.Platform.Tizen/Renderers/IVisualElementRenderer.cs @@ -1,5 +1,6 @@ using System; using ElmSharp; +using ERect = ElmSharp.Rect; namespace Xamarin.Forms.Platform.Tizen { @@ -36,6 +37,6 @@ EvasObject NativeView void UpdateLayout(); - Rect GetNativeContentGeometry(); + ERect GetNativeContentGeometry(); } } diff --git a/Xamarin.Forms.Platform.Tizen/Renderers/ImageButtonRenderer.cs b/Xamarin.Forms.Platform.Tizen/Renderers/ImageButtonRenderer.cs index 03ac5408268..0671ef1eba0 100644 --- a/Xamarin.Forms.Platform.Tizen/Renderers/ImageButtonRenderer.cs +++ b/Xamarin.Forms.Platform.Tizen/Renderers/ImageButtonRenderer.cs @@ -1,6 +1,7 @@ using System; using ElmSharp; using EButton = ElmSharp.Button; +using ERect = ElmSharp.Rect; namespace Xamarin.Forms.Platform.Tizen { @@ -104,7 +105,7 @@ void OnLayout() var height = outter.Height - Forms.ConvertToScaledPixel(Element.Padding.VerticalThickness); var left = outter.Left + Forms.ConvertToScaledPixel(Element.Padding.Left); var top = outter.Top + Forms.ConvertToScaledPixel(Element.Padding.Top); - var imageBound = new Rect(left, top, width, height); + var imageBound = new ERect(left, top, width, height); _image.Geometry = imageBound; _button.Geometry = outter; diff --git a/Xamarin.Forms.Platform.Tizen/Renderers/RefreshViewRenderer.cs b/Xamarin.Forms.Platform.Tizen/Renderers/RefreshViewRenderer.cs index 8be1ff07d12..a85e0a27eef 100644 --- a/Xamarin.Forms.Platform.Tizen/Renderers/RefreshViewRenderer.cs +++ b/Xamarin.Forms.Platform.Tizen/Renderers/RefreshViewRenderer.cs @@ -2,6 +2,7 @@ using System; using System.Reflection; using System.Threading.Tasks; +using ERect = ElmSharp.Rect; using TWebView = Tizen.WebView.WebView; namespace Xamarin.Forms.Platform.Tizen @@ -204,7 +205,7 @@ void UpdateRefreshLayout() Control.Children.Add(_refreshLayoutRenderer.NativeView); var measured = _refreshLayout.Measure(Element.Width, Element.Height); var parentBound = NativeView.Geometry; - var bound = new Rect + var bound = new ERect { X = parentBound.X, Y = parentBound.Y, diff --git a/Xamarin.Forms.Platform.Tizen/Renderers/ScrollViewRenderer.cs b/Xamarin.Forms.Platform.Tizen/Renderers/ScrollViewRenderer.cs index d67cc9d8ada..cb517dde4e8 100644 --- a/Xamarin.Forms.Platform.Tizen/Renderers/ScrollViewRenderer.cs +++ b/Xamarin.Forms.Platform.Tizen/Renderers/ScrollViewRenderer.cs @@ -196,7 +196,7 @@ async void OnScrollRequested(object sender, ScrollToRequestedEventArgs e) y = itemPosition.Y; } - Rect region = new Rectangle(x, y, Element.Width, Element.Height).ToPixel(); + ERect region = new Rectangle(x, y, Element.Width, Element.Height).ToPixel(); await Control.ScrollToAsync(region, e.ShouldAnimate); Element.SendScrollFinished(); } diff --git a/Xamarin.Forms.Platform.Tizen/Renderers/SwipeViewRenderer.cs b/Xamarin.Forms.Platform.Tizen/Renderers/SwipeViewRenderer.cs index 29c8825ec88..fcb72951980 100644 --- a/Xamarin.Forms.Platform.Tizen/Renderers/SwipeViewRenderer.cs +++ b/Xamarin.Forms.Platform.Tizen/Renderers/SwipeViewRenderer.cs @@ -2,6 +2,7 @@ using System.Threading.Tasks; using ElmSharp; using Xamarin.Forms.Internals; +using ERect = ElmSharp.Rect; namespace Xamarin.Forms.Platform.Tizen { @@ -320,7 +321,7 @@ void UpdateItems() _itemsRenderer = itemsRenderer; } - static Task AnimatedMove(IAnimatable animatable, EvasObject target, Rect dest, Easing easing = null, uint length = 120) + static Task AnimatedMove(IAnimatable animatable, EvasObject target, ERect dest, Easing easing = null, uint length = 120) { var tcs = new TaskCompletionSource(); @@ -329,7 +330,7 @@ static Task AnimatedMove(IAnimatable animatable, EvasObject target, Rect dest, E new Animation((progress) => { - var toMove = dest; + ERect toMove = dest; toMove.X += (int)(dx * (1 - progress)); toMove.Y += (int)(dy * (1 - progress)); target.Geometry = toMove; diff --git a/Xamarin.Forms.Platform.Tizen/Renderers/TabbedPageRenderer.cs b/Xamarin.Forms.Platform.Tizen/Renderers/TabbedPageRenderer.cs index cb812e656e4..1fe70abf27e 100644 --- a/Xamarin.Forms.Platform.Tizen/Renderers/TabbedPageRenderer.cs +++ b/Xamarin.Forms.Platform.Tizen/Renderers/TabbedPageRenderer.cs @@ -5,6 +5,7 @@ using ElmSharp; using Xamarin.Forms.PlatformConfiguration.TizenSpecific; using EColor = ElmSharp.Color; +using ERect = ElmSharp.Rect; using EToolbarItem = ElmSharp.ToolbarItem; using EToolbarItemEventArgs = ElmSharp.ToolbarItemEventArgs; @@ -164,7 +165,7 @@ void OnInnerLayoutUpdate() return; int baseX = _innerBox.Geometry.X; - Rect bound = _scroller.Geometry; + ERect bound = _scroller.Geometry; int index = 0; foreach (var page in Element.Children) { diff --git a/Xamarin.Forms.Platform.Tizen/Shell/NavigationView.cs b/Xamarin.Forms.Platform.Tizen/Shell/NavigationView.cs index 8b27c0924b6..e17317c5ebf 100644 --- a/Xamarin.Forms.Platform.Tizen/Shell/NavigationView.cs +++ b/Xamarin.Forms.Platform.Tizen/Shell/NavigationView.cs @@ -3,6 +3,7 @@ using ElmSharp; using EColor = ElmSharp.Color; using EImage = ElmSharp.Image; +using ERect = ElmSharp.Rect; using NBox = Xamarin.Forms.Platform.Tizen.Native.Box; namespace Xamarin.Forms.Platform.Tizen @@ -264,9 +265,9 @@ void UpdateChildGeometry() if (_header != null) { headerHeight = _header.MinimumHeight; - _header.Geometry = new Rect(Geometry.X, Geometry.Y, Geometry.Width, headerHeight); + _header.Geometry = new ERect(Geometry.X, Geometry.Y, Geometry.Width, headerHeight); } - _menu.Geometry = new Rect(Geometry.X, Geometry.Y + headerHeight, Geometry.Width, Geometry.Height - headerHeight); + _menu.Geometry = new ERect(Geometry.X, Geometry.Y + headerHeight, Geometry.Width, Geometry.Height - headerHeight); } } diff --git a/Xamarin.Forms.Platform.Tizen/Shell/ShellRenderer.cs b/Xamarin.Forms.Platform.Tizen/Shell/ShellRenderer.cs index 51221de8783..339bdf347e1 100644 --- a/Xamarin.Forms.Platform.Tizen/Shell/ShellRenderer.cs +++ b/Xamarin.Forms.Platform.Tizen/Shell/ShellRenderer.cs @@ -1,5 +1,5 @@ using System; -using ElmSharp; +using ERect = ElmSharp.Rect; namespace Xamarin.Forms.Platform.Tizen { @@ -22,7 +22,7 @@ public ShellRenderer() RegisterPropertyHandler(Shell.FlyoutIsPresentedProperty, UpdateFlyoutIsPresented); } - public override Rect GetNativeContentGeometry() + public override ERect GetNativeContentGeometry() { var rect = base.GetNativeContentGeometry(); rect.X = 0; diff --git a/Xamarin.Forms.Platform.Tizen/Shell/Watch/NavigationDrawer.cs b/Xamarin.Forms.Platform.Tizen/Shell/Watch/NavigationDrawer.cs index 491f6f974b6..1146579b71c 100644 --- a/Xamarin.Forms.Platform.Tizen/Shell/Watch/NavigationDrawer.cs +++ b/Xamarin.Forms.Platform.Tizen/Shell/Watch/NavigationDrawer.cs @@ -7,6 +7,7 @@ using EColor = ElmSharp.Color; using EImage = ElmSharp.Image; using ELayout = ElmSharp.Layout; +using ERect = ElmSharp.Rect; using EWidget = ElmSharp.Widget; namespace Xamarin.Forms.Platform.Tizen.Watch @@ -492,7 +493,7 @@ void ResetIcon() _drawerIcon.Orientation = ImageOrientation.None; } - Task RunMoveAnimation(EvasObject target, Rect dest, uint length, Easing easing = null) + Task RunMoveAnimation(EvasObject target, ERect dest, uint length, Easing easing = null) { var tcs = new TaskCompletionSource(); diff --git a/Xamarin.Forms.Platform.Tizen/Shell/Watch/ShellSectionItemsRenderer.cs b/Xamarin.Forms.Platform.Tizen/Shell/Watch/ShellSectionItemsRenderer.cs index 4df7f519957..e33d4ba6fc9 100644 --- a/Xamarin.Forms.Platform.Tizen/Shell/Watch/ShellSectionItemsRenderer.cs +++ b/Xamarin.Forms.Platform.Tizen/Shell/Watch/ShellSectionItemsRenderer.cs @@ -4,6 +4,7 @@ using System.ComponentModel; using ElmSharp; using ElmSharp.Wearable; +using ERect = ElmSharp.Rect; namespace Xamarin.Forms.Platform.Tizen.Watch { @@ -26,7 +27,7 @@ public class ShellSectionItemsRenderer : IShellItemRenderer List _items = new List(); int _currentIndex = -1; - Rect _lastLayoutBound; + ERect _lastLayoutBound; int _updateByCode; bool _isScrolling; @@ -119,7 +120,7 @@ void UpdateItems() _items.Clear(); _indexIndicator.Clear(); _innerContainer.UnPackAll(); - _lastLayoutBound = default(Rect); + _lastLayoutBound = default(ERect); foreach (var item in ShellSection.Items) { @@ -293,7 +294,7 @@ void OnInnerLayoutUpdate() var layoutBound = _innerContainer.Geometry.Size; int baseX = _innerContainer.Geometry.X; - Rect bound = _scroller.Geometry; + ERect bound = _scroller.Geometry; int index = 0; foreach (var item in _items) { @@ -340,7 +341,7 @@ static string GetItemStyle(int itemCount, int offset) class ItemHolder { public bool IsRealized { get; set; } - public Rect Bound { get; set; } + public ERect Bound { get; set; } public EvasObject NativeView { get; set; } public IndexItem IndexItem { get; set; } public ShellContent Item { get; set; } diff --git a/Xamarin.Forms.Platform.UAP/BoxViewBorderRenderer.cs b/Xamarin.Forms.Platform.UAP/BoxViewBorderRenderer.cs index 7626a5c3508..6da8f89bdab 100644 --- a/Xamarin.Forms.Platform.UAP/BoxViewBorderRenderer.cs +++ b/Xamarin.Forms.Platform.UAP/BoxViewBorderRenderer.cs @@ -2,7 +2,7 @@ using Windows.UI.Xaml; using Windows.UI.Xaml.Automation.Peers; using Windows.UI.Xaml.Controls; -using Windows.UI.Xaml.Shapes; +using WShape = Windows.UI.Xaml.Shapes.Shape; namespace Xamarin.Forms.Platform.UWP { diff --git a/Xamarin.Forms.Platform.UAP/BoxViewRenderer.cs b/Xamarin.Forms.Platform.UAP/BoxViewRenderer.cs index 2bcdae81fdf..09e4ccd930b 100644 --- a/Xamarin.Forms.Platform.UAP/BoxViewRenderer.cs +++ b/Xamarin.Forms.Platform.UAP/BoxViewRenderer.cs @@ -2,7 +2,7 @@ using System.ComponentModel; using Windows.UI.Xaml; using Windows.UI.Xaml.Automation.Peers; -using Windows.UI.Xaml.Shapes; +using WShape = Windows.UI.Xaml.Shapes.Shape; namespace Xamarin.Forms.Platform.UWP { @@ -22,8 +22,8 @@ protected override void OnElementChanged(ElementChangedEventArgs e) DataContext = Element }; - rect.SetBinding(Shape.FillProperty, new Windows.UI.Xaml.Data.Binding { Converter = new ColorConverter(), Path = new PropertyPath("Color") }); - + rect.SetBinding(WShape.FillProperty, new Windows.UI.Xaml.Data.Binding { Converter = new ColorConverter(), Path = new PropertyPath("Color") }); + SetNativeControl(rect); } diff --git a/Xamarin.Forms.Platform.UAP/ButtonRenderer.cs b/Xamarin.Forms.Platform.UAP/ButtonRenderer.cs index c0c32e57926..4f155953145 100644 --- a/Xamarin.Forms.Platform.UAP/ButtonRenderer.cs +++ b/Xamarin.Forms.Platform.UAP/ButtonRenderer.cs @@ -1,14 +1,13 @@ -using System; using System.ComponentModel; using Windows.UI.Xaml; using Windows.UI.Xaml.Controls; using Windows.UI.Xaml.Media; using Windows.UI.Xaml.Media.Imaging; +using Windows.UI.Xaml.Input; using Xamarin.Forms.Internals; -using WThickness = Windows.UI.Xaml.Thickness; -using WButton = Windows.UI.Xaml.Controls.Button; using WImage = Windows.UI.Xaml.Controls.Image; -using Windows.UI.Xaml.Input; +using WStretch = Windows.UI.Xaml.Media.Stretch; +using WThickness = Windows.UI.Xaml.Thickness; namespace Xamarin.Forms.Platform.UWP { @@ -186,7 +185,7 @@ async void UpdateContent() Source = elementImage, VerticalAlignment = VerticalAlignment.Center, HorizontalAlignment = HorizontalAlignment.Center, - Stretch = Stretch.Uniform, + Stretch = WStretch.Uniform, Width = size.Width, Height = size.Height, }; diff --git a/Xamarin.Forms.Platform.UAP/Extensions/AspectExtensions.cs b/Xamarin.Forms.Platform.UAP/Extensions/AspectExtensions.cs index 77b59f0beed..d283b0db922 100644 --- a/Xamarin.Forms.Platform.UAP/Extensions/AspectExtensions.cs +++ b/Xamarin.Forms.Platform.UAP/Extensions/AspectExtensions.cs @@ -1,27 +1,22 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using Windows.UI.Xaml.Media; +using WStretch = Windows.UI.Xaml.Media.Stretch; namespace Xamarin.Forms.Platform.UWP { internal static class AspectExtensions { - public static Stretch ToStretch(this Aspect aspect) + public static WStretch ToStretch(this Aspect aspect) { switch (aspect) { case Aspect.Fill: - return Stretch.Fill; + return WStretch.Fill; case Aspect.AspectFill: - return Stretch.UniformToFill; + return WStretch.UniformToFill; case Aspect.AspectFit: default: - return Stretch.Uniform; + return WStretch.Uniform; } } } diff --git a/Xamarin.Forms.Platform.UAP/Extensions/CollectionViewExtensions.cs b/Xamarin.Forms.Platform.UAP/Extensions/CollectionViewExtensions.cs index 7350fbf9891..de09011b868 100644 --- a/Xamarin.Forms.Platform.UAP/Extensions/CollectionViewExtensions.cs +++ b/Xamarin.Forms.Platform.UAP/Extensions/CollectionViewExtensions.cs @@ -1,12 +1,8 @@ using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using Windows.Foundation; using Windows.UI.Xaml; using Windows.UI.Xaml.Controls; using Windows.UI.Xaml.Controls.Primitives; +using WRect = Windows.Foundation.Rect; namespace Xamarin.Forms.Platform.UWP { @@ -20,8 +16,8 @@ public static bool IsListViewItemVisible(FrameworkElement element, FrameworkElem if (element.Visibility != Visibility.Visible) return false; - var elementBounds = element.TransformToVisual(container).TransformBounds(new Rect(0, 0, element.ActualWidth, element.ActualHeight)); - var containerBounds = new Rect(0, 0, container.ActualWidth, container.ActualHeight); + var elementBounds = element.TransformToVisual(container).TransformBounds(new WRect(0, 0, element.ActualWidth, element.ActualHeight)); + var containerBounds = new WRect(0, 0, container.ActualWidth, container.ActualHeight); switch (itemsLayoutOrientation) { diff --git a/Xamarin.Forms.Platform.UAP/ImageButtonRenderer.cs b/Xamarin.Forms.Platform.UAP/ImageButtonRenderer.cs index b6cab8f2a99..bb8c733ae80 100644 --- a/Xamarin.Forms.Platform.UAP/ImageButtonRenderer.cs +++ b/Xamarin.Forms.Platform.UAP/ImageButtonRenderer.cs @@ -4,11 +4,12 @@ using Windows.UI.Xaml.Media; using Windows.UI.Xaml.Media.Imaging; using Xamarin.Forms.Internals; -using WThickness = Windows.UI.Xaml.Thickness; -using WImage = Windows.UI.Xaml.Controls.Image; using Windows.UI.Xaml.Input; using System.Threading.Tasks; using System.Diagnostics; +using WImage = Windows.UI.Xaml.Controls.Image; +using WStretch = Windows.UI.Xaml.Media.Stretch; +using WThickness = Windows.UI.Xaml.Thickness; namespace Xamarin.Forms.Platform.UWP { @@ -81,7 +82,7 @@ protected async override void OnElementChanged(ElementChangedEventArgs { const int DefaultPadding = 4; + SolidColorBrush _selectedColor; SolidColorBrush _fillColor; - ObservableCollection _dots; + ObservableCollection _dots; public IndicatorViewRenderer() { @@ -87,7 +85,7 @@ void UpdateIndicatorsColor() int i = 0; foreach (var item in (Control as ItemsControl).Items) { - ((Shape)item).Fill = i == position ? _selectedColor : _fillColor; + ((WShape)item).Fill = i == position ? _selectedColor : _fillColor; i++; } } @@ -109,7 +107,7 @@ void CreateIndicators() return; var position = Element.Position; - var indicators = new List(); + var indicators = new List(); if (Element.ItemsSource != null && Element.Count > 0) { @@ -121,16 +119,16 @@ void CreateIndicators() } } - _dots = new ObservableCollection(indicators); + _dots = new ObservableCollection(indicators); (Control as ItemsControl).ItemsSource = _dots; } - Shape CreateIndicator(int i, int position) + WShape CreateIndicator(int i, int position) { var indicatorSize = Element.IndicatorSize; if (Element.IndicatorsShape == IndicatorShape.Circle) { - return new Ellipse() + return new WEllipse() { Fill = i == position ? _selectedColor : _fillColor, Height = indicatorSize, @@ -140,7 +138,7 @@ Shape CreateIndicator(int i, int position) } else { - return new Windows.UI.Xaml.Shapes.Rectangle() + return new WRectangle() { Fill = i == position ? _selectedColor : _fillColor, Height = indicatorSize, diff --git a/Xamarin.Forms.Platform.UAP/LabelRenderer.cs b/Xamarin.Forms.Platform.UAP/LabelRenderer.cs index f0c025390e7..ffe6a83c610 100644 --- a/Xamarin.Forms.Platform.UAP/LabelRenderer.cs +++ b/Xamarin.Forms.Platform.UAP/LabelRenderer.cs @@ -12,6 +12,7 @@ using Xamarin.Forms.Platform.UAP; using Xamarin.Forms.PlatformConfiguration.WindowsSpecific; using Specifics = Xamarin.Forms.PlatformConfiguration.WindowsSpecific.Label; +using WRect = Windows.Foundation.Rect; using WThickness = Windows.UI.Xaml.Thickness; namespace Xamarin.Forms.Platform.UWP @@ -68,7 +69,7 @@ protected override Windows.Foundation.Size ArrangeOverride(Windows.Foundation.Si return finalSize; double childHeight = Math.Max(0, Math.Min(Element.Height, Control.DesiredSize.Height)); - var rect = new Rect(); + var rect = new WRect(); switch (Element.VerticalTextAlignment) { diff --git a/Xamarin.Forms.Platform.UAP/LayoutRenderer.cs b/Xamarin.Forms.Platform.UAP/LayoutRenderer.cs index 805403ccc2a..b32288c1016 100644 --- a/Xamarin.Forms.Platform.UAP/LayoutRenderer.cs +++ b/Xamarin.Forms.Platform.UAP/LayoutRenderer.cs @@ -1,9 +1,9 @@ using System.ComponentModel; -using Windows.Foundation; using Windows.UI; using Windows.UI.Xaml; using Windows.UI.Xaml.Automation.Peers; using Windows.UI.Xaml.Media; +using WRect = Windows.Foundation.Rect; namespace Xamarin.Forms.Platform.UWP { @@ -68,7 +68,7 @@ void UpdateClipToBounds() Clip = null; if (Element.IsClippedToBounds) { - Clip = new RectangleGeometry { Rect = new Rect(0, 0, ActualWidth, ActualHeight) }; + Clip = new RectangleGeometry { Rect = new WRect(0, 0, ActualWidth, ActualHeight) }; } } } diff --git a/Xamarin.Forms.Platform.UAP/ListViewRenderer.cs b/Xamarin.Forms.Platform.UAP/ListViewRenderer.cs index fd90cef88b1..84b8c68b470 100644 --- a/Xamarin.Forms.Platform.UAP/ListViewRenderer.cs +++ b/Xamarin.Forms.Platform.UAP/ListViewRenderer.cs @@ -16,6 +16,7 @@ using WListView = Windows.UI.Xaml.Controls.ListView; using WBinding = Windows.UI.Xaml.Data.Binding; using WApp = Windows.UI.Xaml.Application; +using WRect = Windows.Foundation.Rect; using Xamarin.Forms.Internals; using Xamarin.Forms.PlatformConfiguration.WindowsSpecific; using Specifics = Xamarin.Forms.PlatformConfiguration.WindowsSpecific.ListView; @@ -624,9 +625,9 @@ await Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () => double tHeight = content.DesiredSize.Height; if (toPosition == ScrollToPosition.Center) - semanticLocation.Bounds = new Rect(0, viewportHeight / 2 - tHeight / 2, 0, 0); + semanticLocation.Bounds = new WRect(0, viewportHeight / 2 - tHeight / 2, 0, 0); else - semanticLocation.Bounds = new Rect(0, viewportHeight - tHeight, 0, 0); + semanticLocation.Bounds = new WRect(0, viewportHeight - tHeight, 0, 0); break; } diff --git a/Xamarin.Forms.Platform.UAP/PointCollectionExtensions.cs b/Xamarin.Forms.Platform.UAP/PointCollectionExtensions.cs new file mode 100644 index 00000000000..ea4d366273a --- /dev/null +++ b/Xamarin.Forms.Platform.UAP/PointCollectionExtensions.cs @@ -0,0 +1,36 @@ +using Xamarin.Forms.Shapes; + +#if WINDOWS_UWP +using WPoint = Windows.Foundation.Point; +using WPointCollection = Windows.UI.Xaml.Media.PointCollection; + +namespace Xamarin.Forms.Platform.UWP +#else +using WPoint = System.Windows.Point; +using WPointCollection = System.Windows.Media.PointCollection; + +namespace Xamarin.Forms.Platform.WPF +#endif +{ + public static class PointCollectionExtensions + { + public static WPointCollection ToWindows(this PointCollection pointCollection) + { + if (pointCollection == null || pointCollection.Count == 0) + { + return new WPointCollection(); + } + + WPointCollection points = new WPointCollection(); + Point[] array = new Point[pointCollection.Count]; + pointCollection.CopyTo(array, 0); + + for (int i = 0; i < array.Length; i++) + { + points.Add(new WPoint(array[i].X, array[i].Y)); + } + + return points; + } + } +} \ No newline at end of file diff --git a/Xamarin.Forms.Platform.UAP/Properties/AssemblyInfo.cs b/Xamarin.Forms.Platform.UAP/Properties/AssemblyInfo.cs index fd2c05df08e..e77c26ad91a 100755 --- a/Xamarin.Forms.Platform.UAP/Properties/AssemblyInfo.cs +++ b/Xamarin.Forms.Platform.UAP/Properties/AssemblyInfo.cs @@ -1,6 +1,8 @@ using System.Reflection; using Xamarin.Forms; using Xamarin.Forms.Platform.UWP; +using Xamarin.Forms.Shapes; +using Rectangle = Xamarin.Forms.Shapes.Rectangle; [assembly: Dependency(typeof(WindowsSerializer))] @@ -36,6 +38,11 @@ [assembly: ExportRenderer(typeof(MediaElement), typeof(MediaElementRenderer))] [assembly: ExportRenderer(typeof(RefreshView), typeof(RefreshViewRenderer))] [assembly: ExportRenderer(typeof(Shell), typeof(ShellRenderer))] +[assembly: ExportRenderer(typeof(Ellipse), typeof(EllipseRenderer))] +[assembly: ExportRenderer(typeof(Line), typeof(LineRenderer))] +[assembly: ExportRenderer(typeof(Polygon), typeof(PolygonRenderer))] +[assembly: ExportRenderer(typeof(Polyline), typeof(PolylineRenderer))] +[assembly: ExportRenderer(typeof(Rectangle), typeof(RectangleRenderer))] [assembly: ExportRenderer(typeof(IndicatorView), typeof(IndicatorViewRenderer))] //ImageSources diff --git a/Xamarin.Forms.Platform.UAP/ScrollViewRenderer.cs b/Xamarin.Forms.Platform.UAP/ScrollViewRenderer.cs index 918991ae1ba..82e34730289 100644 --- a/Xamarin.Forms.Platform.UAP/ScrollViewRenderer.cs +++ b/Xamarin.Forms.Platform.UAP/ScrollViewRenderer.cs @@ -1,9 +1,9 @@ using System; using System.ComponentModel; using System.Threading.Tasks; -using Windows.Foundation; using Windows.UI.Xaml; using Windows.UI.Xaml.Controls; +using WRect = Windows.Foundation.Rect; using UwpScrollBarVisibility = Windows.UI.Xaml.Controls.ScrollBarVisibility; namespace Xamarin.Forms.Platform.UWP @@ -32,7 +32,7 @@ protected override Windows.Foundation.Size ArrangeOverride(Windows.Foundation.Si Element.IsInNativeLayout = true; - Control?.Arrange(new Rect(0, 0, finalSize.Width, finalSize.Height)); + Control?.Arrange(new WRect(0, 0, finalSize.Width, finalSize.Height)); Element.IsInNativeLayout = false; diff --git a/Xamarin.Forms.Platform.UAP/Shapes/EllipseRenderer.cs b/Xamarin.Forms.Platform.UAP/Shapes/EllipseRenderer.cs new file mode 100644 index 00000000000..330ab7f1906 --- /dev/null +++ b/Xamarin.Forms.Platform.UAP/Shapes/EllipseRenderer.cs @@ -0,0 +1,25 @@ +using Xamarin.Forms.Shapes; + +#if WINDOWS_UWP +using WEllipse = Windows.UI.Xaml.Shapes.Ellipse; + +namespace Xamarin.Forms.Platform.UWP +#else +using WEllipse = System.Windows.Shapes.Ellipse; + +namespace Xamarin.Forms.Platform.WPF +#endif +{ + public class EllipseRenderer : ShapeRenderer + { + protected override void OnElementChanged(ElementChangedEventArgs args) + { + if (Control == null && args.NewElement != null) + { + SetNativeControl(new WEllipse()); + } + + base.OnElementChanged(args); + } + } +} diff --git a/Xamarin.Forms.Platform.UAP/Shapes/LineRenderer.cs b/Xamarin.Forms.Platform.UAP/Shapes/LineRenderer.cs new file mode 100644 index 00000000000..08d053becaf --- /dev/null +++ b/Xamarin.Forms.Platform.UAP/Shapes/LineRenderer.cs @@ -0,0 +1,68 @@ +using System.ComponentModel; +using Xamarin.Forms.Shapes; + +#if WINDOWS_UWP +using WLine = Windows.UI.Xaml.Shapes.Line; + +namespace Xamarin.Forms.Platform.UWP +#else +using WLine = System.Windows.Shapes.Line; + +namespace Xamarin.Forms.Platform.WPF +#endif +{ + public class LineRenderer : ShapeRenderer + { + protected override void OnElementChanged(ElementChangedEventArgs args) + { + if (Control == null && args.NewElement != null) + { + SetNativeControl(new WLine()); + } + + base.OnElementChanged(args); + + if (args.NewElement != null) + { + UpdateX1(); + UpdateY1(); + UpdateX2(); + UpdateY2(); + } + } + + protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs args) + { + base.OnElementPropertyChanged(sender, args); + + if (args.PropertyName == Line.X1Property.PropertyName) + UpdateX1(); + else if (args.PropertyName == Line.Y1Property.PropertyName) + UpdateY1(); + else if (args.PropertyName == Line.X2Property.PropertyName) + UpdateX2(); + else if (args.PropertyName == Line.Y2Property.PropertyName) + UpdateY2(); + } + + void UpdateX1() + { + Control.X1 = Element.X1; + } + + void UpdateY1() + { + Control.Y1 = Element.Y1; + } + + void UpdateX2() + { + Control.X2 = Element.X2; + } + + void UpdateY2() + { + Control.Y2 = Element.Y2; + } + } +} diff --git a/Xamarin.Forms.Platform.UAP/Shapes/PolygonRenderer.cs b/Xamarin.Forms.Platform.UAP/Shapes/PolygonRenderer.cs new file mode 100644 index 00000000000..b62f29dec60 --- /dev/null +++ b/Xamarin.Forms.Platform.UAP/Shapes/PolygonRenderer.cs @@ -0,0 +1,57 @@ +using System.ComponentModel; +using Xamarin.Forms.Shapes; + +#if WINDOWS_UWP +using WFillRule = Windows.UI.Xaml.Media.FillRule; +using WPolygon = Windows.UI.Xaml.Shapes.Polygon; + +namespace Xamarin.Forms.Platform.UWP +#else +using Xamarin.Forms.Platform.WPF.Extensions; +using WFillRule = System.Windows.Media.FillRule; +using WPolygon = System.Windows.Shapes.Polygon; + +namespace Xamarin.Forms.Platform.WPF +#endif +{ + public class PolygonRenderer : ShapeRenderer + { + protected override void OnElementChanged(ElementChangedEventArgs args) + { + if (Control == null && args.NewElement != null) + { + SetNativeControl(new WPolygon()); + } + + base.OnElementChanged(args); + + if (args.NewElement != null) + { + UpdatePoints(); + UpdateFillRule(); + } + } + + protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs args) + { + base.OnElementPropertyChanged(sender, args); + + if (args.PropertyName == Polygon.PointsProperty.PropertyName) + UpdatePoints(); + else if (args.PropertyName == Polygon.FillRuleProperty.PropertyName) + UpdateFillRule(); + } + + void UpdatePoints() + { + Control.Points = Element.Points.ToWindows(); + } + + void UpdateFillRule() + { + Control.FillRule = Element.FillRule == FillRule.EvenOdd ? + WFillRule.EvenOdd : + WFillRule.Nonzero; + } + } +} \ No newline at end of file diff --git a/Xamarin.Forms.Platform.UAP/Shapes/PolylineRenderer.cs b/Xamarin.Forms.Platform.UAP/Shapes/PolylineRenderer.cs new file mode 100644 index 00000000000..354d791ebfd --- /dev/null +++ b/Xamarin.Forms.Platform.UAP/Shapes/PolylineRenderer.cs @@ -0,0 +1,57 @@ +using System.ComponentModel; +using Xamarin.Forms.Shapes; + +#if WINDOWS_UWP +using WFillRule = Windows.UI.Xaml.Media.FillRule; +using WPolyline = Windows.UI.Xaml.Shapes.Polyline; + +namespace Xamarin.Forms.Platform.UWP +#else +using Xamarin.Forms.Platform.WPF.Extensions; +using WFillRule = System.Windows.Media.FillRule; +using WPolyline = System.Windows.Shapes.Polyline; + +namespace Xamarin.Forms.Platform.WPF +#endif +{ + public class PolylineRenderer : ShapeRenderer + { + protected override void OnElementChanged(ElementChangedEventArgs args) + { + if (Control == null && args.NewElement != null) + { + SetNativeControl(new WPolyline()); + } + + base.OnElementChanged(args); + + if (args.NewElement != null) + { + UpdatePoints(); + UpdateFillRule(); + } + } + + protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs args) + { + base.OnElementPropertyChanged(sender, args); + + if (args.PropertyName == Polyline.PointsProperty.PropertyName) + UpdatePoints(); + else if (args.PropertyName == Polyline.FillRuleProperty.PropertyName) + UpdateFillRule(); + } + + void UpdatePoints() + { + Control.Points = Element.Points.ToWindows(); + } + + void UpdateFillRule() + { + Control.FillRule = Element.FillRule == FillRule.EvenOdd ? + WFillRule.EvenOdd : + WFillRule.Nonzero; + } + } +} \ No newline at end of file diff --git a/Xamarin.Forms.Platform.UAP/Shapes/RectangleRenderer.cs b/Xamarin.Forms.Platform.UAP/Shapes/RectangleRenderer.cs new file mode 100644 index 00000000000..72cb1f89625 --- /dev/null +++ b/Xamarin.Forms.Platform.UAP/Shapes/RectangleRenderer.cs @@ -0,0 +1,52 @@ +using System.ComponentModel; +using Rect = Xamarin.Forms.Shapes.Rectangle; + +#if WINDOWS_UWP +using WRectangle = Windows.UI.Xaml.Shapes.Rectangle; + +namespace Xamarin.Forms.Platform.UWP +#else +using WRectangle = System.Windows.Shapes.Rectangle; + +namespace Xamarin.Forms.Platform.WPF +#endif +{ + public class RectangleRenderer : ShapeRenderer + { + protected override void OnElementChanged(ElementChangedEventArgs args) + { + if (Control == null && args.NewElement != null) + { + SetNativeControl(new WRectangle()); + } + + base.OnElementChanged(args); + + if (args.NewElement != null) + { + UpdateRadiusX(); + UpdateRadiusY(); + } + } + + protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs args) + { + base.OnElementPropertyChanged(sender, args); + + if (args.PropertyName == Rect.RadiusXProperty.PropertyName) + UpdateRadiusX(); + else if (args.PropertyName == Rect.RadiusYProperty.PropertyName) + UpdateRadiusY(); + } + + void UpdateRadiusX() + { + Control.RadiusX = Element.RadiusX; + } + + void UpdateRadiusY() + { + Control.RadiusY = Element.RadiusY; + } + } +} \ No newline at end of file diff --git a/Xamarin.Forms.Platform.UAP/Shapes/ShapeRenderer.cs b/Xamarin.Forms.Platform.UAP/Shapes/ShapeRenderer.cs new file mode 100644 index 00000000000..687be862a08 --- /dev/null +++ b/Xamarin.Forms.Platform.UAP/Shapes/ShapeRenderer.cs @@ -0,0 +1,205 @@ +using System.ComponentModel; +using Xamarin.Forms.Shapes; + +#if WINDOWS_UWP +using Windows.UI.Xaml; +using WDoubleCollection = Windows.UI.Xaml.Media.DoubleCollection; +using WPenLineCap = Windows.UI.Xaml.Media.PenLineCap; +using WPenLineJoin = Windows.UI.Xaml.Media.PenLineJoin; +using WShape = Windows.UI.Xaml.Shapes.Shape; +using WStretch = Windows.UI.Xaml.Media.Stretch; + +namespace Xamarin.Forms.Platform.UWP +#else +using System.Windows; +using WDoubleCollection = System.Windows.Media.DoubleCollection; +using WPenLineCap = System.Windows.Media.PenLineCap; +using WPenLineJoin = System.Windows.Media.PenLineJoin; +using WShape = System.Windows.Shapes.Shape; +using WStretch = System.Windows.Media.Stretch; + +namespace Xamarin.Forms.Platform.WPF +#endif +{ + public class ShapeRenderer : ViewRenderer + where TShape : Shape + where TNativeShape : WShape + { + protected override void OnElementChanged(ElementChangedEventArgs args) + { + base.OnElementChanged(args); + + if (args.NewElement != null) + { + UpdateAspect(); + UpdateFill(); + UpdateStroke(); + UpdateStrokeThickness(); + UpdateStrokeDashArray(); + UpdateStrokeDashOffset(); + UpdateStrokeLineCap(); + UpdateStrokeLineJoin(); + } + } + + protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs args) + { + base.OnElementPropertyChanged(sender, args); + + if (args.PropertyName == VisualElement.HeightProperty.PropertyName) + UpdateHeight(); + else if (args.PropertyName == VisualElement.WidthProperty.PropertyName) + UpdateWidth(); + else if (args.PropertyName == Shape.AspectProperty.PropertyName) + UpdateAspect(); + else if (args.PropertyName == Shape.FillProperty.PropertyName) + UpdateFill(); + else if (args.PropertyName == Shape.StrokeProperty.PropertyName) + UpdateStroke(); + else if (args.PropertyName == Shape.StrokeThicknessProperty.PropertyName) + UpdateStrokeThickness(); + else if (args.PropertyName == Shape.StrokeDashArrayProperty.PropertyName) + UpdateStrokeDashArray(); + else if (args.PropertyName == Shape.StrokeDashOffsetProperty.PropertyName) + UpdateStrokeDashOffset(); + else if (args.PropertyName == Shape.StrokeLineCapProperty.PropertyName) + UpdateStrokeLineCap(); + else if (args.PropertyName == Shape.StrokeLineJoinProperty.PropertyName) + UpdateStrokeLineJoin(); + } + +#if !WINDOWS_UWP + new +#endif + void UpdateHeight() + { + Control.Height = Element.Height; + } + +#if !WINDOWS_UWP + new +#endif + void UpdateWidth() + { + Control.Width = Element.Width; + } + + void UpdateAspect() + { + Stretch aspect = Element.Aspect; + WStretch stretch = WStretch.None; + + switch (aspect) + { + case Stretch.None: + stretch = WStretch.None; + break; + case Stretch.Fill: + stretch = WStretch.Fill; + break; + case Stretch.Uniform: + stretch = WStretch.Uniform; + break; + case Stretch.UniformToFill: + stretch = WStretch.UniformToFill; + break; + } + + Control.Stretch = stretch; + + if (aspect == Stretch.Uniform) + { + Control.HorizontalAlignment = HorizontalAlignment.Center; + Control.VerticalAlignment = VerticalAlignment.Center; + } + else + { + Control.HorizontalAlignment = HorizontalAlignment.Left; + Control.VerticalAlignment = VerticalAlignment.Top; + } + } + + void UpdateFill() + { + Control.Fill = Element.Fill.ToBrush(); + } + + void UpdateStroke() + { + Control.Stroke = Element.Stroke.ToBrush(); + } + + void UpdateStrokeThickness() + { + Control.StrokeThickness = Element.StrokeThickness; + } + + void UpdateStrokeDashArray() + { + if (Control.StrokeDashArray != null) + Control.StrokeDashArray.Clear(); + + if (Element.StrokeDashArray != null && Element.StrokeDashArray.Count > 0) + { + if (Control.StrokeDashArray == null) + Control.StrokeDashArray = new WDoubleCollection(); + + double[] array = new double[Element.StrokeDashArray.Count]; + Element.StrokeDashArray.CopyTo(array, 0); + + foreach (double value in array) + { + Control.StrokeDashArray.Add(value); + } + } + } + + void UpdateStrokeDashOffset() + { + Control.StrokeDashOffset = Element.StrokeDashOffset; + } + + void UpdateStrokeLineCap() + { + PenLineCap lineCap = Element.StrokeLineCap; + WPenLineCap wLineCap = WPenLineCap.Flat; + + switch (lineCap) + { + case PenLineCap.Flat: + wLineCap = WPenLineCap.Flat; + break; + case PenLineCap.Square: + wLineCap = WPenLineCap.Square; + break; + case PenLineCap.Round: + wLineCap = WPenLineCap.Round; + break; + } + + Control.StrokeStartLineCap = wLineCap; + Control.StrokeEndLineCap = wLineCap; + } + + void UpdateStrokeLineJoin() + { + PenLineJoin lineJoin = Element.StrokeLineJoin; + WPenLineJoin wLineJoin = WPenLineJoin.Miter; + + switch (lineJoin) + { + case PenLineJoin.Miter: + wLineJoin = WPenLineJoin.Miter; + break; + case PenLineJoin.Bevel: + wLineJoin = WPenLineJoin.Bevel; + break; + case PenLineJoin.Round: + wLineJoin = WPenLineJoin.Round; + break; + } + + Control.StrokeLineJoin = wLineJoin; + } + } +} \ No newline at end of file diff --git a/Xamarin.Forms.Platform.UAP/SwitchRenderer.cs b/Xamarin.Forms.Platform.UAP/SwitchRenderer.cs index e1aa951f8b9..cdea9d99dba 100644 --- a/Xamarin.Forms.Platform.UAP/SwitchRenderer.cs +++ b/Xamarin.Forms.Platform.UAP/SwitchRenderer.cs @@ -7,6 +7,7 @@ using Windows.UI.Xaml.Shapes; using WColor = Windows.UI.Color; using WGrid = Windows.UI.Xaml.Controls.Grid; +using WEllipse = Windows.UI.Xaml.Shapes.Ellipse; using WRectangle = Windows.UI.Xaml.Shapes.Rectangle; using WVisualStateManager = Windows.UI.Xaml.VisualStateManager; @@ -210,7 +211,7 @@ void UpdateThumbColor() } } - if (grid.FindName(ToggleSwitchKnobOn) is Ellipse thumb) + if (grid.FindName(ToggleSwitchKnobOn) is WEllipse thumb) { if (_originalThumbOnBrush == null) _originalThumbOnBrush = thumb.Fill; diff --git a/Xamarin.Forms.Platform.UAP/ViewToRendererConverter.cs b/Xamarin.Forms.Platform.UAP/ViewToRendererConverter.cs index cc8ca43bf95..da61975c2ae 100644 --- a/Xamarin.Forms.Platform.UAP/ViewToRendererConverter.cs +++ b/Xamarin.Forms.Platform.UAP/ViewToRendererConverter.cs @@ -1,7 +1,7 @@ using System; -using Windows.Foundation; using Windows.UI.Xaml; using Windows.UI.Xaml.Controls; +using WRect = Windows.Foundation.Rect; namespace Xamarin.Forms.Platform.UWP { @@ -89,7 +89,7 @@ protected override Windows.Foundation.Size ArrangeOverride(Windows.Foundation.Si else { Opacity = 1; - FrameworkElement?.Arrange(new Rect(_view.X, _view.Y, _view.Width, _view.Height)); + FrameworkElement?.Arrange(new WRect(_view.X, _view.Y, _view.Width, _view.Height)); } _view.IsInNativeLayout = false; diff --git a/Xamarin.Forms.Platform.UAP/VisualElementRenderer.cs b/Xamarin.Forms.Platform.UAP/VisualElementRenderer.cs index e8069520f7c..44d7e75a167 100644 --- a/Xamarin.Forms.Platform.UAP/VisualElementRenderer.cs +++ b/Xamarin.Forms.Platform.UAP/VisualElementRenderer.cs @@ -1,14 +1,14 @@ using System; using System.Collections.Generic; using System.ComponentModel; -using Windows.Foundation; using Windows.UI.Xaml; using Windows.UI.Xaml.Automation.Peers; using Windows.UI.Xaml.Controls; using Windows.UI.Xaml.Media; -using Specifics = Xamarin.Forms.PlatformConfiguration.WindowsSpecific.VisualElement; using Xamarin.Forms.Internals; using Windows.UI.Xaml.Input; +using Specifics = Xamarin.Forms.PlatformConfiguration.WindowsSpecific.VisualElement; +using WRect = Windows.Foundation.Rect; namespace Xamarin.Forms.Platform.UWP { @@ -205,7 +205,7 @@ protected override Windows.Foundation.Size ArrangeOverride(Windows.Foundation.Si Element.IsInNativeLayout = true; - var myRect = new Rect(0, 0, finalSize.Width, finalSize.Height); + var myRect = new WRect(0, 0, finalSize.Width, finalSize.Height); if (Control != null) { @@ -223,7 +223,7 @@ protected override Windows.Foundation.Size ArrangeOverride(Windows.Foundation.Si continue; Rectangle bounds = child.Bounds; - renderer.ContainerElement.Arrange(new Rect(bounds.X, bounds.Y, Math.Max(0, bounds.Width), Math.Max(0, bounds.Height))); + renderer.ContainerElement.Arrange(new WRect(bounds.X, bounds.Y, Math.Max(0, bounds.Width), Math.Max(0, bounds.Height))); if (ArrangeNativeChildren) { diff --git a/Xamarin.Forms.Platform.UAP/WindowsDeviceInfo.cs b/Xamarin.Forms.Platform.UAP/WindowsDeviceInfo.cs index 2e02b1226cb..ef99a3e7eac 100644 --- a/Xamarin.Forms.Platform.UAP/WindowsDeviceInfo.cs +++ b/Xamarin.Forms.Platform.UAP/WindowsDeviceInfo.cs @@ -1,8 +1,8 @@ using System; -using Windows.Foundation; using Windows.Graphics.Display; using Windows.UI.Xaml; using Xamarin.Forms.Internals; +using WRect = Windows.Foundation.Rect; namespace Xamarin.Forms.Platform.UWP { @@ -37,7 +37,7 @@ public override Size ScaledScreenSize { get { - Rect windowSize = Window.Current.Bounds; + WRect windowSize = Window.Current.Bounds; return new Size(windowSize.Width, windowSize.Height); } } diff --git a/Xamarin.Forms.Platform.WPF/Extensions/ImageExtensions.cs b/Xamarin.Forms.Platform.WPF/Extensions/ImageExtensions.cs index d7427561d8a..9e437a3c23c 100644 --- a/Xamarin.Forms.Platform.WPF/Extensions/ImageExtensions.cs +++ b/Xamarin.Forms.Platform.WPF/Extensions/ImageExtensions.cs @@ -1,28 +1,25 @@ using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; using System.Threading; using System.Threading.Tasks; -using System.Windows.Media; using Xamarin.Forms.Internals; using WImageSource = System.Windows.Media.ImageSource; +using WStretch = System.Windows.Media.Stretch; namespace Xamarin.Forms.Platform.WPF { public static class ImageExtensions { - public static Stretch ToStretch(this Aspect aspect) + public static WStretch ToStretch(this Aspect aspect) { switch (aspect) { case Aspect.Fill: - return Stretch.Fill; + return WStretch.Fill; case Aspect.AspectFill: - return Stretch.UniformToFill; + return WStretch.UniformToFill; default: case Aspect.AspectFit: - return Stretch.Uniform; + return WStretch.Uniform; } } diff --git a/Xamarin.Forms.Platform.WPF/FormsPanel.cs b/Xamarin.Forms.Platform.WPF/FormsPanel.cs index 7e5566c356d..10e61ad5a8b 100644 --- a/Xamarin.Forms.Platform.WPF/FormsPanel.cs +++ b/Xamarin.Forms.Platform.WPF/FormsPanel.cs @@ -1,10 +1,7 @@ using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; using System.Windows; using System.Windows.Controls; +using WRect = System.Windows.Rect; namespace Xamarin.Forms.Platform.WPF { @@ -48,7 +45,7 @@ protected override System.Windows.Size ArrangeOverride(System.Windows.Size final control.Width = width = Math.Ceiling(width / stepX) * stepX; control.Height = height = Math.Ceiling(height / stepY) * stepY; } - control.Arrange(new Rect(bounds.X, bounds.Y, width, height)); + control.Arrange(new WRect(bounds.X, bounds.Y, width, height)); } Element.IsInNativeLayout = false; diff --git a/Xamarin.Forms.Platform.WPF/Properties/AssemblyInfo.cs b/Xamarin.Forms.Platform.WPF/Properties/AssemblyInfo.cs index 33ab2f812a5..00078a6ad1c 100644 --- a/Xamarin.Forms.Platform.WPF/Properties/AssemblyInfo.cs +++ b/Xamarin.Forms.Platform.WPF/Properties/AssemblyInfo.cs @@ -1,8 +1,8 @@ -using System.Reflection; -using System.Runtime.InteropServices; -using System.Windows; +using System.Windows; using Xamarin.Forms; -using Xamarin.Forms.Platform.WPF; +using Xamarin.Forms.Platform.WPF; +using Xamarin.Forms.Shapes; +using Rectangle = Xamarin.Forms.Shapes.Rectangle; [assembly: ThemeInfo(ResourceDictionaryLocation.None, ResourceDictionaryLocation.SourceAssembly)] @@ -33,6 +33,11 @@ [assembly: ExportRenderer(typeof(OpenGLView), typeof(OpenGLViewRenderer))] [assembly: ExportRenderer(typeof(MediaElement), typeof(MediaElementRenderer))] [assembly: ExportRenderer(typeof(ImageButton), typeof(ImageButtonRenderer))] +[assembly: ExportRenderer(typeof(Ellipse), typeof(EllipseRenderer))] +[assembly: ExportRenderer(typeof(Line), typeof(LineRenderer))] +[assembly: ExportRenderer(typeof(Polygon), typeof(PolygonRenderer))] +[assembly: ExportRenderer(typeof(Polyline), typeof(PolylineRenderer))] +[assembly: ExportRenderer(typeof(Rectangle), typeof(RectangleRenderer))] // Control doesn't exist natively in WPF Platform [assembly: ExportRenderer(typeof(TableView), typeof(TableViewRenderer))] diff --git a/Xamarin.Forms.Platform.WPF/Xamarin.Forms.Platform.WPF.csproj b/Xamarin.Forms.Platform.WPF/Xamarin.Forms.Platform.WPF.csproj index 64b46a87806..d7889ae0d3f 100644 --- a/Xamarin.Forms.Platform.WPF/Xamarin.Forms.Platform.WPF.csproj +++ b/Xamarin.Forms.Platform.WPF/Xamarin.Forms.Platform.WPF.csproj @@ -16,6 +16,13 @@ Crc64.cs + + + + + + + Extensions\TextBlockExtensions.cs @@ -24,4 +31,7 @@ + + + diff --git a/Xamarin.Forms.Platform.iOS/Extensions/DoubleCollectionExtensions.cs b/Xamarin.Forms.Platform.iOS/Extensions/DoubleCollectionExtensions.cs new file mode 100644 index 00000000000..c3407c0aa81 --- /dev/null +++ b/Xamarin.Forms.Platform.iOS/Extensions/DoubleCollectionExtensions.cs @@ -0,0 +1,43 @@ +using System; + +#if __MOBILE__ +namespace Xamarin.Forms.Platform.iOS +#else +namespace Xamarin.Forms.Platform.MacOS +#endif +{ + public static class DoubleCollectionExtensions + { + public static nfloat[] ToArray(this DoubleCollection doubleCollection) + { + if (doubleCollection == null || doubleCollection.Count == 0) + return new nfloat[0]; + else + { + nfloat[] dashArray; + double[] array; + + if (doubleCollection.Count % 2 == 0) + { + array = new double[doubleCollection.Count]; + dashArray = new nfloat[doubleCollection.Count]; + doubleCollection.CopyTo(array, 0); + } + else + { + array = new double[2 * doubleCollection.Count]; + dashArray = new nfloat[2 * doubleCollection.Count]; + doubleCollection.CopyTo(array, 0); + doubleCollection.CopyTo(array, doubleCollection.Count); + } + + for (int i = 0; i < array.Length; i++) + { + dashArray[i] = new nfloat(array[i]); + } + + return dashArray; + } + } + } +} \ No newline at end of file diff --git a/Xamarin.Forms.Platform.iOS/Extensions/PointCollectionExtensions.cs b/Xamarin.Forms.Platform.iOS/Extensions/PointCollectionExtensions.cs new file mode 100644 index 00000000000..611c607e6f0 --- /dev/null +++ b/Xamarin.Forms.Platform.iOS/Extensions/PointCollectionExtensions.cs @@ -0,0 +1,31 @@ +using CoreGraphics; +using Xamarin.Forms.Shapes; + +#if __MOBILE__ +namespace Xamarin.Forms.Platform.iOS +#else +namespace Xamarin.Forms.Platform.MacOS +#endif +{ + public static class PointCollectionExtensions + { + public static CGPoint[] ToCGPoints(this PointCollection pointCollection) + { + if (pointCollection == null || pointCollection.Count == 0) + { + return new CGPoint[0]; + } + + CGPoint[] points = new CGPoint[pointCollection.Count]; + Point[] array = new Point[pointCollection.Count]; + pointCollection.CopyTo(array, 0); + + for (int i = 0; i < array.Length; i++) + { + points[i] = new CGPoint(array[i].X, array[i].Y); + } + + return points; + } + } +} \ No newline at end of file diff --git a/Xamarin.Forms.Platform.iOS/Shapes/EllipseRenderer.cs b/Xamarin.Forms.Platform.iOS/Shapes/EllipseRenderer.cs new file mode 100644 index 00000000000..870547c6156 --- /dev/null +++ b/Xamarin.Forms.Platform.iOS/Shapes/EllipseRenderer.cs @@ -0,0 +1,37 @@ +using CoreGraphics; +using Xamarin.Forms.Shapes; + +#if __MOBILE__ +namespace Xamarin.Forms.Platform.iOS +#else +namespace Xamarin.Forms.Platform.MacOS +#endif +{ + public class EllipseRenderer : ShapeRenderer + { + protected override void OnElementChanged(ElementChangedEventArgs args) + { + if (Control == null) + { + SetNativeControl(new EllipseView()); + } + + base.OnElementChanged(args); + } + } + + public class EllipseView : ShapeView + { + public EllipseView() + { + UpdateShape(); + } + + void UpdateShape() + { + var path = new CGPath(); + path.AddEllipseInRect(new CGRect(0, 0, 1, 1)); + ShapeLayer.UpdateShape(path); + } + } +} \ No newline at end of file diff --git a/Xamarin.Forms.Platform.iOS/Shapes/LineRenderer.cs b/Xamarin.Forms.Platform.iOS/Shapes/LineRenderer.cs new file mode 100644 index 00000000000..b3181924962 --- /dev/null +++ b/Xamarin.Forms.Platform.iOS/Shapes/LineRenderer.cs @@ -0,0 +1,103 @@ +using System; +using System.ComponentModel; +using CoreGraphics; +using Xamarin.Forms.Shapes; + +#if __MOBILE__ +namespace Xamarin.Forms.Platform.iOS +#else +namespace Xamarin.Forms.Platform.MacOS +#endif +{ + public class LineRenderer : ShapeRenderer + { + protected override void OnElementChanged(ElementChangedEventArgs args) + { + if (Control == null) + { + SetNativeControl(new LineView()); + } + + base.OnElementChanged(args); + + if (args.NewElement != null) + { + UpdateX1(); + UpdateY1(); + UpdateX2(); + UpdateY2(); + } + } + + protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs args) + { + base.OnElementPropertyChanged(sender, args); + + if (args.PropertyName == Line.X1Property.PropertyName) + UpdateX1(); + else if (args.PropertyName == Line.Y1Property.PropertyName) + UpdateY1(); + else if (args.PropertyName == Line.X2Property.PropertyName) + UpdateX2(); + else if (args.PropertyName == Line.Y2Property.PropertyName) + UpdateY2(); + } + + void UpdateX1() + { + Control.UpdateX1(Element.X1); + } + + void UpdateY1() + { + Control.UpdateY1(Element.Y1); + } + + void UpdateX2() + { + Control.UpdateX2(Element.X2); + } + + void UpdateY2() + { + Control.UpdateY2(Element.Y2); + } + } + + public class LineView : ShapeView + { + nfloat _x1, _y1, _x2, _y2; + + public void UpdateX1(double x1) + { + _x1 = new nfloat(x1); + UpdateShape(); + } + + public void UpdateY1(double y1) + { + _y1 = new nfloat(y1); + UpdateShape(); + } + + public void UpdateX2(double x2) + { + _x2 = new nfloat(x2); + UpdateShape(); + } + + public void UpdateY2(double y2) + { + _y2 = new nfloat(y2); + UpdateShape(); + } + + void UpdateShape() + { + var path = new CGPath(); + path.MoveToPoint(_x1, _y1); + path.AddLineToPoint(_x2, _y2); + ShapeLayer.UpdateShape(path); + } + } +} \ No newline at end of file diff --git a/Xamarin.Forms.Platform.iOS/Shapes/PolygonRenderer.cs b/Xamarin.Forms.Platform.iOS/Shapes/PolygonRenderer.cs new file mode 100644 index 00000000000..a7935c44666 --- /dev/null +++ b/Xamarin.Forms.Platform.iOS/Shapes/PolygonRenderer.cs @@ -0,0 +1,66 @@ +using System.ComponentModel; +using CoreGraphics; +using Xamarin.Forms.Shapes; + +#if __MOBILE__ +namespace Xamarin.Forms.Platform.iOS +#else +namespace Xamarin.Forms.Platform.MacOS +#endif +{ + public class PolygonRenderer : ShapeRenderer + { + protected override void OnElementChanged(ElementChangedEventArgs args) + { + if (Control == null) + { + SetNativeControl(new PolygonView()); + } + + base.OnElementChanged(args); + + if (args.NewElement != null) + { + UpdatePoints(); + UpdateFillRule(); + } + } + + protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs args) + { + base.OnElementPropertyChanged(sender, args); + + if (args.PropertyName == Polygon.PointsProperty.PropertyName) + UpdatePoints(); + else if (args.PropertyName == Polygon.FillRuleProperty.PropertyName) + UpdateFillRule(); + } + + void UpdatePoints() + { + Control.UpdatePoints(Element.Points.ToCGPoints()); + } + + public void UpdateFillRule() + { + Control.UpdateFillMode(Element.FillRule == FillRule.Nonzero); + } + } + + public class PolygonView : ShapeView + { + public void UpdatePoints(CGPoint[] points) + { + var path = new CGPath(); + path.AddLines(points); + path.CloseSubpath(); + + ShapeLayer.UpdateShape(path); + } + + public void UpdateFillMode(bool fillMode) + { + ShapeLayer.UpdateFillMode(fillMode); + } + } +} diff --git a/Xamarin.Forms.Platform.iOS/Shapes/PolylineRenderer.cs b/Xamarin.Forms.Platform.iOS/Shapes/PolylineRenderer.cs new file mode 100644 index 00000000000..59be1873564 --- /dev/null +++ b/Xamarin.Forms.Platform.iOS/Shapes/PolylineRenderer.cs @@ -0,0 +1,64 @@ +using System.ComponentModel; +using CoreGraphics; +using Xamarin.Forms.Shapes; + +#if __MOBILE__ +namespace Xamarin.Forms.Platform.iOS +#else +namespace Xamarin.Forms.Platform.MacOS +#endif +{ + public class PolylineRenderer : ShapeRenderer + { + protected override void OnElementChanged(ElementChangedEventArgs args) + { + if (Control == null) + { + SetNativeControl(new PolylineView()); + } + + base.OnElementChanged(args); + + if (args.NewElement != null) + { + UpdatePoints(); + UpdateFillRule(); + } + } + + protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs args) + { + base.OnElementPropertyChanged(sender, args); + + if (args.PropertyName == Polyline.PointsProperty.PropertyName) + UpdatePoints(); + else if (args.PropertyName == Polyline.FillRuleProperty.PropertyName) + UpdateFillRule(); + } + + void UpdatePoints() + { + Control.UpdatePoints(Element.Points.ToCGPoints()); + } + + public void UpdateFillRule() + { + Control.UpdateFillMode(Element.FillRule == FillRule.Nonzero); + } + } + + public class PolylineView : ShapeView + { + public void UpdatePoints(CGPoint[] points) + { + var path = new CGPath(); + path.AddLines(points); + ShapeLayer.UpdateShape(path); + } + + public void UpdateFillMode(bool fillMode) + { + ShapeLayer.UpdateFillMode(fillMode); + } + } +} diff --git a/Xamarin.Forms.Platform.iOS/Shapes/RectangleRenderer.cs b/Xamarin.Forms.Platform.iOS/Shapes/RectangleRenderer.cs new file mode 100644 index 00000000000..087756e6107 --- /dev/null +++ b/Xamarin.Forms.Platform.iOS/Shapes/RectangleRenderer.cs @@ -0,0 +1,87 @@ +using System; +using System.ComponentModel; +using CoreGraphics; +using Rect = Xamarin.Forms.Shapes.Rectangle; + +#if __MOBILE__ +namespace Xamarin.Forms.Platform.iOS +#else +namespace Xamarin.Forms.Platform.MacOS +#endif +{ + public class RectangleRenderer : ShapeRenderer + { + protected override void OnElementChanged(ElementChangedEventArgs args) + { + if (Control == null) + { + SetNativeControl(new RectView()); + } + + base.OnElementChanged(args); + + if (args.NewElement != null) + { + UpdateRadiusX(); + UpdateRadiusY(); + } + } + + protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs args) + { + base.OnElementPropertyChanged(sender, args); + + if (args.PropertyName == Rect.RadiusXProperty.PropertyName) + UpdateRadiusX(); + else if (args.PropertyName == Rect.RadiusYProperty.PropertyName) + UpdateRadiusY(); + } + + void UpdateRadiusX() + { + Control.UpdateRadiusX(Element.RadiusX / Element.WidthRequest); + } + + void UpdateRadiusY() + { + Control.UpdateRadiusY(Element.RadiusY / Element.HeightRequest); + } + } + + public class RectView : ShapeView + { + public RectView() + { + UpdateShape(); + } + + public nfloat RadiusX { set; get; } + + public nfloat RadiusY { set; get; } + + void UpdateShape() + { + var path = new CGPath(); + path.AddRoundedRect(new CGRect(0, 0, 1, 1), RadiusX, RadiusY); + ShapeLayer.UpdateShape(path); + } + + public void UpdateRadiusX(double radiusX) + { + if (double.IsInfinity(radiusX)) + return; + + RadiusX = new nfloat(radiusX); + UpdateShape(); + } + + public void UpdateRadiusY(double radiusY) + { + if (double.IsInfinity(radiusY)) + return; + + RadiusY = new nfloat(radiusY); + UpdateShape(); + } + } +} \ No newline at end of file diff --git a/Xamarin.Forms.Platform.iOS/Shapes/ShapeRenderer.cs b/Xamarin.Forms.Platform.iOS/Shapes/ShapeRenderer.cs new file mode 100644 index 00000000000..139b946fc80 --- /dev/null +++ b/Xamarin.Forms.Platform.iOS/Shapes/ShapeRenderer.cs @@ -0,0 +1,446 @@ +using System; +using System.ComponentModel; +using CoreAnimation; +using CoreGraphics; +using Xamarin.Forms.Shapes; + +#if __MOBILE__ +using UIKit; + +namespace Xamarin.Forms.Platform.iOS +#else +using AppKit; + +namespace Xamarin.Forms.Platform.MacOS +#endif +{ + public class ShapeRenderer : ViewRenderer + where TShape : Shape + where TNativeShape : ShapeView + { + double _height; + double _width; + + protected override void OnElementChanged(ElementChangedEventArgs args) + { + base.OnElementChanged(args); + + if (args.NewElement != null) + { + UpdateAspect(); + UpdateFill(); + UpdateStroke(); + UpdateStrokeThickness(); + UpdateStrokeDashArray(); + UpdateStrokeDashOffset(); + UpdateStrokeLineCap(); + UpdateStrokeLineJoin(); + } + } + + protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs args) + { + base.OnElementPropertyChanged(sender, args); + + if (args.PropertyName == VisualElement.HeightProperty.PropertyName) + { + _height = Element.Height; + UpdateSize(); + } + else if (args.PropertyName == VisualElement.WidthProperty.PropertyName) + { + _width = Element.Width; + UpdateSize(); + } + else if (args.PropertyName == Shape.AspectProperty.PropertyName) + UpdateAspect(); + else if (args.PropertyName == Shape.FillProperty.PropertyName) + UpdateFill(); + else if (args.PropertyName == Shape.StrokeProperty.PropertyName) + UpdateStroke(); + else if (args.PropertyName == Shape.StrokeThicknessProperty.PropertyName) + UpdateStrokeThickness(); + else if (args.PropertyName == Shape.StrokeDashArrayProperty.PropertyName) + UpdateStrokeDashArray(); + else if (args.PropertyName == Shape.StrokeDashOffsetProperty.PropertyName) + UpdateStrokeDashOffset(); + else if (args.PropertyName == Shape.StrokeLineCapProperty.PropertyName) + UpdateStrokeLineCap(); + else if (args.PropertyName == Shape.StrokeLineJoinProperty.PropertyName) + UpdateStrokeLineJoin(); + } + + public override SizeRequest GetDesiredSize(double widthConstraint, double heightConstraint) + { + if (Control != null) + { + return Control.ShapeLayer.GetDesiredSize(); + } + + return base.GetDesiredSize(widthConstraint, heightConstraint); + } + + void UpdateAspect() + { + Control.ShapeLayer.UpdateAspect(Element.Aspect); + } + + void UpdateSize() + { + Control.ShapeLayer.UpdateSize(new CGSize(new nfloat(_width), new nfloat(_height))); + } + + void UpdateFill() + { + Control.ShapeLayer.UpdateFill(Element.Fill.ToCGColor()); + } + + void UpdateStroke() + { + Control.ShapeLayer.UpdateStroke(Element.Stroke.ToCGColor()); + } + + void UpdateStrokeThickness() + { + Control.ShapeLayer.UpdateStrokeThickness(Element.StrokeThickness); + } + + void UpdateStrokeDashArray() + { + Control.ShapeLayer.UpdateStrokeDash(Element.StrokeDashArray.ToArray()); + } + + void UpdateStrokeDashOffset() + { + Control.ShapeLayer.UpdateStrokeDashOffset((nfloat)Element.StrokeDashOffset); + } + + void UpdateStrokeLineCap() + { + PenLineCap lineCap = Element.StrokeLineCap; + CGLineCap iLineCap = CGLineCap.Butt; + + switch (lineCap) + { + case PenLineCap.Flat: + iLineCap = CGLineCap.Butt; + break; + case PenLineCap.Square: + iLineCap = CGLineCap.Square; + break; + case PenLineCap.Round: + iLineCap = CGLineCap.Round; + break; + } + + Control.ShapeLayer.UpdateStrokeLineCap(iLineCap); + } + + void UpdateStrokeLineJoin() + { + PenLineJoin lineJoin = Element.StrokeLineJoin; + CGLineJoin iLineJoin = CGLineJoin.Miter; + + switch (lineJoin) + { + case PenLineJoin.Miter: + iLineJoin = CGLineJoin.Miter; + break; + case PenLineJoin.Bevel: + iLineJoin = CGLineJoin.Bevel; + break; + case PenLineJoin.Round: + iLineJoin = CGLineJoin.Round; + break; + } + + Control.ShapeLayer.UpdateStrokeLineJoin(iLineJoin); + } + } + + public class ShapeView +#if __MOBILE__ + : UIView +#else + : NSView +#endif + { + public ShapeView() + { +#if __MOBILE__ + BackgroundColor = UIColor.Clear; +#else + WantsLayer = true; +#endif + ShapeLayer = new ShapeLayer(); + Layer.AddSublayer(ShapeLayer); + Layer.MasksToBounds = false; + } + + public ShapeLayer ShapeLayer + { + private set; + get; + } + +#if !__MOBILE__ + public override bool IsFlipped => true; +#endif + } + + public class ShapeLayer : CALayer + { + const float StrokeMiterLimit = 10f; + + CGPath _path; + CGRect _pathFillBounds; + CGRect _pathStrokeBounds; + + CGPath _renderPath; + + bool _fillMode; + + CGColor _stroke; + CGColor _fill; + + nfloat _strokeWidth; + nfloat[] _strokeDash; + nfloat _dashOffset; + + Stretch _stretch; + + CGLineCap _strokeLineCap; + CGLineJoin _strokeLineJoin; + + public ShapeLayer() + { + _fillMode = false; + _stretch = Stretch.None; + _strokeLineCap = CGLineCap.Butt; + _strokeLineJoin = CGLineJoin.Miter; + } + + public override void DrawInContext(CGContext ctx) + { + base.DrawInContext(ctx); + RenderShape(ctx); + } + + public void UpdateShape(CGPath path) + { + _path = path; + + if (_path != null) + _pathFillBounds = _path.PathBoundingBox; + else + _pathFillBounds = new CGRect(); + + UpdatePathStrokeBounds(); + } + + public void UpdateFillMode(bool fillMode) + { + _fillMode = fillMode; + SetNeedsDisplay(); + } + + public SizeRequest GetDesiredSize() + { + return new SizeRequest(new Size( + Math.Max(0, _pathStrokeBounds.Right), + Math.Max(0, _pathStrokeBounds.Bottom))); + } + + public void UpdateSize(CGSize size) + { + Bounds = new CGRect(new CGPoint(), size); + BuildRenderPath(); + } + + public void UpdateAspect(Stretch stretch) + { + _stretch = stretch; + BuildRenderPath(); + } + + public void UpdateFill(CGColor fill) + { + _fill = fill; + SetNeedsDisplay(); + } + + public void UpdateStroke(CGColor stroke) + { + _stroke = stroke; + SetNeedsDisplay(); + } + + public void UpdateStrokeThickness(double strokeWidth) + { + _strokeWidth = new nfloat(strokeWidth); + BuildRenderPath(); + } + + public void UpdateStrokeDash(nfloat[] dash) + { + _strokeDash = dash; + SetNeedsDisplay(); + } + + public void UpdateStrokeDashOffset(nfloat dashOffset) + { + _dashOffset = dashOffset; + SetNeedsDisplay(); + } + + public void UpdateStrokeLineCap(CGLineCap strokeLineCap) + { + _strokeLineCap = strokeLineCap; + UpdatePathStrokeBounds(); + SetNeedsDisplay(); + } + + public void UpdateStrokeLineJoin(CGLineJoin strokeLineJoin) + { + _strokeLineJoin = strokeLineJoin; + UpdatePathStrokeBounds(); + SetNeedsDisplay(); + } + + void BuildRenderPath() + { + if (_path == null) + { + _renderPath = null; + return; + } + + CATransaction.Begin(); + CATransaction.DisableActions = true; + + if (_stretch != Stretch.None) + { + CGRect viewBounds = Bounds; + viewBounds.X += _strokeWidth / 2; + viewBounds.Y += _strokeWidth / 2; + viewBounds.Width -= _strokeWidth; + viewBounds.Height -= _strokeWidth; + + nfloat widthScale = viewBounds.Width / _pathFillBounds.Width; + nfloat heightScale = viewBounds.Height / _pathFillBounds.Height; + var stretchTransform = CGAffineTransform.MakeIdentity(); + + switch (_stretch) + { + case Stretch.None: + break; + + case Stretch.Fill: + stretchTransform.Scale(widthScale, heightScale); + + stretchTransform.Translate( + viewBounds.Left - widthScale * _pathFillBounds.Left, + viewBounds.Top - heightScale * _pathFillBounds.Top); + break; + + case Stretch.Uniform: + nfloat minScale = NMath.Min(widthScale, heightScale); + + stretchTransform.Scale(minScale, minScale); + + stretchTransform.Translate( + viewBounds.Left - minScale * _pathFillBounds.Left + + (viewBounds.Width - minScale * _pathFillBounds.Width) / 2, + viewBounds.Top - minScale * _pathFillBounds.Top + + (viewBounds.Height - minScale * _pathFillBounds.Height) / 2); + break; + + case Stretch.UniformToFill: + nfloat maxScale = NMath.Max(widthScale, heightScale); + + stretchTransform.Scale(maxScale, maxScale); + + stretchTransform.Translate( + viewBounds.Left - maxScale * _pathFillBounds.Left, + viewBounds.Top - maxScale * _pathFillBounds.Top); + break; + } + + Frame = Bounds; + _renderPath = _path.CopyByTransformingPath(stretchTransform); + } + else + { + nfloat adjustX = NMath.Min(0, _pathStrokeBounds.X); + nfloat adjustY = NMath.Min(0, _pathStrokeBounds.Y); + + if (adjustX < 0 || adjustY < 0) + { + nfloat width = Bounds.Width; + nfloat height = Bounds.Height; + + if (_pathStrokeBounds.Width > Bounds.Width) + width = Bounds.Width - adjustX; + if (_pathStrokeBounds.Height > Bounds.Height) + height = Bounds.Height - adjustY; + + Frame = new CGRect(adjustX, adjustY, width, height); + var transform = new CGAffineTransform(Bounds.Width / width, 0, 0, Bounds.Height / height, -adjustX, -adjustY); + _renderPath = _path.CopyByTransformingPath(transform); + } + else + { + Frame = Bounds; + _renderPath = _path.CopyByTransformingPath(CGAffineTransform.MakeIdentity()); + } + } + + CATransaction.Commit(); + + SetNeedsDisplay(); + } + + void RenderShape(CGContext graphics) + { + if (_path == null) + return; + + if (_stroke == null && _fill == null) + return; + + CATransaction.Begin(); + CATransaction.DisableActions = true; + + var lengths = new nfloat[0]; + + if (_strokeDash.Length > 0) + lengths = new nfloat[_strokeDash.Length]; + + for (int i = 0; i < _strokeDash.Length; i++) + lengths[i] = new nfloat(_dashOffset * _strokeDash[i]); + + graphics.SetLineWidth(_strokeWidth); + graphics.SetLineDash(_dashOffset * _strokeWidth, lengths); + graphics.SetLineCap(_strokeLineCap); + graphics.SetLineJoin(_strokeLineJoin); + graphics.SetMiterLimit(StrokeMiterLimit * _strokeWidth / 4); + + graphics.AddPath(_renderPath); + graphics.SetStrokeColor(_stroke); + graphics.SetFillColor(_fill); + graphics.DrawPath(_fillMode ? CGPathDrawingMode.FillStroke : CGPathDrawingMode.EOFillStroke); + + CATransaction.Commit(); + } + + void UpdatePathStrokeBounds() + { + if (_path != null) + _pathStrokeBounds = _path.CopyByStrokingPath(_strokeWidth, _strokeLineCap, _strokeLineJoin, StrokeMiterLimit).PathBoundingBox; + else + _pathStrokeBounds = new CGRect(); + + BuildRenderPath(); + } + } +} \ No newline at end of file diff --git a/Xamarin.Forms.Platform.iOS/Xamarin.Forms.Platform.iOS.csproj b/Xamarin.Forms.Platform.iOS/Xamarin.Forms.Platform.iOS.csproj index 2d543173fd8..278c46a3e3b 100644 --- a/Xamarin.Forms.Platform.iOS/Xamarin.Forms.Platform.iOS.csproj +++ b/Xamarin.Forms.Platform.iOS/Xamarin.Forms.Platform.iOS.csproj @@ -262,8 +262,16 @@ + + + + + + + + @@ -320,4 +328,7 @@ + + + \ No newline at end of file diff --git a/Xamarin.Forms.Platform/Xamarin.Forms.Platform.cs b/Xamarin.Forms.Platform/Xamarin.Forms.Platform.cs index baf9fe21adb..7f698726023 100644 --- a/Xamarin.Forms.Platform/Xamarin.Forms.Platform.cs +++ b/Xamarin.Forms.Platform/Xamarin.Forms.Platform.cs @@ -146,4 +146,24 @@ internal class _MediaElementRenderer internal class _SwipeViewRenderer { } + + internal class _EllipseRenderer + { + } + + internal class _LineRenderer + { + } + + internal class _RectangleRenderer + { + } + + internal class _PolylineRenderer + { + } + + internal class _PolygonRenderer + { + } } \ No newline at end of file