From 969b3709dbc41738e54b9f929e7bf8c5588303ec Mon Sep 17 00:00:00 2001 From: Chris Hamons Date: Sun, 8 Jan 2017 07:56:46 -0800 Subject: [PATCH] Add basic Xamarin.Mac support Summary: - Does not contain "magic" found in YogaKit yet, but enough to get started - Simple test project showing use - YGInteropSetLogger and YGNodeInit(IntPtr) were missing from native lib built by buck Closes https://github.com/facebook/yoga/pull/278 Reviewed By: emilsjolander Differential Revision: D4388480 Pulled By: splhack fbshipit-source-id: a7387bb5b5554b6fce80d08c23e4fa18a4611cce --- csharp/Mac/.gitignore | 2 + csharp/Mac/ApiDefinition.cs | 23 + csharp/Mac/CustomBuildAction.targets | 11 + .../Mac/Facebook.Yoga.Mac.Test/AppDelegate.cs | 30 + .../Facebook.Yoga.Mac.Test/Entitlements.plist | 6 + .../Facebook.Yoga.Mac.Test.csproj | 84 +++ csharp/Mac/Facebook.Yoga.Mac.Test/Info.plist | 30 + csharp/Mac/Facebook.Yoga.Mac.Test/Main.cs | 21 + .../Facebook.Yoga.Mac.Test/Main.storyboard | 681 ++++++++++++++++++ .../Facebook.Yoga.Mac.Test/ViewController.cs | 137 ++++ .../ViewController.designer.cs | 18 + csharp/Mac/Facebook.Yoga.Mac.csproj | 51 ++ csharp/Mac/Facebook.Yoga.Mac.sln | 25 + 13 files changed, 1119 insertions(+) create mode 100644 csharp/Mac/.gitignore create mode 100644 csharp/Mac/ApiDefinition.cs create mode 100644 csharp/Mac/CustomBuildAction.targets create mode 100644 csharp/Mac/Facebook.Yoga.Mac.Test/AppDelegate.cs create mode 100644 csharp/Mac/Facebook.Yoga.Mac.Test/Entitlements.plist create mode 100644 csharp/Mac/Facebook.Yoga.Mac.Test/Facebook.Yoga.Mac.Test.csproj create mode 100644 csharp/Mac/Facebook.Yoga.Mac.Test/Info.plist create mode 100644 csharp/Mac/Facebook.Yoga.Mac.Test/Main.cs create mode 100644 csharp/Mac/Facebook.Yoga.Mac.Test/Main.storyboard create mode 100644 csharp/Mac/Facebook.Yoga.Mac.Test/ViewController.cs create mode 100644 csharp/Mac/Facebook.Yoga.Mac.Test/ViewController.designer.cs create mode 100644 csharp/Mac/Facebook.Yoga.Mac.csproj create mode 100644 csharp/Mac/Facebook.Yoga.Mac.sln diff --git a/csharp/Mac/.gitignore b/csharp/Mac/.gitignore new file mode 100644 index 00000000..1cf1debb --- /dev/null +++ b/csharp/Mac/.gitignore @@ -0,0 +1,2 @@ +libyoga.dylib +*.userprefs diff --git a/csharp/Mac/ApiDefinition.cs b/csharp/Mac/ApiDefinition.cs new file mode 100644 index 00000000..9fec5cd6 --- /dev/null +++ b/csharp/Mac/ApiDefinition.cs @@ -0,0 +1,23 @@ +/** + * Copyright (c) 2014-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + */ + +using System; + +using AppKit; +using Foundation; +using ObjCRuntime; +using CoreGraphics; + +namespace Facebook.Yoga.Mac +{ + // Xamarin.Mac binding projects allow you to include native libraries inside C# DLLs for easy consumption + // later. However, the binding project build files currently assume you are binding some objective-c API + // and that you need an ApiDefinition.cs for that. yoga is all C APIs, so just include this "blank" file so + // the dylib gets packaged +} diff --git a/csharp/Mac/CustomBuildAction.targets b/csharp/Mac/CustomBuildAction.targets new file mode 100644 index 00000000..e20e70b8 --- /dev/null +++ b/csharp/Mac/CustomBuildAction.targets @@ -0,0 +1,11 @@ + + + + CopyInNativeLib;$(CompileDependsOn) + + + + + + + diff --git a/csharp/Mac/Facebook.Yoga.Mac.Test/AppDelegate.cs b/csharp/Mac/Facebook.Yoga.Mac.Test/AppDelegate.cs new file mode 100644 index 00000000..f6a46196 --- /dev/null +++ b/csharp/Mac/Facebook.Yoga.Mac.Test/AppDelegate.cs @@ -0,0 +1,30 @@ +/** + * Copyright 2014-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the license found in the + * LICENSE-examples file in the root directory of this source tree. + */ + +using AppKit; +using Foundation; + +namespace Facebook.Yoga.Mac.Test +{ + [Register("AppDelegate")] + public class AppDelegate : NSApplicationDelegate + { + public AppDelegate() + { + } + + public override void DidFinishLaunching(NSNotification notification) + { + } + + public override void WillTerminate(NSNotification notification) + { + // Insert code here to tear down your application + } + } +} diff --git a/csharp/Mac/Facebook.Yoga.Mac.Test/Entitlements.plist b/csharp/Mac/Facebook.Yoga.Mac.Test/Entitlements.plist new file mode 100644 index 00000000..9ae59937 --- /dev/null +++ b/csharp/Mac/Facebook.Yoga.Mac.Test/Entitlements.plist @@ -0,0 +1,6 @@ + + + + + + diff --git a/csharp/Mac/Facebook.Yoga.Mac.Test/Facebook.Yoga.Mac.Test.csproj b/csharp/Mac/Facebook.Yoga.Mac.Test/Facebook.Yoga.Mac.Test.csproj new file mode 100644 index 00000000..70535e37 --- /dev/null +++ b/csharp/Mac/Facebook.Yoga.Mac.Test/Facebook.Yoga.Mac.Test.csproj @@ -0,0 +1,84 @@ + + + + Debug + AnyCPU + {64E0AB97-A904-4607-A535-EEA5A966C09E} + {A3F8F2AB-B479-4A4A-A458-A89E7DC349F1};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + Exe + Facebook.Yoga.Mac.Test + Facebook.Yoga.Mac.Test + v2.0 + Xamarin.Mac + Resources + + + true + full + false + bin\Debug + DEBUG; + prompt + 4 + false + Mac Developer + false + false + false + true + true + true + HttpClientHandler + Default + None + x86_64 + + + pdbonly + true + bin\Release + + prompt + 4 + false + true + false + true + true + true + SdkOnly + HttpClientHandler + Default + + + + + + + + + + + + + + + + + + + + ViewController.cs + + + + + + + + {19A1C7D7-C9CC-476A-B604-DF6A3DE1BA71} + Facebook.Yoga.Mac + + + + diff --git a/csharp/Mac/Facebook.Yoga.Mac.Test/Info.plist b/csharp/Mac/Facebook.Yoga.Mac.Test/Info.plist new file mode 100644 index 00000000..7e955671 --- /dev/null +++ b/csharp/Mac/Facebook.Yoga.Mac.Test/Info.plist @@ -0,0 +1,30 @@ + + + + + CFBundleName + Facebook.Yoga.Mac.Test + CFBundleIdentifier + com.companyname.facebook-yoga-mac-test + CFBundleShortVersionString + 1.0 + CFBundleVersion + 1 + LSMinimumSystemVersion + 10.11 + CFBundleDevelopmentRegion + en + CFBundleInfoDictionaryVersion + 6.0 + CFBundlePackageType + APPL + CFBundleSignature + ???? + NSHumanReadableCopyright + ${AuthorCopyright} + NSPrincipalClass + NSApplication + NSMainStoryboardFile + Main + + diff --git a/csharp/Mac/Facebook.Yoga.Mac.Test/Main.cs b/csharp/Mac/Facebook.Yoga.Mac.Test/Main.cs new file mode 100644 index 00000000..97adb4db --- /dev/null +++ b/csharp/Mac/Facebook.Yoga.Mac.Test/Main.cs @@ -0,0 +1,21 @@ +/** + * Copyright 2014-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the license found in the + * LICENSE-examples file in the root directory of this source tree. + */ + +using AppKit; + +namespace Facebook.Yoga.Mac.Test +{ + static class MainClass + { + static void Main(string[] args) + { + NSApplication.Init(); + NSApplication.Main(args); + } + } +} diff --git a/csharp/Mac/Facebook.Yoga.Mac.Test/Main.storyboard b/csharp/Mac/Facebook.Yoga.Mac.Test/Main.storyboard new file mode 100644 index 00000000..1d8f728d --- /dev/null +++ b/csharp/Mac/Facebook.Yoga.Mac.Test/Main.storyboard @@ -0,0 +1,681 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Default + + + + + + + Left to Right + + + + + + + Right to Left + + + + + + + + + + + Default + + + + + + + Left to Right + + + + + + + Right to Left + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/csharp/Mac/Facebook.Yoga.Mac.Test/ViewController.cs b/csharp/Mac/Facebook.Yoga.Mac.Test/ViewController.cs new file mode 100644 index 00000000..e802aa4e --- /dev/null +++ b/csharp/Mac/Facebook.Yoga.Mac.Test/ViewController.cs @@ -0,0 +1,137 @@ +/** + * Copyright 2014-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the license found in the + * LICENSE-examples file in the root directory of this source tree. + */ + +//#define DEBUG_LAYOUT +using System; + +using AppKit; +using Foundation; +using CoreGraphics; + +namespace Facebook.Yoga.Mac.Test +{ + public static class NSViewYogaExtensions + { + public static void ApplyYogaLayout (this NSView view, YogaNode n, bool root = true) + { +#if DEBUG_LAYOUT + Console.WriteLine ($"ApplyYogaLayout {view.ToolTip}, {n.LayoutX}, {n.LayoutY}, {n.LayoutWidth}, {n.LayoutHeight}"); +#endif + + // A bit of gross special casing + // This really should mostly go away if/when the UIView+Yoga.m magic gets ported to AppKit + if (root) + view.Frame = new CGRect (n.LayoutX, n.LayoutY, n.LayoutWidth, n.LayoutHeight); +#if DEBUG_LAYOUT + Console.WriteLine ($"Setting {view.ToolTip} frame to {view.Frame}"); +#endif + + // This assumes your YogaNode and NSView children were inserted in same order + for (int i = 0; i < n.Count; ++i) { + YogaNode childNode = n[i]; + // Cocoa coord space is from bottom left not top left + view.Subviews[i].Frame = new CGRect (childNode.LayoutX, n.LayoutHeight - childNode.LayoutY - childNode.LayoutHeight, childNode.LayoutWidth, childNode.LayoutHeight); +#if DEBUG_LAYOUT + Console.WriteLine ($"Setting {view.Subviews[i].ToolTip} frame to {view.Subviews[i].Frame}"); +#endif + if (childNode.Count > 0){ +#if DEBUG_LAYOUT + Console.WriteLine ($"Calling ApplyYogaLayout recursively on {view.Subviews[i].ToolTip}"); +#endif + ApplyYogaLayout (view.Subviews[i], childNode, false); + } + } + } + } + + public partial class ViewController : NSViewController + { + public ViewController(IntPtr handle) : base(handle) + { + } + + public override void ViewDidLoad() + { + base.ViewDidLoad (); + + NSImage image = NSImage.ImageNamed (NSImageName.TrashFull); + + NSView root = CreateViewHierarchy (image); + var rootNode = CalculateLayout (View.Frame, image.Size); + + root.ApplyYogaLayout (rootNode); + + View.AddSubview (root); + } + + static NSView CreateViewHierarchy (NSImage image) + { + var root = new NSView () { + WantsLayer = true, + ToolTip = "Root" + }; + root.Layer.BackgroundColor = NSColor.Red.CGColor; + + NSView child1 = new NSView () { + WantsLayer = true, + ToolTip = "Child 1" + }; + child1.Layer.BackgroundColor = NSColor.Blue.CGColor; + + NSView child2 = new NSView () { + WantsLayer = true, + ToolTip = "Child 2" + }; + child2.Layer.BackgroundColor = NSColor.Green.CGColor; + + NSView child3 = new NSView () { + WantsLayer = true, + ToolTip = "Child 3" + }; + child3.Layer.BackgroundColor = NSColor.Yellow.CGColor; + + root.AddSubview (child1); + root.AddSubview (child2); + child2.AddSubview (child3); + + return root; + } + + static YogaNode CalculateLayout (CGRect rootFrame, CGSize imageSize) + { + var rootNode = new YogaNode () { + Width = (float)rootFrame.Width, + Height = (float)rootFrame.Height, + AlignItems = YogaAlign.Center, + JustifyContent = YogaJustify.Center + }; + + var child1Node = new YogaNode () { + Width = 100, + Height = 100 + }; + + var child2Node = new YogaNode () { + Width = 200, + Height = 100 + }; + + var child3Node = new YogaNode () { + Width = 100, + Height = 100 + }; + + rootNode.Insert (0, child1Node); + rootNode.Insert (1, child2Node); + child2Node.Insert (0, child3Node); + rootNode.CalculateLayout (); + + return rootNode; + } + } +} diff --git a/csharp/Mac/Facebook.Yoga.Mac.Test/ViewController.designer.cs b/csharp/Mac/Facebook.Yoga.Mac.Test/ViewController.designer.cs new file mode 100644 index 00000000..1cf1e327 --- /dev/null +++ b/csharp/Mac/Facebook.Yoga.Mac.Test/ViewController.designer.cs @@ -0,0 +1,18 @@ +// WARNING +// +// This file has been generated automatically by Xamarin Studio to store outlets and +// actions made in the UI designer. If it is removed, they will be lost. +// Manual changes to this file may not be handled correctly. +// +using Foundation; + +namespace Facebook.Yoga.Mac.Test +{ + [Register("ViewController")] + partial class ViewController + { + void ReleaseDesignerOutlets() + { + } + } +} diff --git a/csharp/Mac/Facebook.Yoga.Mac.csproj b/csharp/Mac/Facebook.Yoga.Mac.csproj new file mode 100644 index 00000000..63dcfe16 --- /dev/null +++ b/csharp/Mac/Facebook.Yoga.Mac.csproj @@ -0,0 +1,51 @@ + + + + Debug + AnyCPU + {19A1C7D7-C9CC-476A-B604-DF6A3DE1BA71} + {810C163F-4746-4721-8B8E-88A3673A62EA};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + Library + Facebook.Yoga.Mac + Facebook.Yoga.Mac + Resources + + + true + full + false + bin\Debug + __UNIFIED__;DEBUG;MONOMAC + prompt + 4 + false + + + true + bin\Release + __UNIFIED__;MONOMAC + prompt + 4 + false + + + + + + + + + + + + + + + Dynamic + False + + + + + + diff --git a/csharp/Mac/Facebook.Yoga.Mac.sln b/csharp/Mac/Facebook.Yoga.Mac.sln new file mode 100644 index 00000000..c99766c6 --- /dev/null +++ b/csharp/Mac/Facebook.Yoga.Mac.sln @@ -0,0 +1,25 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 2012 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Facebook.Yoga.Mac.Test", "Facebook.Yoga.Mac.Test\Facebook.Yoga.Mac.Test.csproj", "{64E0AB97-A904-4607-A535-EEA5A966C09E}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Facebook.Yoga.Mac", "Facebook.Yoga.Mac.csproj", "{19A1C7D7-C9CC-476A-B604-DF6A3DE1BA71}" +EndProject +Project("{D954291E-2A0B-460D-934E-DC6B0785DB48}") = "Facebook.Yoga.Shared", "..\Facebook.Yoga\Facebook.Yoga.Shared.shproj", "{91C42D32-291D-4B72-90B4-551663D60B8B}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {64E0AB97-A904-4607-A535-EEA5A966C09E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {64E0AB97-A904-4607-A535-EEA5A966C09E}.Debug|Any CPU.Build.0 = Debug|Any CPU + {64E0AB97-A904-4607-A535-EEA5A966C09E}.Release|Any CPU.ActiveCfg = Release|Any CPU + {64E0AB97-A904-4607-A535-EEA5A966C09E}.Release|Any CPU.Build.0 = Release|Any CPU + {19A1C7D7-C9CC-476A-B604-DF6A3DE1BA71}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {19A1C7D7-C9CC-476A-B604-DF6A3DE1BA71}.Debug|Any CPU.Build.0 = Debug|Any CPU + {19A1C7D7-C9CC-476A-B604-DF6A3DE1BA71}.Release|Any CPU.ActiveCfg = Release|Any CPU + {19A1C7D7-C9CC-476A-B604-DF6A3DE1BA71}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection +EndGlobal