From d6ddd53ed551f85712bb244b74bac27c7dc643f7 Mon Sep 17 00:00:00 2001 From: Seungkeun Lee Date: Fri, 16 Nov 2018 20:00:45 +0900 Subject: [PATCH] Add ImageButton Renderer on Tizen (#4436) --- .../Native/BorderRectangle.cs | 84 ++++++++ .../Native/RoundRectangle.cs | 10 +- .../Properties/AssemblyInfo.cs | 1 + .../Renderers/ImageButtonRenderer.cs | 183 ++++++++++++++++++ 4 files changed, 276 insertions(+), 2 deletions(-) create mode 100644 Xamarin.Forms.Platform.Tizen/Native/BorderRectangle.cs create mode 100644 Xamarin.Forms.Platform.Tizen/Renderers/ImageButtonRenderer.cs diff --git a/Xamarin.Forms.Platform.Tizen/Native/BorderRectangle.cs b/Xamarin.Forms.Platform.Tizen/Native/BorderRectangle.cs new file mode 100644 index 000000000..ff8879c7b --- /dev/null +++ b/Xamarin.Forms.Platform.Tizen/Native/BorderRectangle.cs @@ -0,0 +1,84 @@ +using System; +using System.Collections.Generic; +using ElmSharp; + +namespace Xamarin.Forms.Platform.Tizen.Native +{ + public class BorderRectangle : RoundRectangle + { + public BorderRectangle(EvasObject parent) : base(parent) { } + + public int BorderWidth { get; set; } + + protected override void DrawPoints() + { + ClearPoints(); + if (BorderWidth > 0) + { + IReadOnlyList radius = GetRadius(); + DrawRect(radius[0], radius[1], radius[2], radius[3], + 0, 0, Width, Height); + DrawRect(Math.Max(radius[0] - BorderWidth, 0), + Math.Max(radius[1] - BorderWidth, 0), + Math.Max(radius[2] - BorderWidth, 0), + Math.Max(radius[3] - BorderWidth, 0), + BorderWidth, BorderWidth, Width - BorderWidth * 2, Height - BorderWidth * 2); + } + } + + protected void DrawRect(int topLeft, int topRight, int bottomLeft, int bottomRight, int startX, int startY, int width, int height) + { + int[] radius = new int[4]; + int maxR = Math.Min(width / 2, height / 2); + radius[0] = Math.Min(topLeft, maxR); + radius[1] = Math.Min(topRight, maxR); + radius[2] = Math.Min(bottomLeft, maxR); + radius[3] = Math.Min(bottomRight, maxR); + + Point first = new Point(-1, -1); + for (int i = 0; i <= radius[0]; i++) + { + int x = i; + int dx = radius[0] - x; + int y = radius[0] - (int)Math.Sqrt((radius[0] * radius[0]) - (dx * dx)); + AddRelativePoint(startX + x, startY + y); + if (first.X < 0 && first.Y < 0) + { + first.X = startX + x; + first.Y = startY + y; + } + } + + AddRelativePoint(startX + width - radius[1], startY); + + for (int i = width - radius[1]; i <= width; i++) + { + int x = i; + int dx = radius[1] - (width - x); + int y = radius[1] - (int)Math.Sqrt((radius[1] * radius[1]) - (dx * dx)); + AddRelativePoint(startX + x, startY + y); + } + + AddRelativePoint(startX + width, startY + height - radius[3]); + + for (int i = width; i >= width - radius[3]; i--) + { + int x = i; + int dx = radius[3] - (width - x); + int y = height - radius[3] + (int)Math.Sqrt((radius[3] * radius[3]) - (dx * dx)); + AddRelativePoint(startX + x, startY + y); + } + + AddRelativePoint(startX + radius[2], startY + height); + + for (int i = radius[2]; i >= 0; i--) + { + int x = i; + int dx = radius[2] - x; + int y = height - radius[2] + (int)Math.Sqrt((radius[2] * radius[2]) - (dx * dx)); + AddRelativePoint(startX + x, startY + y); + } + AddRelativePoint((int)first.X, (int)first.Y); + } + } +} diff --git a/Xamarin.Forms.Platform.Tizen/Native/RoundRectangle.cs b/Xamarin.Forms.Platform.Tizen/Native/RoundRectangle.cs index 0f6b581de..76e4a3212 100644 --- a/Xamarin.Forms.Platform.Tizen/Native/RoundRectangle.cs +++ b/Xamarin.Forms.Platform.Tizen/Native/RoundRectangle.cs @@ -1,11 +1,12 @@ using System; +using System.Collections.Generic; using ElmSharp; namespace Xamarin.Forms.Platform.Tizen.Native { public class RoundRectangle : Polygon { - int[] _radius = new int[4]; + readonly int[] _radius = new int[4]; public RoundRectangle(EvasObject parent) : base(parent) { } @@ -29,6 +30,11 @@ namespace Xamarin.Forms.Platform.Tizen.Native _radius[3] = bottomRight; } + public IReadOnlyList GetRadius() + { + return _radius; + } + public void Draw() { DrawPoints(); @@ -96,7 +102,7 @@ namespace Xamarin.Forms.Platform.Tizen.Native } } - void AddRelativePoint(int x, int y) + protected void AddRelativePoint(int x, int y) { AddPoint(X + x, Y + y); } diff --git a/Xamarin.Forms.Platform.Tizen/Properties/AssemblyInfo.cs b/Xamarin.Forms.Platform.Tizen/Properties/AssemblyInfo.cs index 8eb7b8dce..9f5d23533 100644 --- a/Xamarin.Forms.Platform.Tizen/Properties/AssemblyInfo.cs +++ b/Xamarin.Forms.Platform.Tizen/Properties/AssemblyInfo.cs @@ -35,6 +35,7 @@ using System.Reflection; [assembly: ExportRenderer(typeof(TableView), typeof(TableViewRenderer))] [assembly: ExportRenderer(typeof(NativeViewWrapper), typeof(NativeViewWrapperRenderer))] [assembly: ExportRenderer(typeof(WebView), typeof(WebViewRenderer))] +[assembly: ExportRenderer(typeof(ImageButton), typeof(ImageButtonRenderer))] [assembly: ExportImageSourceHandler(typeof(FileImageSource), typeof(FileImageSourceHandler))] [assembly: ExportImageSourceHandler(typeof(StreamImageSource), typeof(StreamImageSourceHandler))] diff --git a/Xamarin.Forms.Platform.Tizen/Renderers/ImageButtonRenderer.cs b/Xamarin.Forms.Platform.Tizen/Renderers/ImageButtonRenderer.cs new file mode 100644 index 000000000..ad75d4a96 --- /dev/null +++ b/Xamarin.Forms.Platform.Tizen/Renderers/ImageButtonRenderer.cs @@ -0,0 +1,183 @@ +using System; +using ElmSharp; +using EButton = ElmSharp.Button; + +namespace Xamarin.Forms.Platform.Tizen +{ + public class ImageButtonRenderer : ViewRenderer + { + public ImageButtonRenderer() + { + RegisterPropertyHandler(ImageButton.SourceProperty, UpdateSource); + RegisterPropertyHandler(ImageButton.PaddingProperty, UpdatePadding); + RegisterPropertyHandler(ImageButton.CornerRadiusProperty, UpdateRadius); + RegisterPropertyHandler(ImageButton.BorderWidthProperty, UpdateBorderWidth); + RegisterPropertyHandler(ImageButton.BorderColorProperty, UpdateBorderColor); + RegisterPropertyHandler(ImageButton.AspectProperty, UpdateAspect); + } + + Native.Image _image; + EButton _button; + Native.RoundRectangle _round; + Native.BorderRectangle _border; + protected override void OnElementChanged(ElementChangedEventArgs e) + { + if (Control == null) + { + SetNativeControl(new Box(Forms.NativeParent)); + Control.SetLayoutCallback(OnLayout); + _round = new Native.RoundRectangle(Forms.NativeParent); + _round.Show(); + _border = new Native.BorderRectangle(Forms.NativeParent); + _border.Show(); + _image = new Native.Image(Forms.NativeParent); + _image.Show(); + _button = new EButton(Forms.NativeParent) + { + Style = "transparent" + }; + _button.Clicked += OnClicked; + _button.Pressed += OnPressed; + _button.Released += OnReleased; + _button.Show(); + Control.PackEnd(_round); + Control.PackEnd(_image); + Control.PackEnd(_border); + Control.PackEnd(_button); + } + base.OnElementChanged(e); + } + + protected virtual void UpdateAfterLoading() + { + _image.IsOpaque = Element.IsOpaque; + } + + protected override ElmSharp.Size Measure(int availableWidth, int availableHeight) + { + var size = _image.Measure(availableHeight, availableHeight); + size.Width += Forms.ConvertToScaledPixel(Element.Padding.HorizontalThickness); + size.Height += Forms.ConvertToScaledPixel(Element.Padding.VerticalThickness); + return size; + } + + protected override void UpdateBackgroundColor(bool initialize) + { + _round.Color = Element.BackgroundColor.ToNative(); + } + + protected override void Dispose(bool disposing) + { + if (disposing) + { + if (_button != null) + { + _button.Clicked -= OnClicked; + _button.Pressed -= OnPressed; + _button.Released -= OnReleased; + _button = null; + } + } + base.Dispose(disposing); + } + + void OnReleased(object sender, EventArgs e) + { + (Element as IButtonController)?.SendReleased(); + } + + void OnPressed(object sender, EventArgs e) + { + (Element as IButtonController)?.SendPressed(); + } + + void OnClicked(object sender, EventArgs e) + { + (Element as IButtonController)?.SendClicked(); + } + + void OnLayout() + { + var outter = Control.Geometry; + var width = outter.Width - Forms.ConvertToScaledPixel(Element.Padding.HorizontalThickness); + 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); + + _image.Geometry = imageBound; + _button.Geometry = outter; + _round.Draw(outter); + _border.Draw(outter); + } + + void UpdatePadding() + { + Control.MarkChanged(); + } + + async void UpdateSource() + { + ImageSource source = Element.Source; + (Element as IImageController)?.SetIsLoading(true); + + if (Control != null) + { + bool success = await _image.LoadFromImageSourceAsync(source); + if (!IsDisposed && success) + { + (Element as IVisualElementController)?.NativeSizeChanged(); + UpdateAfterLoading(); + } + } + + if (!IsDisposed) + ((IImageController)Element).SetIsLoading(false); + } + + void UpdateRadius(bool init) + { + if (Element.CornerRadius > 0) + { + _round.SetRadius(Forms.ConvertToScaledPixel(Element.CornerRadius)); + _border.SetRadius(Forms.ConvertToScaledPixel(Element.CornerRadius)); + } + else + { + _round.SetRadius(0); + _border.SetRadius(0); + } + if (!init) + { + _round.Draw(); + _border.Draw(); + } + } + + void UpdateBorderWidth(bool init) + { + if (Element.BorderWidth > 0) + { + _border.BorderWidth = Forms.ConvertToScaledPixel(Element.BorderWidth); + } + else + { + _border.BorderWidth = 0; + } + if (!init) + { + _border.Draw(); + } + } + + void UpdateBorderColor() + { + _border.Color = Element.BorderColor.ToNative(); + } + + void UpdateAspect() + { + _image.Aspect = Element.Aspect; + } + } +}