diff --git a/.gitignore b/.gitignore index 88667ae7..5b346768 100644 --- a/.gitignore +++ b/.gitignore @@ -5,54 +5,6 @@ /.buckconfig.local /.buckd /gentest/test.html -.buckversion # Visual studio code .vscode -*.pdb -*.tlog -*.obj -*.pch -*.log -*.orig - -# Xcode -## Build generated -build/ -DerivedData/ - -## Various settings -*.pbxuser -!default.pbxuser -*.mode1v3 -!default.mode1v3 -*.mode2v3 -!default.mode2v3 -*.perspectivev3 -!default.perspectivev3 -xcuserdata/ - -## Other -*.moved-aside -*.xcuserstate - -## Obj-C/Swift specific -*.hmap -*.ipa -*.dSYM.zip -*.dSYM - -# CocoaPods -# -# We recommend against adding the Pods directory to your .gitignore. However -# you should judge for yourself, the pros and cons are mentioned at: -# https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control -# -Pods/ - -# Carthage -# -# Add this line if you want to avoid checking in source code from Carthage dependencies. -# Carthage/Checkouts - -Carthage/Build diff --git a/csharp/.gitignore b/csharp/.gitignore index bdb6ff4e..c333f116 100644 --- a/csharp/.gitignore +++ b/csharp/.gitignore @@ -267,3 +267,5 @@ paket-files/ # Python Tools for Visual Studio (PTVS) __pycache__/ *.pyc + +libyoga.a diff --git a/csharp/Facebook.Yoga/Native.cs b/csharp/Facebook.Yoga/Native.cs index b66cf8a6..fa870ee9 100644 --- a/csharp/Facebook.Yoga/Native.cs +++ b/csharp/Facebook.Yoga/Native.cs @@ -89,8 +89,10 @@ namespace Facebook.Yoga [DllImport(DllName, ExactSpelling = true, CallingConvention = CallingConvention.Cdecl)] public static extern void YGNodePrint(YGNodeHandle node, YogaPrintOptions options); +#if !__IOS__ [DllImport(DllName, ExactSpelling = true, CallingConvention = CallingConvention.Cdecl)] [return: MarshalAs(UnmanagedType.I1)] +#endif public static extern bool YGValueIsUndefined(float value); [DllImport(DllName, ExactSpelling = true, CallingConvention = CallingConvention.Cdecl)] diff --git a/csharp/Facebook.Yoga/YogaLogger.cs b/csharp/Facebook.Yoga/YogaLogger.cs index e5d79b79..b0cb4444 100644 --- a/csharp/Facebook.Yoga/YogaLogger.cs +++ b/csharp/Facebook.Yoga/YogaLogger.cs @@ -42,4 +42,4 @@ namespace Facebook.Yoga } } } -} +} \ No newline at end of file diff --git a/csharp/Facebook.YogaKit/Facebook.YogaKit.Shared.shproj b/csharp/Facebook.YogaKit/Facebook.YogaKit.Shared.shproj new file mode 100644 index 00000000..0943de36 --- /dev/null +++ b/csharp/Facebook.YogaKit/Facebook.YogaKit.Shared.shproj @@ -0,0 +1,11 @@ + + + + {A24B3BA6-3143-4FFF-B8B8-1EDF166F5F4A} + + + + + + + \ No newline at end of file diff --git a/csharp/Facebook.YogaKit/Facebook.YogaKit.projitems b/csharp/Facebook.YogaKit/Facebook.YogaKit.projitems new file mode 100644 index 00000000..abc6371b --- /dev/null +++ b/csharp/Facebook.YogaKit/Facebook.YogaKit.projitems @@ -0,0 +1,15 @@ + + + + $(MSBuildAllProjects);$(MSBuildThisFileFullPath) + true + {A24B3BA6-3143-4FFF-B8B8-1EDF166F5F4A} + + + Facebook.YogaKit + + + + + + \ No newline at end of file diff --git a/csharp/Facebook.YogaKit/YogaKit.cs b/csharp/Facebook.YogaKit/YogaKit.cs new file mode 100644 index 00000000..e5d06656 --- /dev/null +++ b/csharp/Facebook.YogaKit/YogaKit.cs @@ -0,0 +1,180 @@ +using System; +using System.Collections.Generic; +using Facebook.Yoga; +#if __IOS__ +using NativeView = UIKit.UIView; +#endif + +namespace Facebook.YogaKit +{ + public static class YogaKit + { + internal static Dictionary Bridges = new Dictionary(); + + public static void UsesYoga(this NativeView view, bool usesYoga) + { + YogaKitNative.UsesYoga(view, usesYoga); + } + + public static bool GetUsesYoga(this NativeView view) + { + return YogaKitNative.GetUsesYoga(view); + } + + public static void IncludeYogaLayout(this NativeView view, bool includeInLayout) + { + YogaKitNative.IncludeYogaLayout(view, includeInLayout); + } + + public static bool GetIncludeYogaLayout(this NativeView view) + { + return YogaKitNative.GetIncludeYogaLayout(view); + } + + public static void YogaWidth(this NativeView view, nfloat width) + { + var node = GetYogaNode(view); + node.Width = (float)width; + } + + public static void YogaHeight(this NativeView view, nfloat height) + { + var node = GetYogaNode(view); + node.Height = (float)height; + } + + public static void YogaMinWidth(this NativeView view, float minWidth) + { + var node = GetYogaNode(view); + node.MinWidth = minWidth; + } + + public static void YogaMinHeight(this NativeView view, float minHeight) + { + var node = GetYogaNode(view); + node.MinHeight = minHeight; + } + + public static void YogaMaxWidth(this NativeView view, float maxWidth) + { + var node = GetYogaNode(view); + node.MaxWidth = maxWidth; + } + + public static void YogaMaxHeight(this NativeView view, float maxHeight) + { + var node = GetYogaNode(view); + node.MaxHeight = maxHeight; + } + + public static void YogaAlignItems(this NativeView view, YogaAlign align) + { + var node = GetYogaNode(view); + node.AlignItems = align; + } + + public static void YogaJustify(this NativeView view, YogaJustify justify) + { + var node = GetYogaNode(view); + node.JustifyContent = justify; + } + + public static void YogaAlign(this NativeView view, YogaAlign align) + { + var node = GetYogaNode(view); + node.AlignContent = align; + } + + public static void YogaAlignSelf(this NativeView view, YogaAlign align) + { + var node = GetYogaNode(view); + node.AlignSelf = align; + } + + public static void YogaDirection(this NativeView view, YogaDirection direction) + { + var node = GetYogaNode(view); + node.StyleDirection = direction; + } + + public static void YogaFlexDirection(this NativeView view, YogaFlexDirection direction) + { + var node = GetYogaNode(view); + node.FlexDirection = direction; + } + + public static void YogaPositionType(this NativeView view, YogaPositionType position) + { + var node = GetYogaNode(view); + node.PositionType = position; + } + + public static void YogaFlexWrap(this NativeView view, YogaWrap wrap) + { + var node = GetYogaNode(view); + node.Wrap = wrap; + } + + public static void YogaFlexShrink(this NativeView view, float shrink) + { + var node = GetYogaNode(view); + node.FlexShrink = shrink; + } + + public static void YogaFlexGrow(this NativeView view, float grow) + { + var node = GetYogaNode(view); + node.FlexGrow = grow; + } + + public static void YogaFlexBasis(this NativeView view, float basis) + { + var node = GetYogaNode(view); + node.FlexBasis = basis; + } + + public static void YogaPositionForEdge(this NativeView view, float position, YogaEdge edge) + { + var node = GetYogaNode(view); + node.SetPosition(edge, position); + } + + public static void YogaMarginForEdge(this NativeView view, float margin, YogaEdge edge) + { + var node = GetYogaNode(view); + node.SetMargin(edge, margin); + } + + public static void YogaPaddingForEdge(this NativeView view, float padding, YogaEdge edge) + { + var node = GetYogaNode(view); + node.SetPadding(edge, padding); + } + + public static void YogaAspectRation(this NativeView view, float ratio) + { + var node = GetYogaNode(view); + node.StyleAspectRatio = ratio; + } + + #region Layout and Sizing + public static void YogaApplyLayout(this NativeView view) + { + YogaKitNative.CalculateLayoutWithSize(view, view.Bounds.Size); + YogaKitNative.ApplyLayoutToViewHierarchy(view); + } + + public static YogaDirection YogaResolvedDirection(this NativeView view) + { + var node = GetYogaNode(view); + return node.LayoutDirection; + } + + #endregion + + public static YogaNode GetYogaNode(this NativeView view) + { + return YogaKitNative.GetYogaNode(view); + } + } +} \ No newline at end of file diff --git a/csharp/Facebook.YogaKit/YogaKitNative.cs b/csharp/Facebook.YogaKit/YogaKitNative.cs new file mode 100644 index 00000000..fd872835 --- /dev/null +++ b/csharp/Facebook.YogaKit/YogaKitNative.cs @@ -0,0 +1,255 @@ +using System; +using System.Collections.Generic; +using System.Runtime.InteropServices; +using Facebook.Yoga; +#if __IOS__ +using CoreGraphics; +using Foundation; +using UIKit; +#endif + +namespace Facebook.YogaKit +{ + internal static class YogaKitNative + { + static NSString YogaNodeKey = new NSString("YogaNode"); + + static NSString UsesYogaKey = new NSString("UsesYoga"); + + static NSString IncludeYogaKey = new NSString("UsesYoga"); + + public static void UsesYoga(UIView view, bool usesYoga) + { + var value = NSNumber.FromBoolean(usesYoga); + objc_setAssociatedObject(view.Handle, UsesYogaKey.Handle, value.Handle, AssociationPolicy.RETAIN_NONATOMIC); + } + + public static bool GetUsesYoga(UIView view) + { + var value = ObjCRuntime.Runtime.GetNSObject(objc_getAssociatedObject(view.Handle, UsesYogaKey.Handle)) as NSNumber; + return value == null ? false : value.BoolValue; + } + + public static void IncludeYogaLayout(UIView view, bool includeInLayout) + { + var value = NSNumber.FromBoolean(includeInLayout); + objc_setAssociatedObject(view.Handle, IncludeYogaKey.Handle, value.Handle, AssociationPolicy.RETAIN_NONATOMIC); + } + + public static bool GetIncludeYogaLayout(UIView view) + { + var value = ObjCRuntime.Runtime.GetNSObject(objc_getAssociatedObject(view.Handle, IncludeYogaKey.Handle)) as NSNumber; + return value == null ? true : value.BoolValue; + } + + public static YogaNode GetYogaNode(UIView view) + { + var value = ObjCRuntime.Runtime.GetNSObject(objc_getAssociatedObject(view.Handle, YogaNodeKey.Handle)) as YGNodeBridge; + if (value == null) + { + value = new YGNodeBridge(); + value.SetContext(view); + objc_setAssociatedObject(view.Handle, YogaNodeKey.Handle, value.Handle, AssociationPolicy.RETAIN_NONATOMIC); + } + return value.node; + } + + public static CGSize CalculateLayoutWithSize(UIView view, CGSize size) + { + if (!view.GetUsesYoga()) + { + System.Diagnostics.Debug.WriteLine("Doesn't use Yoga"); + } + AttachNodesFromViewHierachy(view); + var node = GetYogaNode(view); + + node.Width = (float)size.Width; + node.Height = (float)size.Height; + node.CalculateLayout(); + + return new CGSize { Width = node.LayoutWidth, Height = node.LayoutHeight }; + } + + public static void ApplyLayoutToViewHierarchy(UIView view) + { + if (!view.GetIncludeYogaLayout()) + return; + + var node = GetYogaNode(view); + CGPoint topLeft = new CGPoint(node.LayoutX, node.LayoutY); + CGPoint bottomRight = new CGPoint(topLeft.X + node.LayoutWidth, topLeft.Y + node.LayoutHeight); + view.Frame = new CGRect(RoundPixelValue(topLeft.X), RoundPixelValue(topLeft.Y), RoundPixelValue(bottomRight.X) - RoundPixelValue(topLeft.X), RoundPixelValue(bottomRight.Y) - RoundPixelValue(topLeft.Y)); + bool isLeaf = !view.GetUsesYoga() || view.Subviews.Length == 0; + if (!isLeaf) + { + for (int i = 0; i < view.Subviews.Length; i++) + { + ApplyLayoutToViewHierarchy(view.Subviews[i]); + } + } + } + + public static CGSize YogaIntrinsicSize(this UIView view) + { + var constrainedSize = new CGSize + { + Width = float.NaN, + Height = float.NaN + }; + return CalculateLayoutWithSize(view, constrainedSize); + } + + static YogaSize MeasureView(YogaNode node, float width, YogaMeasureMode widthMode, float height, YogaMeasureMode heightMode) + { + var constrainedWidth = (widthMode == YogaMeasureMode.Undefined) ? nfloat.MaxValue : width; + var constrainedHeight = (heightMode == YogaMeasureMode.Undefined) ? nfloat.MaxValue : height; + + UIView view = null; + if (YogaKit.Bridges.ContainsKey(node)) + (YogaKit.Bridges[node] as YGNodeBridge).viewRef.TryGetTarget(out view); + + var sizeThatFits = view.SizeThatFits(new CGSize(constrainedWidth, constrainedHeight)); + + var finalWidth = SanitizeMeasurement(constrainedWidth, sizeThatFits.Width, widthMode); + var finalHeight = SanitizeMeasurement(constrainedHeight, sizeThatFits.Height, heightMode); + + return MeasureOutput.Make(finalWidth, finalHeight); + } + + static float SanitizeMeasurement(nfloat constrainedSize, nfloat measuredSize, YogaMeasureMode measureMode) + { + float result; + if (measureMode == YogaMeasureMode.Exactly) + { + result = (float)constrainedSize; + } + else if (measureMode == YogaMeasureMode.AtMost) + { + result = (float)Math.Min(constrainedSize, measuredSize); + } + else { + result = (float)measuredSize; + } + + return result; + + } + + static double RoundPixelValue(nfloat value) + { + nfloat scale = UIScreen.MainScreen.Scale; + + return Math.Round(value * scale) / scale; + } + + static void AttachNodesFromViewHierachy(UIView view) + { + var node = GetYogaNode(view); + + // Only leaf nodes should have a measure function + if (!view.GetUsesYoga() || view.Subviews.Length == 0) + { + node.SetMeasureFunction(MeasureView); + RemoveAllChildren(node); + } + else + { + node.SetMeasureFunction(null); + // Create a list of all the subviews that we are going to use for layout. + var subviewsToInclude = new List(); + foreach (var subview in view.Subviews) + { + if (subview.GetIncludeYogaLayout()) + { + subviewsToInclude.Add(subview); + } + } + + var shouldReconstructChildList = false; + if (node.Count != subviewsToInclude.Count) + { + shouldReconstructChildList = true; + } + else + { + for (int i = 0; i < subviewsToInclude.Count; i++) + { + if (node[i] != GetYogaNode(subviewsToInclude[i])) + { + shouldReconstructChildList = true; + break; + } + } + } + + if (shouldReconstructChildList) + { + RemoveAllChildren(node); + + for (int i = 0; i < subviewsToInclude.Count; i++) + { + var subView = subviewsToInclude[i]; + node.Insert(i, subView.GetYogaNode()); + AttachNodesFromViewHierachy(subView); + } + } + } + } + + static void RemoveAllChildren(YogaNode node) + { + if (node == null) + return; + + while (node.Count > 0) + { + node.Clear(); + } + } + + + [DllImport("/usr/lib/libobjc.dylib")] + static extern void objc_setAssociatedObject(IntPtr @object, IntPtr key, IntPtr value, AssociationPolicy policy); + + [DllImport("/usr/lib/libobjc.dylib")] + static extern IntPtr objc_getAssociatedObject(IntPtr @object, IntPtr key); + + enum AssociationPolicy + { + ASSIGN = 0, + RETAIN_NONATOMIC = 1, + COPY_NONATOMIC = 3, + RETAIN = 01401, + COPY = 01403, + } + } + + class YGNodeBridge : NSObject + { + bool disposed; + internal WeakReference viewRef; + internal YogaNode node; + public YGNodeBridge() + { + node = new YogaNode(); + } + + public void SetContext(UIView view) + { + viewRef = new WeakReference(view); + YogaKit.Bridges.Add(node, this); + } + + protected override void Dispose(bool disposing) + { + if (disposing && !disposed) + { + disposed = true; + YogaKit.Bridges.Remove(node); + viewRef = null; + node = null; + } + base.Dispose(disposing); + } + } +} \ No newline at end of file diff --git a/csharp/Xamarin.iOS/Facebook.Yoga.iOS.Test/AppDelegate.cs b/csharp/Xamarin.iOS/Facebook.Yoga.iOS.Test/AppDelegate.cs new file mode 100644 index 00000000..8dee0ee7 --- /dev/null +++ b/csharp/Xamarin.iOS/Facebook.Yoga.iOS.Test/AppDelegate.cs @@ -0,0 +1,59 @@ +using Foundation; +using UIKit; + +namespace Facebook.Yoga.iOS.Test +{ + // The UIApplicationDelegate for the application. This class is responsible for launching the + // User Interface of the application, as well as listening (and optionally responding) to application events from iOS. + [Register("AppDelegate")] + public class AppDelegate : UIApplicationDelegate + { + // class-level declarations + + public override UIWindow Window + { + get; + set; + } + + public override bool FinishedLaunching(UIApplication application, NSDictionary launchOptions) + { + // Override point for customization after application launch. + // If not required for your application you can safely delete this method + + return true; + } + + public override void OnResignActivation(UIApplication application) + { + // Invoked when the application is about to move from active to inactive state. + // This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) + // or when the user quits the application and it begins the transition to the background state. + // Games should use this method to pause the game. + } + + public override void DidEnterBackground(UIApplication application) + { + // Use this method to release shared resources, save user data, invalidate timers and store the application state. + // If your application supports background exection this method is called instead of WillTerminate when the user quits. + } + + public override void WillEnterForeground(UIApplication application) + { + // Called as part of the transiton from background to active state. + // Here you can undo many of the changes made on entering the background. + } + + public override void OnActivated(UIApplication application) + { + // Restart any tasks that were paused (or not yet started) while the application was inactive. + // If the application was previously in the background, optionally refresh the user interface. + } + + public override void WillTerminate(UIApplication application) + { + // Called when the application is about to terminate. Save data, if needed. See also DidEnterBackground. + } + } +} + diff --git a/csharp/Xamarin.iOS/Facebook.Yoga.iOS.Test/Assets.xcassets/AppIcon.appiconset/Contents.json b/csharp/Xamarin.iOS/Facebook.Yoga.iOS.Test/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 00000000..4e646784 --- /dev/null +++ b/csharp/Xamarin.iOS/Facebook.Yoga.iOS.Test/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,157 @@ +{ + "images": [ + { + "idiom": "iphone", + "size": "29x29", + "scale": "1x" + }, + { + "idiom": "iphone", + "size": "29x29", + "scale": "2x" + }, + { + "idiom": "iphone", + "size": "29x29", + "scale": "3x" + }, + { + "idiom": "iphone", + "size": "40x40", + "scale": "2x" + }, + { + "idiom": "iphone", + "size": "40x40", + "scale": "3x" + }, + { + "idiom": "iphone", + "size": "57x57", + "scale": "1x" + }, + { + "idiom": "iphone", + "size": "57x57", + "scale": "2x" + }, + { + "idiom": "iphone", + "size": "60x60", + "scale": "2x" + }, + { + "idiom": "iphone", + "size": "60x60", + "scale": "3x" + }, + { + "idiom": "ipad", + "size": "29x29", + "scale": "1x" + }, + { + "idiom": "ipad", + "size": "29x29", + "scale": "2x" + }, + { + "idiom": "ipad", + "size": "40x40", + "scale": "1x" + }, + { + "idiom": "ipad", + "size": "40x40", + "scale": "2x" + }, + { + "idiom": "ipad", + "size": "50x50", + "scale": "1x" + }, + { + "idiom": "ipad", + "size": "50x50", + "scale": "2x" + }, + { + "idiom": "ipad", + "size": "72x72", + "scale": "1x" + }, + { + "idiom": "ipad", + "size": "72x72", + "scale": "2x" + }, + { + "idiom": "ipad", + "size": "76x76", + "scale": "1x" + }, + { + "idiom": "ipad", + "size": "76x76", + "scale": "2x" + }, + { + "size": "24x24", + "idiom": "watch", + "scale": "2x", + "role": "notificationCenter", + "subtype": "38mm" + }, + { + "size": "27.5x27.5", + "idiom": "watch", + "scale": "2x", + "role": "notificationCenter", + "subtype": "42mm" + }, + { + "size": "29x29", + "idiom": "watch", + "role": "companionSettings", + "scale": "2x" + }, + { + "size": "29x29", + "idiom": "watch", + "role": "companionSettings", + "scale": "3x" + }, + { + "size": "40x40", + "idiom": "watch", + "scale": "2x", + "role": "appLauncher", + "subtype": "38mm" + }, + { + "size": "44x44", + "idiom": "watch", + "scale": "2x", + "role": "longLook", + "subtype": "42mm" + }, + { + "size": "86x86", + "idiom": "watch", + "scale": "2x", + "role": "quickLook", + "subtype": "38mm" + }, + { + "size": "98x98", + "idiom": "watch", + "scale": "2x", + "role": "quickLook", + "subtype": "42mm" + } + ], + "info": { + "version": 1, + "author": "xcode" + } +} \ No newline at end of file diff --git a/csharp/Xamarin.iOS/Facebook.Yoga.iOS.Test/Assets.xcassets/Contents.json b/csharp/Xamarin.iOS/Facebook.Yoga.iOS.Test/Assets.xcassets/Contents.json new file mode 100644 index 00000000..4caf392f --- /dev/null +++ b/csharp/Xamarin.iOS/Facebook.Yoga.iOS.Test/Assets.xcassets/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/csharp/Xamarin.iOS/Facebook.Yoga.iOS.Test/Entitlements.plist b/csharp/Xamarin.iOS/Facebook.Yoga.iOS.Test/Entitlements.plist new file mode 100644 index 00000000..9ae59937 --- /dev/null +++ b/csharp/Xamarin.iOS/Facebook.Yoga.iOS.Test/Entitlements.plist @@ -0,0 +1,6 @@ + + + + + + diff --git a/csharp/Xamarin.iOS/Facebook.Yoga.iOS.Test/Facebook.Yoga.iOS.Test.csproj b/csharp/Xamarin.iOS/Facebook.Yoga.iOS.Test/Facebook.Yoga.iOS.Test.csproj new file mode 100644 index 00000000..88a27ac8 --- /dev/null +++ b/csharp/Xamarin.iOS/Facebook.Yoga.iOS.Test/Facebook.Yoga.iOS.Test.csproj @@ -0,0 +1,128 @@ + + + + Debug + iPhoneSimulator + {3B27656A-129D-4779-BDAD-1A088DFDD9C5} + {FEACFBD2-3405-455C-9665-78FE426C6842};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + Exe + Facebook.Yoga.iOS.Test + Facebook.Yoga.iOS.Test + Resources + + + true + full + false + bin\iPhoneSimulator\Debug + DEBUG;ENABLE_TEST_CLOUD; + prompt + 4 + iPhone Developer + true + true + true + true + true + 22979 + None + x86_64 + HttpClientHandler + Default + false + + + pdbonly + true + bin\iPhone\Release + + prompt + 4 + iPhone Developer + true + true + true + Entitlements.plist + SdkOnly + ARMv7, ARM64 + HttpClientHandler + Default + + + pdbonly + true + bin\iPhoneSimulator\Release + + prompt + 4 + iPhone Developer + true + true + None + x86_64 + HttpClientHandler + Default + + + true + full + false + bin\iPhone\Debug + DEBUG;ENABLE_TEST_CLOUD; + prompt + 4 + iPhone Developer + true + true + true + true + true + true + true + Entitlements.plist + SdkOnly + ARMv7, ARM64 + HttpClientHandler + Default + + + + + + + + + + + + + + + + + + + + + + + + + + + + ViewController.cs + + + + + {33B1B6BE-F415-4819-A5FB-CFFE2E40AD6E} + Facebook.YogaKit.iOS + + + {BE4CBFDA-02E2-4DF0-A81A-CEFB7987A708} + Facebook.Yoga.iOS + + + + \ No newline at end of file diff --git a/csharp/Xamarin.iOS/Facebook.Yoga.iOS.Test/Info.plist b/csharp/Xamarin.iOS/Facebook.Yoga.iOS.Test/Info.plist new file mode 100644 index 00000000..fd20287a --- /dev/null +++ b/csharp/Xamarin.iOS/Facebook.Yoga.iOS.Test/Info.plist @@ -0,0 +1,39 @@ + + + + + CFBundleName + Facebook.Yoga.iOS.Test + CFBundleIdentifier + com.xamarin.facebook-yoga-ios-test + CFBundleShortVersionString + 1.0 + CFBundleVersion + 1.0 + LSRequiresIPhoneOS + + MinimumOSVersion + 10.1 + UIDeviceFamily + + 1 + 2 + + UILaunchStoryboardName + LaunchScreen + UIMainStoryboardFile + Main + UIRequiredDeviceCapabilities + + armv7 + + UISupportedInterfaceOrientations + + UIInterfaceOrientationPortrait + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + XSAppIconAssets + Assets.xcassets/AppIcon.appiconset + + diff --git a/csharp/Xamarin.iOS/Facebook.Yoga.iOS.Test/LaunchScreen.storyboard b/csharp/Xamarin.iOS/Facebook.Yoga.iOS.Test/LaunchScreen.storyboard new file mode 100644 index 00000000..5d2e905a --- /dev/null +++ b/csharp/Xamarin.iOS/Facebook.Yoga.iOS.Test/LaunchScreen.storyboard @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/csharp/Xamarin.iOS/Facebook.Yoga.iOS.Test/Main.cs b/csharp/Xamarin.iOS/Facebook.Yoga.iOS.Test/Main.cs new file mode 100644 index 00000000..b2ba0f78 --- /dev/null +++ b/csharp/Xamarin.iOS/Facebook.Yoga.iOS.Test/Main.cs @@ -0,0 +1,15 @@ +using UIKit; + +namespace Facebook.Yoga.iOS.Test +{ + public class Application + { + // This is the main entry point of the application. + static void Main(string[] args) + { + // if you want to use a different Application Delegate class from "AppDelegate" + // you can specify it here. + UIApplication.Main(args, null, "AppDelegate"); + } + } +} diff --git a/csharp/Xamarin.iOS/Facebook.Yoga.iOS.Test/Main.storyboard b/csharp/Xamarin.iOS/Facebook.Yoga.iOS.Test/Main.storyboard new file mode 100644 index 00000000..a43ad72c --- /dev/null +++ b/csharp/Xamarin.iOS/Facebook.Yoga.iOS.Test/Main.storyboard @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/csharp/Xamarin.iOS/Facebook.Yoga.iOS.Test/ViewController.cs b/csharp/Xamarin.iOS/Facebook.Yoga.iOS.Test/ViewController.cs new file mode 100644 index 00000000..7bd8c1b9 --- /dev/null +++ b/csharp/Xamarin.iOS/Facebook.Yoga.iOS.Test/ViewController.cs @@ -0,0 +1,63 @@ +using System; +using CoreGraphics; +using Facebook.YogaKit.iOS; +using Foundation; +using UIKit; + +namespace Facebook.Yoga.iOS.Test +{ + + public partial class ViewController : UIViewController + { + protected ViewController(IntPtr handle) : base(handle) + { + // Note: this .ctor should not contain any initialization logic. + } + + public override void ViewDidLoad() + { + base.ViewDidLoad(); + + CreateViewHierarchy(View, View.Bounds.Size.Width, View.Bounds.Size.Height); + } + + static void CreateViewHierarchy(UIView root, nfloat width, nfloat height) + { + root.BackgroundColor = UIColor.Red; + + root.UsesYoga(true); + root.YogaWidth(width); + root.YogaWidth(height); + root.YogaAlignItems(YogaAlign.Center); + root.YogaJustify(YogaJustify.Center); + + var child1 = new UIView { BackgroundColor = UIColor.Blue }; + child1.YogaWidth(100); + child1.YogaHeight(100); + child1.UsesYoga(true); + + var child2 = new UIView + { + BackgroundColor = UIColor.Green, + Frame = new CGRect { Size = new CGSize(200, 100) } + }; + + var child3 = new UIView + { + BackgroundColor = UIColor.Yellow, + Frame = new CGRect { Size = new CGSize(100, 100) } + }; + + child2.AddSubview(child3); + root.AddSubview(child1); + root.AddSubview(child2); + root.YogaApplyLayout(); + } + + public override void DidReceiveMemoryWarning() + { + base.DidReceiveMemoryWarning(); + // Release any cached data, images, etc that aren't in use. + } + } +} diff --git a/csharp/Xamarin.iOS/Facebook.Yoga.iOS.Test/ViewController.designer.cs b/csharp/Xamarin.iOS/Facebook.Yoga.iOS.Test/ViewController.designer.cs new file mode 100644 index 00000000..5527c480 --- /dev/null +++ b/csharp/Xamarin.iOS/Facebook.Yoga.iOS.Test/ViewController.designer.cs @@ -0,0 +1,17 @@ +// +// This file has been generated automatically by MonoDevelop to store outlets and +// actions made in the Xcode designer. If it is removed, they will be lost. +// Manual changes to this file may not be handled correctly. +// +using Foundation; + +namespace Facebook.Yoga.iOS.Test +{ + [Register("ViewController")] + partial class ViewController + { + void ReleaseDesignerOutlets() + { + } + } +} diff --git a/csharp/Xamarin.iOS/Facebook.Yoga.iOS.sln b/csharp/Xamarin.iOS/Facebook.Yoga.iOS.sln new file mode 100644 index 00000000..cec625fe --- /dev/null +++ b/csharp/Xamarin.iOS/Facebook.Yoga.iOS.sln @@ -0,0 +1,57 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 2012 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Facebook.Yoga.iOS.Test", "Facebook.Yoga.iOS.Test\Facebook.Yoga.iOS.Test.csproj", "{3B27656A-129D-4779-BDAD-1A088DFDD9C5}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Facebook.YogaKit.iOS", "Facebook.YogaKit.iOS\Facebook.YogaKit.iOS.csproj", "{33B1B6BE-F415-4819-A5FB-CFFE2E40AD6E}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Facebook.Yoga.iOS", "Facebook.Yoga.iOS\Facebook.Yoga.iOS.csproj", "{BE4CBFDA-02E2-4DF0-A81A-CEFB7987A708}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + Debug|iPhoneSimulator = Debug|iPhoneSimulator + Release|iPhone = Release|iPhone + Release|iPhoneSimulator = Release|iPhoneSimulator + Debug|iPhone = Debug|iPhone + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {3B27656A-129D-4779-BDAD-1A088DFDD9C5}.Debug|Any CPU.ActiveCfg = Debug|iPhoneSimulator + {3B27656A-129D-4779-BDAD-1A088DFDD9C5}.Debug|Any CPU.Build.0 = Debug|iPhoneSimulator + {3B27656A-129D-4779-BDAD-1A088DFDD9C5}.Release|Any CPU.ActiveCfg = Release|iPhone + {3B27656A-129D-4779-BDAD-1A088DFDD9C5}.Release|Any CPU.Build.0 = Release|iPhone + {3B27656A-129D-4779-BDAD-1A088DFDD9C5}.Debug|iPhoneSimulator.ActiveCfg = Debug|iPhoneSimulator + {3B27656A-129D-4779-BDAD-1A088DFDD9C5}.Debug|iPhoneSimulator.Build.0 = Debug|iPhoneSimulator + {3B27656A-129D-4779-BDAD-1A088DFDD9C5}.Release|iPhone.ActiveCfg = Release|iPhone + {3B27656A-129D-4779-BDAD-1A088DFDD9C5}.Release|iPhone.Build.0 = Release|iPhone + {3B27656A-129D-4779-BDAD-1A088DFDD9C5}.Release|iPhoneSimulator.ActiveCfg = Release|iPhoneSimulator + {3B27656A-129D-4779-BDAD-1A088DFDD9C5}.Release|iPhoneSimulator.Build.0 = Release|iPhoneSimulator + {3B27656A-129D-4779-BDAD-1A088DFDD9C5}.Debug|iPhone.ActiveCfg = Debug|iPhone + {3B27656A-129D-4779-BDAD-1A088DFDD9C5}.Debug|iPhone.Build.0 = Debug|iPhone + {33B1B6BE-F415-4819-A5FB-CFFE2E40AD6E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {33B1B6BE-F415-4819-A5FB-CFFE2E40AD6E}.Debug|Any CPU.Build.0 = Debug|Any CPU + {33B1B6BE-F415-4819-A5FB-CFFE2E40AD6E}.Release|Any CPU.ActiveCfg = Release|Any CPU + {33B1B6BE-F415-4819-A5FB-CFFE2E40AD6E}.Release|Any CPU.Build.0 = Release|Any CPU + {33B1B6BE-F415-4819-A5FB-CFFE2E40AD6E}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {33B1B6BE-F415-4819-A5FB-CFFE2E40AD6E}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU + {33B1B6BE-F415-4819-A5FB-CFFE2E40AD6E}.Release|iPhone.ActiveCfg = Release|Any CPU + {33B1B6BE-F415-4819-A5FB-CFFE2E40AD6E}.Release|iPhone.Build.0 = Release|Any CPU + {33B1B6BE-F415-4819-A5FB-CFFE2E40AD6E}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU + {33B1B6BE-F415-4819-A5FB-CFFE2E40AD6E}.Release|iPhoneSimulator.Build.0 = Release|Any CPU + {33B1B6BE-F415-4819-A5FB-CFFE2E40AD6E}.Debug|iPhone.ActiveCfg = Debug|Any CPU + {33B1B6BE-F415-4819-A5FB-CFFE2E40AD6E}.Debug|iPhone.Build.0 = Debug|Any CPU + {BE4CBFDA-02E2-4DF0-A81A-CEFB7987A708}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {BE4CBFDA-02E2-4DF0-A81A-CEFB7987A708}.Debug|Any CPU.Build.0 = Debug|Any CPU + {BE4CBFDA-02E2-4DF0-A81A-CEFB7987A708}.Release|Any CPU.ActiveCfg = Release|Any CPU + {BE4CBFDA-02E2-4DF0-A81A-CEFB7987A708}.Release|Any CPU.Build.0 = Release|Any CPU + {BE4CBFDA-02E2-4DF0-A81A-CEFB7987A708}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {BE4CBFDA-02E2-4DF0-A81A-CEFB7987A708}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU + {BE4CBFDA-02E2-4DF0-A81A-CEFB7987A708}.Release|iPhone.ActiveCfg = Release|Any CPU + {BE4CBFDA-02E2-4DF0-A81A-CEFB7987A708}.Release|iPhone.Build.0 = Release|Any CPU + {BE4CBFDA-02E2-4DF0-A81A-CEFB7987A708}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU + {BE4CBFDA-02E2-4DF0-A81A-CEFB7987A708}.Release|iPhoneSimulator.Build.0 = Release|Any CPU + {BE4CBFDA-02E2-4DF0-A81A-CEFB7987A708}.Debug|iPhone.ActiveCfg = Debug|Any CPU + {BE4CBFDA-02E2-4DF0-A81A-CEFB7987A708}.Debug|iPhone.Build.0 = Debug|Any CPU + EndGlobalSection +EndGlobal diff --git a/csharp/Xamarin.iOS/Facebook.Yoga.iOS/ApiDefinition.cs b/csharp/Xamarin.iOS/Facebook.Yoga.iOS/ApiDefinition.cs new file mode 100644 index 00000000..2d178004 --- /dev/null +++ b/csharp/Xamarin.iOS/Facebook.Yoga.iOS/ApiDefinition.cs @@ -0,0 +1,11 @@ +using System; + +using UIKit; +using Foundation; +using ObjCRuntime; +using CoreGraphics; + +namespace Facebook.Yoga.iOS +{ + // The build will fail without ApiDefinition.cs +} diff --git a/csharp/Xamarin.iOS/Facebook.Yoga.iOS/CustomBuildAction.targets b/csharp/Xamarin.iOS/Facebook.Yoga.iOS/CustomBuildAction.targets new file mode 100644 index 00000000..d29173f2 --- /dev/null +++ b/csharp/Xamarin.iOS/Facebook.Yoga.iOS/CustomBuildAction.targets @@ -0,0 +1,10 @@ + + + + CopyInNativeLib;$(CompileDependsOn) + + + + + + \ No newline at end of file diff --git a/csharp/Xamarin.iOS/Facebook.Yoga.iOS/Facebook.Yoga.iOS.csproj b/csharp/Xamarin.iOS/Facebook.Yoga.iOS/Facebook.Yoga.iOS.csproj new file mode 100644 index 00000000..21d5f45d --- /dev/null +++ b/csharp/Xamarin.iOS/Facebook.Yoga.iOS/Facebook.Yoga.iOS.csproj @@ -0,0 +1,121 @@ + + + + Debug + AnyCPU + {BE4CBFDA-02E2-4DF0-A81A-CEFB7987A708} + {8FFB629D-F513-41CE-95D2-7ECE97B6EEEC};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + Library + Facebook.Yoga.iOS + Facebook.Yoga.iOS + Resources + + + true + full + false + bin\Debug + DEBUG; + prompt + 4 + true + + + true + bin\Release + prompt + 4 + true + + + + + + + + + + MeasureFunction.cs + + + MeasureOutput.cs + + + Native.cs + + + Spacing.cs + + + YogaAlign.cs + + + YogaConstants.cs + + + YogaDimension.cs + + + YogaDirection.cs + + + YogaEdge.cs + + + YogaExperimentalFeature.cs + + + YogaFlexDirection.cs + + + YogaJustify.cs + + + YogaLogger.cs + + + YogaLogLevel.cs + + + YogaMeasureFunc.cs + + + YogaMeasureMode.cs + + + YogaNode.Create.cs + + + YogaNode.cs + + + YogaOverflow.cs + + + YogaPositionType.cs + + + YogaPrintOptions.cs + + + YogaSize.cs + + + YogaWrap.cs + + + + + + + + + + + Static + False + + + + + \ No newline at end of file diff --git a/csharp/Xamarin.iOS/Facebook.Yoga.iOS/Facebook.Yoga.sln b/csharp/Xamarin.iOS/Facebook.Yoga.iOS/Facebook.Yoga.sln new file mode 100644 index 00000000..cb7bfe38 --- /dev/null +++ b/csharp/Xamarin.iOS/Facebook.Yoga.iOS/Facebook.Yoga.sln @@ -0,0 +1,67 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 2012 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Facebook.Yoga.iOS", "Facebook.Yoga.iOS.csproj", "{128FB32A-C4A1-4363-BF06-0A36E700B7FA}" +EndProject +Project("{D954291E-2A0B-460D-934E-DC6B0785DB48}") = "Facebook.YogaKit.Shared", "..\..\Facebook.YogaKit\Facebook.YogaKit.Shared.shproj", "{A24B3BA6-3143-4FFF-B8B8-1EDF166F5F4A}" +EndProject +Project("{D954291E-2A0B-460D-934E-DC6B0785DB48}") = "Facebook.Yoga.Shared", "..\..\Facebook.Yoga\Facebook.Yoga.Shared.shproj", "{91C42D32-291D-4B72-90B4-551663D60B8B}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Facebook.YogaKit.iOS", "..\Facebook.YogaKit.iOS\Facebook.YogaKit.iOS.csproj", "{0C38AA9D-3178-4B43-9C3B-3C97A90FB1B0}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Facebook.YogaKit.iOS.Sample", "..\Facebook.YogaKit.iOS.Sample\Facebook.YogaKit.iOS.Sample.csproj", "{6A094B74-FA9A-4E49-A8E1-F450A04E3E5B}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Shared", "Shared", "{89A39C6B-6A7B-4458-872B-A0456550CAA6}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + Debug|iPhoneSimulator = Debug|iPhoneSimulator + Release|iPhone = Release|iPhone + Release|iPhoneSimulator = Release|iPhoneSimulator + Debug|iPhone = Debug|iPhone + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {128FB32A-C4A1-4363-BF06-0A36E700B7FA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {128FB32A-C4A1-4363-BF06-0A36E700B7FA}.Debug|Any CPU.Build.0 = Debug|Any CPU + {128FB32A-C4A1-4363-BF06-0A36E700B7FA}.Release|Any CPU.ActiveCfg = Release|Any CPU + {128FB32A-C4A1-4363-BF06-0A36E700B7FA}.Release|Any CPU.Build.0 = Release|Any CPU + {128FB32A-C4A1-4363-BF06-0A36E700B7FA}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {128FB32A-C4A1-4363-BF06-0A36E700B7FA}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU + {128FB32A-C4A1-4363-BF06-0A36E700B7FA}.Release|iPhone.ActiveCfg = Release|Any CPU + {128FB32A-C4A1-4363-BF06-0A36E700B7FA}.Release|iPhone.Build.0 = Release|Any CPU + {128FB32A-C4A1-4363-BF06-0A36E700B7FA}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU + {128FB32A-C4A1-4363-BF06-0A36E700B7FA}.Release|iPhoneSimulator.Build.0 = Release|Any CPU + {128FB32A-C4A1-4363-BF06-0A36E700B7FA}.Debug|iPhone.ActiveCfg = Debug|Any CPU + {128FB32A-C4A1-4363-BF06-0A36E700B7FA}.Debug|iPhone.Build.0 = Debug|Any CPU + {0C38AA9D-3178-4B43-9C3B-3C97A90FB1B0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {0C38AA9D-3178-4B43-9C3B-3C97A90FB1B0}.Debug|Any CPU.Build.0 = Debug|Any CPU + {0C38AA9D-3178-4B43-9C3B-3C97A90FB1B0}.Release|Any CPU.ActiveCfg = Release|Any CPU + {0C38AA9D-3178-4B43-9C3B-3C97A90FB1B0}.Release|Any CPU.Build.0 = Release|Any CPU + {0C38AA9D-3178-4B43-9C3B-3C97A90FB1B0}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {0C38AA9D-3178-4B43-9C3B-3C97A90FB1B0}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU + {0C38AA9D-3178-4B43-9C3B-3C97A90FB1B0}.Release|iPhone.ActiveCfg = Release|Any CPU + {0C38AA9D-3178-4B43-9C3B-3C97A90FB1B0}.Release|iPhone.Build.0 = Release|Any CPU + {0C38AA9D-3178-4B43-9C3B-3C97A90FB1B0}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU + {0C38AA9D-3178-4B43-9C3B-3C97A90FB1B0}.Release|iPhoneSimulator.Build.0 = Release|Any CPU + {0C38AA9D-3178-4B43-9C3B-3C97A90FB1B0}.Debug|iPhone.ActiveCfg = Debug|Any CPU + {0C38AA9D-3178-4B43-9C3B-3C97A90FB1B0}.Debug|iPhone.Build.0 = Debug|Any CPU + {6A094B74-FA9A-4E49-A8E1-F450A04E3E5B}.Debug|Any CPU.ActiveCfg = Debug|iPhoneSimulator + {6A094B74-FA9A-4E49-A8E1-F450A04E3E5B}.Debug|Any CPU.Build.0 = Debug|iPhoneSimulator + {6A094B74-FA9A-4E49-A8E1-F450A04E3E5B}.Release|Any CPU.ActiveCfg = Release|iPhone + {6A094B74-FA9A-4E49-A8E1-F450A04E3E5B}.Release|Any CPU.Build.0 = Release|iPhone + {6A094B74-FA9A-4E49-A8E1-F450A04E3E5B}.Debug|iPhoneSimulator.ActiveCfg = Debug|iPhoneSimulator + {6A094B74-FA9A-4E49-A8E1-F450A04E3E5B}.Debug|iPhoneSimulator.Build.0 = Debug|iPhoneSimulator + {6A094B74-FA9A-4E49-A8E1-F450A04E3E5B}.Release|iPhone.ActiveCfg = Release|iPhone + {6A094B74-FA9A-4E49-A8E1-F450A04E3E5B}.Release|iPhone.Build.0 = Release|iPhone + {6A094B74-FA9A-4E49-A8E1-F450A04E3E5B}.Release|iPhoneSimulator.ActiveCfg = Release|iPhoneSimulator + {6A094B74-FA9A-4E49-A8E1-F450A04E3E5B}.Release|iPhoneSimulator.Build.0 = Release|iPhoneSimulator + {6A094B74-FA9A-4E49-A8E1-F450A04E3E5B}.Debug|iPhone.ActiveCfg = Debug|iPhone + {6A094B74-FA9A-4E49-A8E1-F450A04E3E5B}.Debug|iPhone.Build.0 = Debug|iPhone + EndGlobalSection + GlobalSection(NestedProjects) = preSolution + {91C42D32-291D-4B72-90B4-551663D60B8B} = {89A39C6B-6A7B-4458-872B-A0456550CAA6} + {A24B3BA6-3143-4FFF-B8B8-1EDF166F5F4A} = {89A39C6B-6A7B-4458-872B-A0456550CAA6} + EndGlobalSection +EndGlobal diff --git a/csharp/Xamarin.iOS/Facebook.Yoga.iOS/Properties/AssemblyInfo.cs b/csharp/Xamarin.iOS/Facebook.Yoga.iOS/Properties/AssemblyInfo.cs new file mode 100644 index 00000000..232777a9 --- /dev/null +++ b/csharp/Xamarin.iOS/Facebook.Yoga.iOS/Properties/AssemblyInfo.cs @@ -0,0 +1,34 @@ +using System.Reflection; +using System.Runtime.CompilerServices; + +using Foundation; + +// This attribute allows you to mark your assemblies as “safe to link”. +// When the attribute is present, the linker—if enabled—will process the assembly +// even if you’re using the “Link SDK assemblies only” option, which is the default for device builds. + +[assembly: LinkerSafe] + +// Information about this assembly is defined by the following attributes. +// Change them to the values specific to your project. + +[assembly: AssemblyTitle("Facebook.Yoga.iOS")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("")] +[assembly: AssemblyCopyright("rmarinho")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// The assembly version has the format "{Major}.{Minor}.{Build}.{Revision}". +// The form "{Major}.{Minor}.*" will automatically update the build and revision, +// and "{Major}.{Minor}.{Build}.*" will update just the revision. + +[assembly: AssemblyVersion("1.0.*")] + +// The following attributes are used to specify the signing key for the assembly, +// if desired. See the Mono documentation for more information about signing. + +//[assembly: AssemblyDelaySign(false)] +//[assembly: AssemblyKeyFile("")] diff --git a/csharp/Xamarin.iOS/Facebook.YogaKit.iOS.Sample/AppDelegate.cs b/csharp/Xamarin.iOS/Facebook.YogaKit.iOS.Sample/AppDelegate.cs new file mode 100644 index 00000000..b59ca105 --- /dev/null +++ b/csharp/Xamarin.iOS/Facebook.YogaKit.iOS.Sample/AppDelegate.cs @@ -0,0 +1,59 @@ +using Foundation; +using UIKit; + +namespace Facebook.YogaKit.iOS.Sample +{ + // The UIApplicationDelegate for the application. This class is responsible for launching the + // User Interface of the application, as well as listening (and optionally responding) to application events from iOS. + [Register("AppDelegate")] + public class AppDelegate : UIApplicationDelegate + { + // class-level declarations + + public override UIWindow Window + { + get; + set; + } + + public override bool FinishedLaunching(UIApplication application, NSDictionary launchOptions) + { + // Override point for customization after application launch. + // If not required for your application you can safely delete this method + + return true; + } + + public override void OnResignActivation(UIApplication application) + { + // Invoked when the application is about to move from active to inactive state. + // This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) + // or when the user quits the application and it begins the transition to the background state. + // Games should use this method to pause the game. + } + + public override void DidEnterBackground(UIApplication application) + { + // Use this method to release shared resources, save user data, invalidate timers and store the application state. + // If your application supports background exection this method is called instead of WillTerminate when the user quits. + } + + public override void WillEnterForeground(UIApplication application) + { + // Called as part of the transiton from background to active state. + // Here you can undo many of the changes made on entering the background. + } + + public override void OnActivated(UIApplication application) + { + // Restart any tasks that were paused (or not yet started) while the application was inactive. + // If the application was previously in the background, optionally refresh the user interface. + } + + public override void WillTerminate(UIApplication application) + { + // Called when the application is about to terminate. Save data, if needed. See also DidEnterBackground. + } + } +} + diff --git a/csharp/Xamarin.iOS/Facebook.YogaKit.iOS.Sample/Assets.xcassets/AppIcon.appiconset/Contents.json b/csharp/Xamarin.iOS/Facebook.YogaKit.iOS.Sample/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 00000000..4e646784 --- /dev/null +++ b/csharp/Xamarin.iOS/Facebook.YogaKit.iOS.Sample/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,157 @@ +{ + "images": [ + { + "idiom": "iphone", + "size": "29x29", + "scale": "1x" + }, + { + "idiom": "iphone", + "size": "29x29", + "scale": "2x" + }, + { + "idiom": "iphone", + "size": "29x29", + "scale": "3x" + }, + { + "idiom": "iphone", + "size": "40x40", + "scale": "2x" + }, + { + "idiom": "iphone", + "size": "40x40", + "scale": "3x" + }, + { + "idiom": "iphone", + "size": "57x57", + "scale": "1x" + }, + { + "idiom": "iphone", + "size": "57x57", + "scale": "2x" + }, + { + "idiom": "iphone", + "size": "60x60", + "scale": "2x" + }, + { + "idiom": "iphone", + "size": "60x60", + "scale": "3x" + }, + { + "idiom": "ipad", + "size": "29x29", + "scale": "1x" + }, + { + "idiom": "ipad", + "size": "29x29", + "scale": "2x" + }, + { + "idiom": "ipad", + "size": "40x40", + "scale": "1x" + }, + { + "idiom": "ipad", + "size": "40x40", + "scale": "2x" + }, + { + "idiom": "ipad", + "size": "50x50", + "scale": "1x" + }, + { + "idiom": "ipad", + "size": "50x50", + "scale": "2x" + }, + { + "idiom": "ipad", + "size": "72x72", + "scale": "1x" + }, + { + "idiom": "ipad", + "size": "72x72", + "scale": "2x" + }, + { + "idiom": "ipad", + "size": "76x76", + "scale": "1x" + }, + { + "idiom": "ipad", + "size": "76x76", + "scale": "2x" + }, + { + "size": "24x24", + "idiom": "watch", + "scale": "2x", + "role": "notificationCenter", + "subtype": "38mm" + }, + { + "size": "27.5x27.5", + "idiom": "watch", + "scale": "2x", + "role": "notificationCenter", + "subtype": "42mm" + }, + { + "size": "29x29", + "idiom": "watch", + "role": "companionSettings", + "scale": "2x" + }, + { + "size": "29x29", + "idiom": "watch", + "role": "companionSettings", + "scale": "3x" + }, + { + "size": "40x40", + "idiom": "watch", + "scale": "2x", + "role": "appLauncher", + "subtype": "38mm" + }, + { + "size": "44x44", + "idiom": "watch", + "scale": "2x", + "role": "longLook", + "subtype": "42mm" + }, + { + "size": "86x86", + "idiom": "watch", + "scale": "2x", + "role": "quickLook", + "subtype": "38mm" + }, + { + "size": "98x98", + "idiom": "watch", + "scale": "2x", + "role": "quickLook", + "subtype": "42mm" + } + ], + "info": { + "version": 1, + "author": "xcode" + } +} \ No newline at end of file diff --git a/csharp/Xamarin.iOS/Facebook.YogaKit.iOS.Sample/Assets.xcassets/Contents.json b/csharp/Xamarin.iOS/Facebook.YogaKit.iOS.Sample/Assets.xcassets/Contents.json new file mode 100644 index 00000000..4caf392f --- /dev/null +++ b/csharp/Xamarin.iOS/Facebook.YogaKit.iOS.Sample/Assets.xcassets/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/csharp/Xamarin.iOS/Facebook.YogaKit.iOS.Sample/Entitlements.plist b/csharp/Xamarin.iOS/Facebook.YogaKit.iOS.Sample/Entitlements.plist new file mode 100644 index 00000000..9ae59937 --- /dev/null +++ b/csharp/Xamarin.iOS/Facebook.YogaKit.iOS.Sample/Entitlements.plist @@ -0,0 +1,6 @@ + + + + + + diff --git a/csharp/Xamarin.iOS/Facebook.YogaKit.iOS.Sample/Facebook.YogaKit.iOS.Sample.csproj b/csharp/Xamarin.iOS/Facebook.YogaKit.iOS.Sample/Facebook.YogaKit.iOS.Sample.csproj new file mode 100644 index 00000000..d94eb930 --- /dev/null +++ b/csharp/Xamarin.iOS/Facebook.YogaKit.iOS.Sample/Facebook.YogaKit.iOS.Sample.csproj @@ -0,0 +1,128 @@ + + + + Debug + iPhoneSimulator + {6A094B74-FA9A-4E49-A8E1-F450A04E3E5B} + {FEACFBD2-3405-455C-9665-78FE426C6842};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + Exe + Facebook.YogaKit.iOS.Sample + Facebook.YogaKit.iOS.Sample + Resources + + + true + full + false + bin\iPhoneSimulator\Debug + DEBUG;ENABLE_TEST_CLOUD;__IOS__ + prompt + 4 + iPhone Developer + true + true + true + true + true + 56768 + None + x86_64 + HttpClientHandler + Default + false + + + pdbonly + true + bin\iPhone\Release + + prompt + 4 + iPhone Developer + true + true + true + Entitlements.plist + SdkOnly + ARMv7, ARM64 + HttpClientHandler + Default + + + + true + bin\iPhoneSimulator\Release + + prompt + 4 + iPhone Developer + true + true + None + x86_64 + HttpClientHandler + Default + + + true + full + false + bin\iPhone\Debug + DEBUG;ENABLE_TEST_CLOUD; + prompt + 4 + iPhone Developer + true + true + true + true + true + true + true + Entitlements.plist + SdkOnly + ARMv7, ARM64 + HttpClientHandler + Default + + + + + + + + + + + + + + + + + + + + + + + + + + + + ViewController.cs + + + + + {0C38AA9D-3178-4B43-9C3B-3C97A90FB1B0} + Facebook.YogaKit.iOS + + + {128FB32A-C4A1-4363-BF06-0A36E700B7FA} + Facebook.Yoga.iOS + + + + \ No newline at end of file diff --git a/csharp/Xamarin.iOS/Facebook.YogaKit.iOS.Sample/Info.plist b/csharp/Xamarin.iOS/Facebook.YogaKit.iOS.Sample/Info.plist new file mode 100644 index 00000000..0c6a791e --- /dev/null +++ b/csharp/Xamarin.iOS/Facebook.YogaKit.iOS.Sample/Info.plist @@ -0,0 +1,39 @@ + + + + + CFBundleName + Facebook.YogaKit.iOS.Sample + CFBundleIdentifier + com.xamarin.facebook-yogakit-ios-sample + CFBundleShortVersionString + 1.0 + CFBundleVersion + 1.0 + LSRequiresIPhoneOS + + MinimumOSVersion + 10.2 + UIDeviceFamily + + 1 + 2 + + UILaunchStoryboardName + LaunchScreen + UIMainStoryboardFile + Main + UIRequiredDeviceCapabilities + + armv7 + + UISupportedInterfaceOrientations + + UIInterfaceOrientationPortrait + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + XSAppIconAssets + Assets.xcassets/AppIcon.appiconset + + diff --git a/csharp/Xamarin.iOS/Facebook.YogaKit.iOS.Sample/LaunchScreen.storyboard b/csharp/Xamarin.iOS/Facebook.YogaKit.iOS.Sample/LaunchScreen.storyboard new file mode 100644 index 00000000..5d2e905a --- /dev/null +++ b/csharp/Xamarin.iOS/Facebook.YogaKit.iOS.Sample/LaunchScreen.storyboard @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/csharp/Xamarin.iOS/Facebook.YogaKit.iOS.Sample/Main.cs b/csharp/Xamarin.iOS/Facebook.YogaKit.iOS.Sample/Main.cs new file mode 100644 index 00000000..f87df673 --- /dev/null +++ b/csharp/Xamarin.iOS/Facebook.YogaKit.iOS.Sample/Main.cs @@ -0,0 +1,15 @@ +using UIKit; + +namespace Facebook.YogaKit.iOS.Sample +{ + public class Application + { + // This is the main entry point of the application. + static void Main(string[] args) + { + // if you want to use a different Application Delegate class from "AppDelegate" + // you can specify it here. + UIApplication.Main(args, null, "AppDelegate"); + } + } +} diff --git a/csharp/Xamarin.iOS/Facebook.YogaKit.iOS.Sample/Main.storyboard b/csharp/Xamarin.iOS/Facebook.YogaKit.iOS.Sample/Main.storyboard new file mode 100644 index 00000000..a43ad72c --- /dev/null +++ b/csharp/Xamarin.iOS/Facebook.YogaKit.iOS.Sample/Main.storyboard @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/csharp/Xamarin.iOS/Facebook.YogaKit.iOS.Sample/ViewController.cs b/csharp/Xamarin.iOS/Facebook.YogaKit.iOS.Sample/ViewController.cs new file mode 100644 index 00000000..072c8851 --- /dev/null +++ b/csharp/Xamarin.iOS/Facebook.YogaKit.iOS.Sample/ViewController.cs @@ -0,0 +1,60 @@ +using System; +using CoreGraphics; +using Facebook.Yoga; +using UIKit; + +namespace Facebook.YogaKit.iOS.Sample +{ + public partial class ViewController : UIViewController + { + protected ViewController(IntPtr handle) : base(handle) + { + // Note: this .ctor should not contain any initialization logic. + } + + public override void ViewDidLoad() + { + base.ViewDidLoad(); + CreateViewHierarchy(View, View.Bounds.Size.Width, View.Bounds.Size.Height); + } + + static void CreateViewHierarchy(UIView root, nfloat width, nfloat height) + { + root.BackgroundColor = UIColor.Red; + + root.UsesYoga(true); + root.YogaWidth(width); + root.YogaWidth(height); + root.YogaAlignItems(YogaAlign.Center); + root.YogaJustify(YogaJustify.Center); + + var child1 = new UIView { BackgroundColor = UIColor.Blue }; + child1.YogaWidth(100); + child1.YogaHeight(100); + child1.UsesYoga(true); + + var child2 = new UIView + { + BackgroundColor = UIColor.Green, + Frame = new CGRect { Size = new CGSize(200, 100) } + }; + + var child3 = new UIView + { + BackgroundColor = UIColor.Yellow, + Frame = new CGRect { Size = new CGSize(100, 100) } + }; + + child2.AddSubview(child3); + root.AddSubview(child1); + root.AddSubview(child2); + root.YogaApplyLayout(); + } + + public override void DidReceiveMemoryWarning() + { + base.DidReceiveMemoryWarning(); + // Release any cached data, images, etc that aren't in use. + } + } +} diff --git a/csharp/Xamarin.iOS/Facebook.YogaKit.iOS.Sample/ViewController.designer.cs b/csharp/Xamarin.iOS/Facebook.YogaKit.iOS.Sample/ViewController.designer.cs new file mode 100644 index 00000000..810950d0 --- /dev/null +++ b/csharp/Xamarin.iOS/Facebook.YogaKit.iOS.Sample/ViewController.designer.cs @@ -0,0 +1,17 @@ +// +// This file has been generated automatically by MonoDevelop to store outlets and +// actions made in the Xcode designer. If it is removed, they will be lost. +// Manual changes to this file may not be handled correctly. +// +using Foundation; + +namespace Facebook.YogaKit.iOS.Sample +{ + [Register("ViewController")] + partial class ViewController + { + void ReleaseDesignerOutlets() + { + } + } +} diff --git a/csharp/Xamarin.iOS/Facebook.YogaKit.iOS/Facebook.YogaKit.iOS.csproj b/csharp/Xamarin.iOS/Facebook.YogaKit.iOS/Facebook.YogaKit.iOS.csproj new file mode 100644 index 00000000..ce348067 --- /dev/null +++ b/csharp/Xamarin.iOS/Facebook.YogaKit.iOS/Facebook.YogaKit.iOS.csproj @@ -0,0 +1,67 @@ + + + + Debug + AnyCPU + {0C38AA9D-3178-4B43-9C3B-3C97A90FB1B0} + {FEACFBD2-3405-455C-9665-78FE426C6842};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + Library + Facebook.YogaKit.iOS + Facebook.YogaKit.iOS + Resources + + + true + full + false + bin\Debug + DEBUG;__IOS__ + prompt + 4 + iPhone Developer + true + true + true + true + true + 53781 + false + SdkOnly + HttpClientHandler + Default + + + pdbonly + true + bin\Release + + prompt + 4 + iPhone Developer + true + true + SdkOnly + HttpClientHandler + Default + + + + + + + + + + + + + + + + {128FB32A-C4A1-4363-BF06-0A36E700B7FA} + Facebook.Yoga.iOS + + + + + \ No newline at end of file diff --git a/csharp/Xamarin.iOS/Facebook.YogaKit.iOS/Properties/AssemblyInfo.cs b/csharp/Xamarin.iOS/Facebook.YogaKit.iOS/Properties/AssemblyInfo.cs new file mode 100644 index 00000000..944ab239 --- /dev/null +++ b/csharp/Xamarin.iOS/Facebook.YogaKit.iOS/Properties/AssemblyInfo.cs @@ -0,0 +1,26 @@ +using System.Reflection; +using System.Runtime.CompilerServices; + +// Information about this assembly is defined by the following attributes. +// Change them to the values specific to your project. + +[assembly: AssemblyTitle("Facebook.YogaKit.iOS")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("")] +[assembly: AssemblyCopyright("rmarinho")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// The assembly version has the format "{Major}.{Minor}.{Build}.{Revision}". +// The form "{Major}.{Minor}.*" will automatically update the build and revision, +// and "{Major}.{Minor}.{Build}.*" will update just the revision. + +[assembly: AssemblyVersion("1.0.*")] + +// The following attributes are used to specify the signing key for the assembly, +// if desired. See the Mono documentation for more information about signing. + +//[assembly: AssemblyDelaySign(false)] +//[assembly: AssemblyKeyFile("")] diff --git a/csharp/Xamarin.iOS/Facebook.YogaKit.iOS/YogaKit.cs b/csharp/Xamarin.iOS/Facebook.YogaKit.iOS/YogaKit.cs new file mode 100644 index 00000000..7e7cd7b6 --- /dev/null +++ b/csharp/Xamarin.iOS/Facebook.YogaKit.iOS/YogaKit.cs @@ -0,0 +1,180 @@ +using System; +using System.Collections.Generic; +using Facebook.Yoga; +#if __IOS__ +using NativeView = UIKit.UIView; +#endif + +namespace Facebook.YogaKit.iOS +{ + public static class YogaKit + { + internal static Dictionary Bridges = new Dictionary(); + + public static void UsesYoga(this NativeView view, bool usesYoga) + { + YogaKitNative.UsesYoga(view, usesYoga); + } + + public static bool GetUsesYoga(this NativeView view) + { + return YogaKitNative.GetUsesYoga(view); + } + + public static void IncludeYogaLayout(this NativeView view, bool includeInLayout) + { + YogaKitNative.IncludeYogaLayout(view, includeInLayout); + } + + public static bool GetIncludeYogaLayout(this NativeView view) + { + return YogaKitNative.GetIncludeYogaLayout(view); + } + + public static void YogaWidth(this NativeView view, nfloat width) + { + var node = GetYogaNode(view); + node.Width = (float)width; + } + + public static void YogaHeight(this NativeView view, nfloat height) + { + var node = GetYogaNode(view); + node.Height = (float)height; + } + + public static void YogaMinWidth(this NativeView view, float minWidth) + { + var node = GetYogaNode(view); + node.MinWidth = minWidth; + } + + public static void YogaMinHeight(this NativeView view, float minHeight) + { + var node = GetYogaNode(view); + node.MinHeight = minHeight; + } + + public static void YogaMaxWidth(this NativeView view, float maxWidth) + { + var node = GetYogaNode(view); + node.MaxWidth = maxWidth; + } + + public static void YogaMaxHeight(this NativeView view, float maxHeight) + { + var node = GetYogaNode(view); + node.MaxHeight = maxHeight; + } + + public static void YogaAlignItems(this NativeView view, YogaAlign align) + { + var node = GetYogaNode(view); + node.AlignItems = align; + } + + public static void YogaJustify(this NativeView view, YogaJustify justify) + { + var node = GetYogaNode(view); + node.JustifyContent = justify; + } + + public static void YogaAlign(this NativeView view, YogaAlign align) + { + var node = GetYogaNode(view); + node.AlignContent = align; + } + + public static void YogaAlignSelf(this NativeView view, YogaAlign align) + { + var node = GetYogaNode(view); + node.AlignSelf = align; + } + + public static void YogaDirection(this NativeView view, YogaDirection direction) + { + var node = GetYogaNode(view); + node.StyleDirection = direction; + } + + public static void YogaFlexDirection(this NativeView view, YogaFlexDirection direction) + { + var node = GetYogaNode(view); + node.FlexDirection = direction; + } + + public static void YogaPositionType(this NativeView view, YogaPositionType position) + { + var node = GetYogaNode(view); + node.PositionType = position; + } + + public static void YogaFlexWrap(this NativeView view, YogaWrap wrap) + { + var node = GetYogaNode(view); + node.Wrap = wrap; + } + + public static void YogaFlexShrink(this NativeView view, float shrink) + { + var node = GetYogaNode(view); + node.FlexShrink = shrink; + } + + public static void YogaFlexGrow(this NativeView view, float grow) + { + var node = GetYogaNode(view); + node.FlexGrow = grow; + } + + public static void YogaFlexBasis(this NativeView view, float basis) + { + var node = GetYogaNode(view); + node.FlexBasis = basis; + } + + public static void YogaPositionForEdge(this NativeView view, float position, YogaEdge edge) + { + var node = GetYogaNode(view); + node.SetPosition(edge, position); + } + + public static void YogaMarginForEdge(this NativeView view, float margin, YogaEdge edge) + { + var node = GetYogaNode(view); + node.SetMargin(edge, margin); + } + + public static void YogaPaddingForEdge(this NativeView view, float padding, YogaEdge edge) + { + var node = GetYogaNode(view); + node.SetPadding(edge, padding); + } + + public static void YogaAspectRation(this NativeView view, float ratio) + { + var node = GetYogaNode(view); + node.StyleAspectRatio = ratio; + } + + #region Layout and Sizing + public static void YogaApplyLayout(this NativeView view) + { + YogaKitNative.CalculateLayoutWithSize(view, view.Bounds.Size); + YogaKitNative.ApplyLayoutToViewHierarchy(view); + } + + public static YogaDirection YogaResolvedDirection(this NativeView view) + { + var node = GetYogaNode(view); + return node.LayoutDirection; + } + + #endregion + + public static YogaNode GetYogaNode(this NativeView view) + { + return YogaKitNative.GetYogaNode(view); + } + } +} diff --git a/csharp/Xamarin.iOS/Facebook.YogaKit.iOS/YogaKitNative.cs b/csharp/Xamarin.iOS/Facebook.YogaKit.iOS/YogaKitNative.cs new file mode 100644 index 00000000..cbe4da26 --- /dev/null +++ b/csharp/Xamarin.iOS/Facebook.YogaKit.iOS/YogaKitNative.cs @@ -0,0 +1,253 @@ +using System; +using System.Collections.Generic; +using System.Runtime.InteropServices; +using CoreGraphics; +using Facebook.Yoga; +using Foundation; +using UIKit; + +namespace Facebook.YogaKit.iOS +{ + internal static class YogaKitNative + { + static NSString YogaNodeKey = new NSString("YogaNode"); + + static NSString UsesYogaKey = new NSString("UsesYoga"); + + static NSString IncludeYogaKey = new NSString("UsesYoga"); + + public static void UsesYoga(UIView view, bool usesYoga) + { + var value = NSNumber.FromBoolean(usesYoga); + objc_setAssociatedObject(view.Handle, UsesYogaKey.Handle, value.Handle, AssociationPolicy.RETAIN_NONATOMIC); + } + + public static bool GetUsesYoga(UIView view) + { + var value = ObjCRuntime.Runtime.GetNSObject(objc_getAssociatedObject(view.Handle, UsesYogaKey.Handle)) as NSNumber; + return value == null ? false : value.BoolValue; + } + + public static void IncludeYogaLayout(UIView view, bool includeInLayout) + { + var value = NSNumber.FromBoolean(includeInLayout); + objc_setAssociatedObject(view.Handle, IncludeYogaKey.Handle, value.Handle, AssociationPolicy.RETAIN_NONATOMIC); + } + + public static bool GetIncludeYogaLayout(UIView view) + { + var value = ObjCRuntime.Runtime.GetNSObject(objc_getAssociatedObject(view.Handle, IncludeYogaKey.Handle)) as NSNumber; + return value == null ? true : value.BoolValue; + } + + public static YogaNode GetYogaNode(UIView view) + { + var value = ObjCRuntime.Runtime.GetNSObject(objc_getAssociatedObject(view.Handle, YogaNodeKey.Handle)) as YGNodeBridge; + if (value == null) + { + value = new YGNodeBridge(); + value.SetContext(view); + objc_setAssociatedObject(view.Handle, YogaNodeKey.Handle, value.Handle, AssociationPolicy.RETAIN_NONATOMIC); + } + return value.node; + } + + public static CGSize CalculateLayoutWithSize(UIView view, CGSize size) + { + if (!view.GetUsesYoga()) + { + System.Diagnostics.Debug.WriteLine("Doesn't use Yoga"); + } + AttachNodesFromViewHierachy(view); + var node = GetYogaNode(view); + + node.Width = (float)size.Width; + node.Height = (float)size.Height; + node.CalculateLayout(); + + return new CGSize { Width = node.LayoutWidth, Height = node.LayoutHeight }; + } + + public static void ApplyLayoutToViewHierarchy(UIView view) + { + if (!view.GetIncludeYogaLayout()) + return; + + var node = GetYogaNode(view); + CGPoint topLeft = new CGPoint(node.LayoutX, node.LayoutY); + CGPoint bottomRight = new CGPoint(topLeft.X + node.LayoutWidth, topLeft.Y + node.LayoutHeight); + view.Frame = new CGRect(RoundPixelValue(topLeft.X), RoundPixelValue(topLeft.Y), RoundPixelValue(bottomRight.X) - RoundPixelValue(topLeft.X), RoundPixelValue(bottomRight.Y) - RoundPixelValue(topLeft.Y)); + bool isLeaf = !view.GetUsesYoga() || view.Subviews.Length == 0; + if (!isLeaf) + { + for (int i = 0; i < view.Subviews.Length; i++) + { + ApplyLayoutToViewHierarchy(view.Subviews[i]); + } + } + } + + public static CGSize YogaIntrinsicSize(this UIView view) + { + var constrainedSize = new CGSize + { + Width = float.NaN, + Height = float.NaN + }; + return CalculateLayoutWithSize(view, constrainedSize); + } + + static long MeasureView(YogaNode node, float width, YogaMeasureMode widthMode, float height, YogaMeasureMode heightMode) + { + var constrainedWidth = (widthMode == YogaMeasureMode.Undefined) ? nfloat.MaxValue : width; + var constrainedHeight = (heightMode == YogaMeasureMode.Undefined) ? nfloat.MaxValue : height; + + UIView view = null; + if (YogaKit.Bridges.ContainsKey(node)) + (YogaKit.Bridges[node] as YGNodeBridge).viewRef.TryGetTarget(out view); + + var sizeThatFits = view.SizeThatFits(new CGSize(constrainedWidth, constrainedHeight)); + + var finalWidth = SanitizeMeasurement(constrainedWidth, sizeThatFits.Width, widthMode); + var finalHeight = SanitizeMeasurement(constrainedHeight, sizeThatFits.Height, heightMode); + + return MeasureOutput.Make(finalWidth, finalHeight); + } + + static float SanitizeMeasurement(nfloat constrainedSize, nfloat measuredSize, YogaMeasureMode measureMode) + { + float result; + if (measureMode == YogaMeasureMode.Exactly) + { + result = (float)constrainedSize; + } + else if (measureMode == YogaMeasureMode.AtMost) + { + result = (float)Math.Min(constrainedSize, measuredSize); + } + else { + result = (float)measuredSize; + } + + return result; + + } + + static double RoundPixelValue(nfloat value) + { + nfloat scale = UIScreen.MainScreen.Scale; + + return Math.Round(value * scale) / scale; + } + + static void AttachNodesFromViewHierachy(UIView view) + { + var node = GetYogaNode(view); + + // Only leaf nodes should have a measure function + if (!view.GetUsesYoga() || view.Subviews.Length == 0) + { + node.SetMeasureFunction(MeasureView); + RemoveAllChildren(node); + } + else + { + node.SetMeasureFunction(null); + // Create a list of all the subviews that we are going to use for layout. + var subviewsToInclude = new List(); + foreach (var subview in view.Subviews) + { + if (subview.GetIncludeYogaLayout()) + { + subviewsToInclude.Add(subview); + } + } + + var shouldReconstructChildList = false; + if (node.Count != subviewsToInclude.Count) + { + shouldReconstructChildList = true; + } + else + { + for (int i = 0; i < subviewsToInclude.Count; i++) + { + if (node[i] != GetYogaNode(subviewsToInclude[i])) + { + shouldReconstructChildList = true; + break; + } + } + } + + if (shouldReconstructChildList) + { + RemoveAllChildren(node); + + for (int i = 0; i < subviewsToInclude.Count; i++) + { + var subView = subviewsToInclude[i]; + node.Insert(i, subView.GetYogaNode()); + AttachNodesFromViewHierachy(subView); + } + } + } + } + + static void RemoveAllChildren(YogaNode node) + { + if (node == null) + return; + + while (node.Count > 0) + { + node.Clear(); + } + } + + + [DllImport("/usr/lib/libobjc.dylib")] + static extern void objc_setAssociatedObject(IntPtr @object, IntPtr key, IntPtr value, AssociationPolicy policy); + + [DllImport("/usr/lib/libobjc.dylib")] + static extern IntPtr objc_getAssociatedObject(IntPtr @object, IntPtr key); + + enum AssociationPolicy + { + ASSIGN = 0, + RETAIN_NONATOMIC = 1, + COPY_NONATOMIC = 3, + RETAIN = 01401, + COPY = 01403, + } + } + + class YGNodeBridge : NSObject + { + bool disposed; + internal WeakReference viewRef; + internal YogaNode node; + public YGNodeBridge() + { + node = new YogaNode(); + } + + public void SetContext(UIView view) + { + viewRef = new WeakReference(view); + YogaKit.Bridges.Add(node, this); + } + + protected override void Dispose(bool disposing) + { + if (disposing && !disposed) + { + disposed = true; + YogaKit.Bridges.Remove(node); + viewRef = null; + node = null; + } + base.Dispose(disposing); + } + } +}