summaryrefslogtreecommitdiff
path: root/Xamarin.Forms.Platform.MacOS/Platform.cs
diff options
context:
space:
mode:
Diffstat (limited to 'Xamarin.Forms.Platform.MacOS/Platform.cs')
-rw-r--r--Xamarin.Forms.Platform.MacOS/Platform.cs262
1 files changed, 262 insertions, 0 deletions
diff --git a/Xamarin.Forms.Platform.MacOS/Platform.cs b/Xamarin.Forms.Platform.MacOS/Platform.cs
new file mode 100644
index 0000000..8629684
--- /dev/null
+++ b/Xamarin.Forms.Platform.MacOS/Platform.cs
@@ -0,0 +1,262 @@
+´╗┐using System;
+using AppKit;
+using RectangleF = CoreGraphics.CGRect;
+using System.Linq;
+
+namespace Xamarin.Forms.Platform.MacOS
+{
+ public class Platform : BindableObject, IPlatform, IDisposable
+ {
+ internal static readonly BindableProperty RendererProperty = BindableProperty.CreateAttached("Renderer",
+ typeof(IVisualElementRenderer), typeof(Platform), default(IVisualElementRenderer),
+ propertyChanged: (bindable, oldvalue, newvalue) =>
+ {
+ var view = bindable as VisualElement;
+ if (view != null)
+ view.IsPlatformEnabled = newvalue != null;
+ });
+
+ readonly PlatformRenderer PlatformRenderer;
+
+ bool _appeared;
+ bool _disposed;
+
+ internal static NativeToolbarTracker NativeToolbarTracker = new NativeToolbarTracker();
+
+ internal Platform()
+ {
+ PlatformRenderer = new PlatformRenderer(this);
+
+ MessagingCenter.Subscribe(this, Page.AlertSignalName, (Page sender, AlertArguments arguments) =>
+ {
+ var alert = NSAlert.WithMessage(arguments.Title, arguments.Cancel, arguments.Accept, null, arguments.Message);
+ var result = alert.RunModal();
+ arguments.SetResult(result == 1);
+ });
+
+ MessagingCenter.Subscribe(this, Page.ActionSheetSignalName, (Page sender, ActionSheetArguments arguments) =>
+ {
+ var alert = NSAlert.WithMessage(arguments.Title, arguments.Cancel, arguments.Destruction, null, "");
+ if (arguments.Buttons != null)
+ {
+ alert.AccessoryView = GetExtraButton(arguments);
+ alert.Layout();
+ }
+
+ var result = (int)alert.RunSheetModal(NSApplication.SharedApplication.MainWindow);
+ var titleResult = string.Empty;
+ if (result == 1)
+ titleResult = arguments.Cancel;
+ else if (result == 0)
+ titleResult = arguments.Destruction;
+ else if (result > 1 && arguments.Buttons != null && result - 2 <= arguments.Buttons.Count())
+ titleResult = arguments.Buttons.ElementAt(result - 2);
+
+ arguments.SetResult(titleResult);
+ });
+ }
+
+ SizeRequest IPlatform.GetNativeSize(VisualElement view, double widthConstraint, double heightConstraint)
+ {
+ var renderView = GetRenderer(view);
+ if (renderView == null || renderView.NativeView == null)
+ return new SizeRequest(Size.Zero);
+
+ return renderView.GetDesiredSize(widthConstraint, heightConstraint);
+ }
+
+ Page Page { get; set; }
+
+ Application TargetApplication
+ {
+ get
+ {
+ if (Page == null)
+ return null;
+ return Page.RealParent as Application;
+ }
+ }
+
+ void IDisposable.Dispose()
+ {
+ if (_disposed)
+ return;
+ _disposed = true;
+
+ Page.DescendantRemoved -= HandleChildRemoved;
+ MessagingCenter.Unsubscribe<Page, ActionSheetArguments>(this, Page.ActionSheetSignalName);
+ MessagingCenter.Unsubscribe<Page, AlertArguments>(this, Page.AlertSignalName);
+ MessagingCenter.Unsubscribe<Page, bool>(this, Page.BusySetSignalName);
+
+ DisposeModelAndChildrenRenderers(Page);
+ PlatformRenderer.Dispose();
+ }
+
+ public static IVisualElementRenderer CreateRenderer(VisualElement element)
+ {
+ var t = element.GetType();
+ var renderer = Registrar.Registered.GetHandler<IVisualElementRenderer>(t) ?? new DefaultRenderer();
+ renderer.SetElement(element);
+ return renderer;
+ }
+
+ public static IVisualElementRenderer GetRenderer(VisualElement bindable)
+ {
+ return (IVisualElementRenderer)bindable.GetValue(RendererProperty);
+ }
+
+ public static void SetRenderer(VisualElement bindable, IVisualElementRenderer value)
+ {
+ bindable.SetValue(RendererProperty, value);
+ }
+
+ protected override void OnBindingContextChanged()
+ {
+ SetInheritedBindingContext(Page, BindingContext);
+
+ base.OnBindingContextChanged();
+ }
+
+ internal NSViewController ViewController => PlatformRenderer;
+
+ internal static void DisposeModelAndChildrenRenderers(Element view)
+ {
+ IVisualElementRenderer renderer;
+ foreach (VisualElement child in view.Descendants())
+ DisposeModelAndChildrenRenderers(child);
+
+ renderer = GetRenderer((VisualElement)view);
+ if (renderer?.ViewController?.ParentViewController != null)
+ renderer?.ViewController?.RemoveFromParentViewController();
+
+ renderer?.NativeView?.RemoveFromSuperview();
+ renderer?.Dispose();
+
+ view.ClearValue(RendererProperty);
+ }
+
+ internal static void DisposeRendererAndChildren(IVisualElementRenderer rendererToRemove)
+ {
+ if (rendererToRemove == null || rendererToRemove.Element == null)
+ return;
+
+ if (GetRenderer(rendererToRemove.Element) == rendererToRemove)
+ rendererToRemove.Element.ClearValue(RendererProperty);
+
+ if (rendererToRemove.NativeView != null)
+ {
+ var subviews = rendererToRemove.NativeView.Subviews;
+ for (var i = 0; i < subviews.Length; i++)
+ {
+ var childRenderer = subviews[i] as IVisualElementRenderer;
+ if (childRenderer != null)
+ DisposeRendererAndChildren(childRenderer);
+ }
+
+ rendererToRemove.NativeView.RemoveFromSuperview();
+ }
+ rendererToRemove.Dispose();
+ }
+
+ internal void LayoutSubviews()
+ {
+ if (Page == null)
+ return;
+
+ var rootRenderer = GetRenderer(Page);
+
+ if (rootRenderer == null)
+ return;
+
+ rootRenderer.SetElementSize(new Size(PlatformRenderer.View.Bounds.Width, PlatformRenderer.View.Bounds.Height));
+ }
+
+ internal void SetPage(Page newRoot)
+ {
+ if (newRoot == null)
+ return;
+ if (Page != null)
+ throw new NotImplementedException();
+ Page = newRoot;
+
+ if (_appeared == false)
+ return;
+
+ Page.Platform = this;
+ AddChild(Page);
+
+ Page.DescendantRemoved += HandleChildRemoved;
+
+ TargetApplication.NavigationProxy.Inner = PlatformRenderer.Navigation;
+ }
+
+ internal void DidAppear()
+ {
+ PlatformRenderer.Navigation.AnimateModalPages = false;
+ TargetApplication.NavigationProxy.Inner = PlatformRenderer.Navigation;
+ PlatformRenderer.Navigation.AnimateModalPages = true;
+ }
+
+ internal void WillAppear()
+ {
+ if (_appeared)
+ return;
+
+ Page.Platform = this;
+ AddChild(Page);
+
+ Page.DescendantRemoved += HandleChildRemoved;
+
+ _appeared = true;
+ }
+
+ static NSView GetExtraButton(ActionSheetArguments arguments)
+ {
+ var newView = new NSView();
+ int height = 50;
+ int width = 300;
+ int i = 0;
+ foreach (var button in arguments.Buttons)
+ {
+ var btn = new NSButton { Title = button, Tag = i };
+ btn.SetButtonType(NSButtonType.MomentaryPushIn);
+ btn.Activated +=
+ (s, e) =>
+ {
+ NSApplication.SharedApplication.EndSheet(NSApplication.SharedApplication.MainWindow.AttachedSheet,
+ ((NSButton)s).Tag + 2);
+ };
+ btn.Frame = new RectangleF(0, height * i, width, height);
+ newView.AddSubview(btn);
+ i++;
+ }
+ newView.Frame = new RectangleF(0, 0, width, height * i);
+ return newView;
+ }
+
+ void AddChild(VisualElement view)
+ {
+ if (!Application.IsApplicationOrNull(view.RealParent))
+ Console.Error.WriteLine("Tried to add parented view to canvas directly");
+
+ if (GetRenderer(view) == null)
+ {
+ var viewRenderer = CreateRenderer(view);
+ SetRenderer(view, viewRenderer);
+
+ PlatformRenderer.View.AddSubview(viewRenderer.NativeView);
+ if (viewRenderer.ViewController != null)
+ PlatformRenderer.AddChildViewController(viewRenderer.ViewController);
+ viewRenderer.SetElementSize(new Size(PlatformRenderer.View.Bounds.Width, PlatformRenderer.View.Bounds.Height));
+ }
+ else
+ Console.Error.WriteLine("A Renderer was already found, potential view double add");
+ }
+
+ void HandleChildRemoved(object sender, ElementEventArgs e)
+ {
+ var view = e.Element;
+ DisposeModelAndChildrenRenderers(view);
+ }
+ }
+} \ No newline at end of file