From e2a7938b267cd0f93b0d3cc18bc017b793f76af0 Mon Sep 17 00:00:00 2001 From: Ben Holcomb Date: Sat, 7 Jan 2017 10:23:02 -0800 Subject: [PATCH] Revert D4386906: [YogaKit] Improved the objective-c and swift api Summary: This reverts commit 05ac0e571ef3a8ff0be31469e449a7b23f102218 Differential Revision: D4386906 fbshipit-source-id: adac0d8e71ce9f3442f3bfd14b5157f88367c998 --- YogaKit/Tests/YogaKitTests.m | 214 +++++----- YogaKit/UIView+Yoga.h | 70 ++- YogaKit/UIView+Yoga.m | 403 +++++++++++++++++- YogaKit/YGLayout+Private.h | 16 - YogaKit/YGLayout.h | 114 ----- YogaKit/YGLayout.m | 380 ----------------- .../YogaKitSample.xcodeproj/project.pbxproj | 31 +- .../YogaKitSample/SwiftViewController.swift | 40 -- .../YogaKitSample/ViewController.m | 18 +- .../YogaKitSample-Bridging-Header.h | 10 - enums.py | 8 +- yoga/YGEnums.h | 56 +-- yoga/YGMacros.h | 16 - 13 files changed, 609 insertions(+), 767 deletions(-) delete mode 100644 YogaKit/YGLayout+Private.h delete mode 100644 YogaKit/YGLayout.h delete mode 100644 YogaKit/YGLayout.m delete mode 100644 YogaKit/YogaKitSample/YogaKitSample/SwiftViewController.swift delete mode 100644 YogaKit/YogaKitSample/YogaKitSample/YogaKitSample-Bridging-Header.h diff --git a/YogaKit/Tests/YogaKitTests.m b/YogaKit/Tests/YogaKitTests.m index 79f7043c..bdade66e 100644 --- a/YogaKit/Tests/YogaKitTests.m +++ b/YogaKit/Tests/YogaKitTests.m @@ -23,7 +23,7 @@ XCTAssertEqual(0, YGNodeGetInstanceCount()); UIView *view = [[UIView alloc] initWithFrame:CGRectZero]; - view.yoga.flexBasis = 1; + [view yg_setFlexBasis:1]; XCTAssertEqual(1, YGNodeGetInstanceCount()); view = nil; @@ -35,11 +35,11 @@ XCTAssertEqual(0, YGNodeGetInstanceCount()); UIView *view = [[UIView alloc] initWithFrame:CGRectZero]; - view.yoga.flexBasis = 1; + [view yg_setFlexBasis:1]; for (int i=0; i<10; i++) { UIView *subview = [[UIView alloc] initWithFrame:CGRectZero]; - subview.yoga.flexBasis = 1; + [subview yg_setFlexBasis:1]; [view addSubview:subview]; } XCTAssertEqual(11, YGNodeGetInstanceCount()); @@ -53,69 +53,69 @@ - (void)testUsesYoga { UIView *view = [[UIView alloc] initWithFrame:CGRectZero]; - XCTAssertFalse(view.yoga.isEnabled); + XCTAssertFalse([view yg_usesYoga]); - view.yoga.isEnabled = YES; - XCTAssertTrue(view.yoga.isEnabled); + [view yg_setUsesYoga:YES]; + XCTAssertTrue([view yg_usesYoga]); - view.yoga.isEnabled = NO; - XCTAssertFalse(view.yoga.isEnabled); + [view yg_setUsesYoga:NO]; + XCTAssertFalse([view yg_usesYoga]); } - (void)testSizeThatFitsAsserts { UIView *view = [[UIView alloc] initWithFrame:CGRectZero]; dispatch_sync(dispatch_queue_create("com.facebook.Yoga.testing", DISPATCH_QUEUE_SERIAL), ^(void){ - XCTAssertThrows(view.yoga.intrinsicSize); + XCTAssertThrows([view yg_intrinsicSize]); }); } - (void)testSizeThatFitsSmoke { UIView *container = [[UIView alloc] initWithFrame:CGRectZero]; - container.yoga.isEnabled = YES; - container.yoga.flexDirection = YGFlexDirectionRow; - container.yoga.alignItems = YGAlignFlexStart; + [container yg_setUsesYoga:YES]; + [container yg_setFlexDirection:YGFlexDirectionRow]; + [container yg_setAlignItems:YGAlignFlexStart]; UILabel *longTextLabel = [[UILabel alloc] initWithFrame:CGRectZero]; longTextLabel.text = @"This is a very very very very very very very very long piece of text."; longTextLabel.lineBreakMode = NSLineBreakByTruncatingTail; longTextLabel.numberOfLines = 1; - longTextLabel.yoga.isEnabled = YES; - longTextLabel.yoga.flexShrink = 1; + [longTextLabel yg_setUsesYoga:YES]; + [longTextLabel yg_setFlexShrink:1]; [container addSubview:longTextLabel]; UIView *textBadgeView = [[UIView alloc] initWithFrame:CGRectZero]; - textBadgeView.yoga.isEnabled = YES; - textBadgeView.yoga.marginLeft = 3.0; - textBadgeView.yoga.width = 10; - textBadgeView.yoga.height = 10; + [textBadgeView yg_setUsesYoga:YES]; + [textBadgeView yg_setMargin:3.0 forEdge:YGEdgeLeft]; + [textBadgeView yg_setWidth:10]; + [textBadgeView yg_setHeight:10]; [container addSubview:textBadgeView]; - const CGSize containerSize = container.yoga.intrinsicSize; + const CGSize containerSize = [container yg_intrinsicSize]; XCTAssertTrue(CGSizeEqualToSize(CGSizeMake(514,21), containerSize), @"Size is actually %@", NSStringFromCGSize(containerSize)); } - (void)testThatMarkingLeafsAsDirtyWillTriggerASizeRecalculation { UIView *container = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 500, 50)]; - container.yoga.isEnabled = YES; - container.yoga.flexDirection = YGFlexDirectionRow; - container.yoga.alignItems = YGAlignFlexStart; + [container yg_setUsesYoga:YES]; + [container yg_setFlexDirection:YGFlexDirectionRow]; + [container yg_setAlignItems:YGAlignFlexStart]; UILabel *label = [[UILabel alloc] initWithFrame:CGRectZero]; label.text = @"This is a short text."; label.numberOfLines = 1; - label.yoga.isEnabled = YES; + [label yg_setUsesYoga:YES]; [container addSubview:label]; - [container.yoga applyLayout]; + [container yg_applyLayout]; XCTAssertTrue(CGSizeEqualToSize(CGSizeMake(146,21), label.bounds.size), @"Size is actually %@", NSStringFromCGSize(label.bounds.size)); label.text = @"This is a slightly longer text."; - [label.yoga markDirty]; + [label yg_markDirty]; - [container.yoga applyLayout]; + [container yg_applyLayout]; XCTAssertTrue(CGSizeEqualToSize(CGSizeMake(213,21), label.bounds.size), @"Size is actually %@", NSStringFromCGSize(label.bounds.size)); } @@ -124,17 +124,17 @@ const CGSize containerSize = CGSizeMake(320, 50); UIView *container = [[UIView alloc] initWithFrame:CGRectMake(0, 0, containerSize.width, containerSize.height)]; - container.yoga.isEnabled = YES; - container.yoga.flexDirection = YGFlexDirectionRow; + [container yg_setUsesYoga:YES]; + [container yg_setFlexDirection:YGFlexDirectionRow]; for (int i = 0; i < 3; i++) { UIView *subview = [[UIView alloc] initWithFrame:CGRectZero]; - subview.yoga.isEnabled = YES; - subview.yoga.flexGrow = 1; + [subview yg_setUsesYoga:YES]; + [subview yg_setFlexGrow:1]; [container addSubview:subview]; } - [container.yoga applyLayout]; + [container yg_applyLayout]; XCTAssertFalse(CGRectIntersectsRect([container.subviews objectAtIndex:0].frame, [container.subviews objectAtIndex:1].frame)); XCTAssertFalse(CGRectIntersectsRect([container.subviews objectAtIndex:1].frame, [container.subviews objectAtIndex:2].frame)); @@ -153,33 +153,33 @@ const CGSize containerSize = CGSizeMake(300, 50); UIView *container = [[UIView alloc] initWithFrame:CGRectMake(0, 0, containerSize.width, containerSize.height)]; - container.yoga.isEnabled = YES; - container.yoga.flexDirection = YGFlexDirectionRow; + [container yg_setUsesYoga:YES]; + [container yg_setFlexDirection:YGFlexDirectionRow]; UIView *subview1 = [[UIView alloc] initWithFrame:CGRectZero]; - subview1.yoga.isEnabled = YES; - subview1.yoga.flexGrow = 1; + [subview1 yg_setUsesYoga:YES]; + [subview1 yg_setFlexGrow:1]; [container addSubview:subview1]; UIView *subview2 = [[UIView alloc] initWithFrame:CGRectZero]; - subview2.yoga.isEnabled = YES; - subview2.yoga.flexGrow = 1; + [subview2 yg_setUsesYoga:YES]; + [subview2 yg_setFlexGrow:1]; [container addSubview:subview2]; UIView *subview3 = [[UIView alloc] initWithFrame:CGRectZero]; - subview3.yoga.isEnabled = YES; - subview3.yoga.flexGrow = 1; + [subview3 yg_setUsesYoga:YES]; + [subview3 yg_setFlexGrow:1]; [container addSubview:subview3]; - [container.yoga applyLayout]; + [container yg_applyLayout]; XCTAssertTrue(CGRectEqualToRect(subview1.frame, CGRectMake(0, 0, 100, 50))); XCTAssertTrue(CGRectEqualToRect(subview2.frame, CGRectMake(100, 0, 100, 50)), @"It's actually %@", NSStringFromCGRect(subview2.frame)); XCTAssertTrue(CGRectEqualToRect(subview3.frame, CGRectMake(200, 0, 100, 50))); [container exchangeSubviewAtIndex:2 withSubviewAtIndex:0]; - subview2.yoga.isIncludedInLayout = NO; - [container.yoga applyLayout]; + [subview2 yg_setIncludeInLayout:NO]; + [container yg_applyLayout]; XCTAssertTrue(CGRectEqualToRect(subview3.frame, CGRectMake(0, 0, 150, 50))); XCTAssertTrue(CGRectEqualToRect(subview1.frame, CGRectMake(150, 0, 150, 50))); @@ -193,32 +193,32 @@ const CGSize containerSize = CGSizeMake(300, 50); UIView *container = [[UIView alloc] initWithFrame:CGRectMake(0, 0, containerSize.width, containerSize.height)]; - container.yoga.isEnabled = YES; - container.yoga.flexDirection = YGFlexDirectionRow; + [container yg_setUsesYoga:YES]; + [container yg_setFlexDirection:YGFlexDirectionRow]; UIView *subview1 = [[UIView alloc] initWithFrame:CGRectZero]; - subview1.yoga.isEnabled = YES; - subview1.yoga.flexGrow = 1; + [subview1 yg_setUsesYoga:YES]; + [subview1 yg_setFlexGrow:1]; [container addSubview:subview1]; UIView *subview2 = [[UIView alloc] initWithFrame:CGRectZero]; - subview2.yoga.isEnabled = YES; - subview2.yoga.flexGrow = 1; + [subview2 yg_setUsesYoga:YES]; + [subview2 yg_setFlexGrow:1]; [container addSubview:subview2]; UIView *subview3 = [[UIView alloc] initWithFrame:CGRectZero]; - subview3.yoga.isEnabled = YES; - subview3.yoga.flexGrow = 1; + [subview3 yg_setUsesYoga:YES]; + [subview3 yg_setFlexGrow:1]; [container addSubview:subview3]; - [container.yoga applyLayout]; + [container yg_applyLayout]; for (UIView *view in container.subviews) { XCTAssertTrue(CGSizeEqualToSize(CGSizeMake(100, 50), subview1.bounds.size), @"Actual size is %@", NSStringFromCGSize(view.bounds.size)); } - subview3.yoga.isIncludedInLayout = NO; - [container.yoga applyLayout]; + [subview3 yg_setIncludeInLayout:NO]; + [container yg_applyLayout]; XCTAssertTrue(CGSizeEqualToSize(CGSizeMake(150, 50), subview1.bounds.size), @"Actual size is %@", NSStringFromCGSize(subview1.bounds.size)); XCTAssertTrue(CGSizeEqualToSize(CGSizeMake(150, 50), subview2.bounds.size), @"Actual size is %@", NSStringFromCGSize(subview2.bounds.size)); @@ -230,62 +230,62 @@ - (void)testThatNumberOfChildrenIsCorrectWhenWeIgnoreSubviews { UIView *container = [[UIView alloc] initWithFrame:CGRectZero]; - container.yoga.isEnabled = YES; - container.yoga.flexDirection = YGFlexDirectionRow; + [container yg_setUsesYoga:YES]; + [container yg_setFlexDirection:YGFlexDirectionRow]; UIView *subview1 = [[UIView alloc] initWithFrame:CGRectZero]; - subview1.yoga.isEnabled = YES; - subview1.yoga.isIncludedInLayout = NO; + [subview1 yg_setUsesYoga:YES]; + [subview1 yg_setIncludeInLayout:NO]; [container addSubview:subview1]; UIView *subview2 = [[UIView alloc] initWithFrame:CGRectZero]; - subview2.yoga.isEnabled = YES; - subview2.yoga.isIncludedInLayout = NO; + [subview2 yg_setUsesYoga:YES]; + [subview2 yg_setIncludeInLayout:NO]; [container addSubview:subview2]; UIView *subview3 = [[UIView alloc] initWithFrame:CGRectZero]; - subview3.yoga.isEnabled = YES; - subview3.yoga.isIncludedInLayout = YES; + [subview3 yg_setUsesYoga:YES]; + [subview3 yg_setIncludeInLayout:YES]; [container addSubview:subview3]; - [container.yoga applyLayout]; - XCTAssertEqual(1, container.yoga.numberOfChildren); + [container yg_applyLayout]; + XCTAssertEqual(1, [container yg_numberOfChildren]); - subview2.yoga.isIncludedInLayout = YES; - [container.yoga applyLayout]; - XCTAssertEqual(2, container.yoga.numberOfChildren); + [subview2 yg_setIncludeInLayout:YES]; + [container yg_applyLayout]; + XCTAssertEqual(2, [container yg_numberOfChildren]); } - (void)testThatViewNotIncludedInFirstLayoutPassAreIncludedInSecond { UIView *container = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 300, 50)]; - container.yoga.isEnabled = YES; - container.yoga.flexDirection = YGFlexDirectionRow; + [container yg_setUsesYoga:YES]; + [container yg_setFlexDirection:YGFlexDirectionRow]; UIView *subview1 = [[UIView alloc] initWithFrame:CGRectZero]; - subview1.yoga.isEnabled = YES; - subview1.yoga.flexGrow = 1; + [subview1 yg_setUsesYoga:YES]; + [subview1 yg_setFlexGrow:1]; [container addSubview:subview1]; UIView *subview2 = [[UIView alloc] initWithFrame:CGRectZero]; - subview2.yoga.isEnabled = YES; - subview2.yoga.flexGrow = 1; + [subview2 yg_setUsesYoga:YES]; + [subview2 yg_setFlexGrow:1]; [container addSubview:subview2]; UIView *subview3 = [[UIView alloc] initWithFrame:CGRectZero]; - subview3.yoga.isEnabled = YES; - subview3.yoga.flexGrow = 1; - subview3.yoga.isIncludedInLayout = NO; + [subview3 yg_setUsesYoga:YES]; + [subview3 yg_setFlexGrow:1]; + [subview3 yg_setIncludeInLayout:NO]; [container addSubview:subview3]; - [container.yoga applyLayout]; + [container yg_applyLayout]; XCTAssertTrue(CGSizeEqualToSize(CGSizeMake(150, 50), subview1.bounds.size), @"Actual size is %@", NSStringFromCGSize(subview1.bounds.size)); XCTAssertTrue(CGSizeEqualToSize(CGSizeMake(150, 50), subview2.bounds.size), @"Actual size is %@", NSStringFromCGSize(subview2.bounds.size)); XCTAssertTrue(CGSizeEqualToSize(CGSizeZero, subview3.bounds.size), @"Actual size %@", NSStringFromCGSize(subview3.bounds.size)); - subview3.yoga.isIncludedInLayout = YES; - [container.yoga applyLayout]; + [subview3 yg_setIncludeInLayout:YES]; + [container yg_applyLayout]; for (UIView *view in container.subviews) { XCTAssertTrue(CGSizeEqualToSize(CGSizeMake(100, 50), subview1.bounds.size), @"Actual size is %@", NSStringFromCGSize(view.bounds.size)); } @@ -294,60 +294,60 @@ - (void)testyg_isLeafFlag { UIView *view = [[UIView alloc] initWithFrame:CGRectZero]; - XCTAssertTrue(view.yoga.isLeaf); + XCTAssertTrue(view.yg_isLeaf); for (int i=0; i<10; i++) { UIView *subview = [[UIView alloc] initWithFrame:CGRectZero]; [view addSubview:subview]; } - XCTAssertTrue(view.yoga.isLeaf); + XCTAssertTrue(view.yg_isLeaf); - view.yoga.isEnabled = YES; - view.yoga.width = 50.0; - XCTAssertTrue(view.yoga.isLeaf); + [view yg_setUsesYoga:YES]; + [view yg_setWidth:50.0]; + XCTAssertTrue(view.yg_isLeaf); UIView *const subview = view.subviews[0]; - subview.yoga.isEnabled = YES; - subview.yoga.width = 50.0; - XCTAssertFalse(view.yoga.isLeaf); + [subview yg_setUsesYoga:YES]; + [subview yg_setWidth:50.0]; + XCTAssertFalse(view.yg_isLeaf); } - (void)testThatWeCorrectlyAttachNestedViews { UIView *container = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 300, 50)]; - container.yoga.isEnabled = YES; - container.yoga.flexDirection = YGFlexDirectionColumn; + [container yg_setUsesYoga:YES]; + [container yg_setFlexDirection:YGFlexDirectionColumn]; UIView *subview1 = [[UIView alloc] initWithFrame:CGRectZero]; - subview1.yoga.isEnabled = YES; - subview1.yoga.width = 100; - subview1.yoga.flexGrow = 1; - subview1.yoga.flexDirection = YGFlexDirectionColumn; + [subview1 yg_setUsesYoga:YES]; + [subview1 yg_setWidth:100]; + [subview1 yg_setFlexGrow:1]; + [subview1 yg_setFlexDirection:YGFlexDirectionColumn]; [container addSubview:subview1]; UIView *subview2 = [[UIView alloc] initWithFrame:CGRectZero]; - subview2.yoga.isEnabled = YES; - subview2.yoga.width = 150; - subview2.yoga.flexGrow = 1; - subview2.yoga.flexDirection = YGFlexDirectionColumn; + [subview2 yg_setUsesYoga:YES]; + [subview2 yg_setWidth:150]; + [subview2 yg_setFlexGrow:1]; + [subview2 yg_setFlexDirection:YGFlexDirectionColumn]; [container addSubview:subview2]; for (UIView *view in @[subview1, subview2]) { UIView *someView = [[UIView alloc] initWithFrame:CGRectZero]; - someView.yoga.isEnabled = YES; - someView.yoga.flexGrow = 1; + [someView yg_setUsesYoga:YES]; + [someView yg_setFlexGrow:1]; [view addSubview:someView]; } - [container.yoga applyLayout]; + [container yg_applyLayout]; // Add the same amount of new views, reapply layout. for (UIView *view in @[subview1, subview2]) { UIView *someView = [[UIView alloc] initWithFrame:CGRectZero]; - someView.yoga.isEnabled = YES; - someView.yoga.flexGrow = 1; + [someView yg_setUsesYoga:YES]; + [someView yg_setFlexGrow:1]; [view addSubview:someView]; } - [container.yoga applyLayout]; + [container yg_applyLayout]; XCTAssertTrue(CGSizeEqualToSize(CGSizeMake(100, 25), subview1.bounds.size), @"Actual size is %@", NSStringFromCGSize(subview1.bounds.size)); for (UIView *subview in subview1.subviews) { @@ -369,19 +369,19 @@ - (void)testThatANonLeafNodeCanBecomeALeafNode { UIView *container = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 300, 50)]; - container.yoga.isEnabled = YES; + [container yg_setUsesYoga:YES]; UIView *subview1 = [[UIView alloc] initWithFrame:CGRectZero]; - subview1.yoga.isEnabled = YES; + [subview1 yg_setUsesYoga:YES]; [container addSubview:subview1]; UIView *subview2 = [[UIView alloc] initWithFrame:CGRectZero]; - subview2.yoga.isEnabled = YES; + [subview2 yg_setUsesYoga:YES]; [subview1 addSubview:subview2]; - [container.yoga applyLayout]; + [container yg_applyLayout]; [subview2 removeFromSuperview]; - [container.yoga applyLayout]; + [container yg_applyLayout]; } @end diff --git a/YogaKit/UIView+Yoga.h b/YogaKit/UIView+Yoga.h index 70e91917..b565b1ae 100644 --- a/YogaKit/UIView+Yoga.h +++ b/YogaKit/UIView+Yoga.h @@ -8,10 +8,76 @@ */ #import -#import "YGLayout.h" +#import @interface UIView (Yoga) -@property (nonatomic, readonly, strong) YGLayout *yoga; +/** + The property that decides if we should include this view when calculating layout. Defaults to YES. + */ +@property (nonatomic, readwrite, assign, setter=yg_setIncludeInLayout:) BOOL yg_includeInLayout; + +/** + The property that decides during layout/sizing whether or not yg_* properties should be applied. Defaults to NO. + */ +@property (nonatomic, readwrite, assign, setter=yg_setUsesYoga:) BOOL yg_usesYoga; + +- (void)yg_setDirection:(YGDirection)direction; +- (void)yg_setFlexDirection:(YGFlexDirection)flexDirection; +- (void)yg_setJustifyContent:(YGJustify)justifyContent; +- (void)yg_setAlignContent:(YGAlign)alignContent; +- (void)yg_setAlignItems:(YGAlign)alignItems; +- (void)yg_setAlignSelf:(YGAlign)alignSelf; +- (void)yg_setPositionType:(YGPositionType)positionType; +- (void)yg_setFlexWrap:(YGWrap)flexWrap; +- (void)yg_setOverflow:(YGOverflow)overflow; + +- (void)yg_setFlexGrow:(CGFloat)flexGrow; +- (void)yg_setFlexShrink:(CGFloat)flexShrink; +- (void)yg_setFlexBasis:(CGFloat)flexBasis; + +- (void)yg_setPosition:(CGFloat)position forEdge:(YGEdge)edge; +- (void)yg_setMargin:(CGFloat)margin forEdge:(YGEdge)edge; +- (void)yg_setPadding:(CGFloat)padding forEdge:(YGEdge)edge; + +- (void)yg_setWidth:(CGFloat)width; +- (void)yg_setHeight:(CGFloat)height; +- (void)yg_setMinWidth:(CGFloat)minWidth; +- (void)yg_setMinHeight:(CGFloat)minHeight; +- (void)yg_setMaxWidth:(CGFloat)maxWidth; +- (void)yg_setMaxHeight:(CGFloat)maxHeight; + +// Yoga specific properties, not compatible with flexbox specification +- (void)yg_setAspectRatio:(CGFloat)aspectRatio; + +/** + Get the resolved direction of this node. This won't be YGDirectionInherit + */ +- (YGDirection)yg_resolvedDirection; + +/** + Perform a layout calculation and update the frames of the views in the hierarchy with the results + */ +- (void)yg_applyLayout; + +/** + Returns the size of the view if no constraints were given. This could equivalent to calling [self sizeThatFits:CGSizeMake(CGFLOAT_MAX, CGFLOAT_MAX)]; + */ +- (CGSize)yg_intrinsicSize; + +/** + Returns the number of children that are using Flexbox. + */ +- (NSUInteger)yg_numberOfChildren; + +/** + Return a BOOL indiciating whether or not we this node contains any subviews that are included in Yoga's layout. + */ +- (BOOL)yg_isLeaf; + +/** + Mark that a view's layout needs to be recalculated. Only works for leaf views. + */ +- (void)yg_markDirty; @end diff --git a/YogaKit/UIView+Yoga.m b/YogaKit/UIView+Yoga.m index 66b7eed0..cfe0afa0 100644 --- a/YogaKit/UIView+Yoga.m +++ b/YogaKit/UIView+Yoga.m @@ -8,23 +8,404 @@ */ #import "UIView+Yoga.h" -#import "YGLayout+Private.h" + #import -static const void *kYGYogaAssociatedKey = &kYGYogaAssociatedKey; +static const void *kYGNodeBridgeAssociatedKey = &kYGNodeBridgeAssociatedKey; -@implementation UIView (YogaKit) +@interface YGNodeBridge : NSObject +@property (nonatomic, assign, readonly) YGNodeRef cnode; +@end -- (YGLayout *)yoga +@implementation YGNodeBridge + ++ (void)initialize { - YGLayout *yoga = objc_getAssociatedObject(self, kYGYogaAssociatedKey); - if (!yoga) { - yoga = [[YGLayout alloc] initWithView:self]; - objc_setAssociatedObject(self, kYGYogaAssociatedKey, yoga, OBJC_ASSOCIATION_RETAIN_NONATOMIC); - } - - return yoga; + YGSetExperimentalFeatureEnabled(YGExperimentalFeatureWebFlexBasis, true); } +- (instancetype)init +{ + if ([super init]) { + _cnode = YGNodeNew(); + } + + return self; +} + +- (void)dealloc +{ + YGNodeFree(_cnode); +} +@end + +@implementation UIView (Yoga) + +- (void)yg_markDirty +{ + YGNodeBridge *const bridge = objc_getAssociatedObject(self, kYGNodeBridgeAssociatedKey); + if (bridge != nil && [self yg_isLeaf]) { + YGNodeMarkDirty(bridge.cnode); + } +} + +- (BOOL)yg_usesYoga +{ + NSNumber *usesYoga = objc_getAssociatedObject(self, @selector(yg_usesYoga)); + return [usesYoga boolValue]; +} + +- (BOOL)yg_includeInLayout +{ + NSNumber *includeInLayout = objc_getAssociatedObject(self, @selector(yg_includeInLayout)); + return (includeInLayout != nil) ? [includeInLayout boolValue] : YES; +} + +- (NSUInteger)yg_numberOfChildren +{ + return YGNodeGetChildCount([self ygNode]); +} + +- (BOOL)yg_isLeaf +{ + NSAssert([NSThread isMainThread], @"This method must be called on the main thread."); + if ([self yg_usesYoga]) { + for (UIView *subview in self.subviews) { + if ([subview yg_usesYoga] && [subview yg_includeInLayout]) { + return NO; + } + } + } + + return YES; +} + +#pragma mark - Setters + +- (void)yg_setIncludeInLayout:(BOOL)includeInLayout +{ + objc_setAssociatedObject( + self, + @selector(yg_includeInLayout), + @(includeInLayout), + OBJC_ASSOCIATION_RETAIN_NONATOMIC); +} + +- (void)yg_setUsesYoga:(BOOL)enabled +{ + objc_setAssociatedObject( + self, + @selector(yg_usesYoga), + @(enabled), + OBJC_ASSOCIATION_RETAIN_NONATOMIC); +} + +- (void)yg_setDirection:(YGDirection)direction +{ + YGNodeStyleSetDirection([self ygNode], direction); +} + +- (void)yg_setFlexDirection:(YGFlexDirection)flexDirection +{ + YGNodeStyleSetFlexDirection([self ygNode], flexDirection); +} + +- (void)yg_setJustifyContent:(YGJustify)justifyContent +{ + YGNodeStyleSetJustifyContent([self ygNode], justifyContent); +} + +- (void)yg_setAlignContent:(YGAlign)alignContent +{ + YGNodeStyleSetAlignContent([self ygNode], alignContent); +} + +- (void)yg_setAlignItems:(YGAlign)alignItems +{ + YGNodeStyleSetAlignItems([self ygNode], alignItems); +} + +- (void)yg_setAlignSelf:(YGAlign)alignSelf +{ + YGNodeStyleSetAlignSelf([self ygNode], alignSelf); +} + +- (void)yg_setPositionType:(YGPositionType)positionType +{ + YGNodeStyleSetPositionType([self ygNode], positionType); +} + +- (void)yg_setFlexWrap:(YGWrap)flexWrap +{ + YGNodeStyleSetFlexWrap([self ygNode], flexWrap); +} + +- (void)yg_setOverflow:(YGOverflow)overflow +{ + YGNodeStyleSetOverflow([self ygNode], overflow); +} + +- (void)yg_setFlexGrow:(CGFloat)flexGrow +{ + YGNodeStyleSetFlexGrow([self ygNode], flexGrow); +} + +- (void)yg_setFlexShrink:(CGFloat)flexShrink +{ + YGNodeStyleSetFlexShrink([self ygNode], flexShrink); +} + +- (void)yg_setFlexBasis:(CGFloat)flexBasis +{ + YGNodeStyleSetFlexBasis([self ygNode], flexBasis); +} + +- (void)yg_setPosition:(CGFloat)position forEdge:(YGEdge)edge +{ + YGNodeStyleSetPosition([self ygNode], edge, position); +} + +- (void)yg_setMargin:(CGFloat)margin forEdge:(YGEdge)edge +{ + YGNodeStyleSetMargin([self ygNode], edge, margin); +} + +- (void)yg_setPadding:(CGFloat)padding forEdge:(YGEdge)edge +{ + YGNodeStyleSetPadding([self ygNode], edge, padding); +} + +- (void)yg_setWidth:(CGFloat)width +{ + YGNodeStyleSetWidth([self ygNode], width); +} + +- (void)yg_setHeight:(CGFloat)height +{ + YGNodeStyleSetHeight([self ygNode], height); +} + +- (void)yg_setMinWidth:(CGFloat)minWidth +{ + YGNodeStyleSetMinWidth([self ygNode], minWidth); +} + +- (void)yg_setMinHeight:(CGFloat)minHeight +{ + YGNodeStyleSetMinHeight([self ygNode], minHeight); +} + +- (void)yg_setMaxWidth:(CGFloat)maxWidth +{ + YGNodeStyleSetMaxWidth([self ygNode], maxWidth); +} + +- (void)yg_setMaxHeight:(CGFloat)maxHeight +{ + YGNodeStyleSetMaxHeight([self ygNode], maxHeight); +} + +- (void)yg_setAspectRatio:(CGFloat)aspectRatio +{ + YGNodeStyleSetAspectRatio([self ygNode], aspectRatio); +} + +#pragma mark - Layout and Sizing + +- (YGDirection)yg_resolvedDirection +{ + return YGNodeLayoutGetDirection([self ygNode]); +} + +- (void)yg_applyLayout +{ + [self calculateLayoutWithSize:self.bounds.size]; + YGApplyLayoutToViewHierarchy(self); +} + +- (CGSize)yg_intrinsicSize +{ + const CGSize constrainedSize = { + .width = YGUndefined, + .height = YGUndefined, + }; + return [self calculateLayoutWithSize:constrainedSize]; +} + +#pragma mark - Private + +- (YGNodeRef)ygNode +{ + YGNodeBridge *node = objc_getAssociatedObject(self, kYGNodeBridgeAssociatedKey); + if (!node) { + node = [YGNodeBridge new]; + YGNodeSetContext(node.cnode, (__bridge void *) self); + objc_setAssociatedObject(self, kYGNodeBridgeAssociatedKey, node, OBJC_ASSOCIATION_RETAIN_NONATOMIC); + } + return node.cnode; +} + +- (CGSize)calculateLayoutWithSize:(CGSize)size +{ + NSAssert([NSThread isMainThread], @"YG Layout calculation must be done on main."); + NSAssert([self yg_usesYoga], @"YG Layout is not enabled for this view."); + + YGAttachNodesFromViewHierachy(self); + + const YGNodeRef node = [self ygNode]; + YGNodeCalculateLayout( + node, + size.width, + size.height, + YGNodeStyleGetDirection(node)); + + return (CGSize) { + .width = YGNodeLayoutGetWidth(node), + .height = YGNodeLayoutGetHeight(node), + }; +} + +static YGSize YGMeasureView( + YGNodeRef node, + float width, + YGMeasureMode widthMode, + float height, + YGMeasureMode heightMode) +{ + const CGFloat constrainedWidth = (widthMode == YGMeasureModeUndefined) ? CGFLOAT_MAX : width; + const CGFloat constrainedHeight = (heightMode == YGMeasureModeUndefined) ? CGFLOAT_MAX: height; + + UIView *view = (__bridge UIView*) YGNodeGetContext(node); + const CGSize sizeThatFits = [view sizeThatFits:(CGSize) { + .width = constrainedWidth, + .height = constrainedHeight, + }]; + + return (YGSize) { + .width = YGSanitizeMeasurement(constrainedWidth, sizeThatFits.width, widthMode), + .height = YGSanitizeMeasurement(constrainedHeight, sizeThatFits.height, heightMode), + }; +} + +static CGFloat YGSanitizeMeasurement( + CGFloat constrainedSize, + CGFloat measuredSize, + YGMeasureMode measureMode) +{ + CGFloat result; + if (measureMode == YGMeasureModeExactly) { + result = constrainedSize; + } else if (measureMode == YGMeasureModeAtMost) { + result = MIN(constrainedSize, measuredSize); + } else { + result = measuredSize; + } + + return result; +} + +static BOOL YGNodeHasExactSameChildren(const YGNodeRef node, NSArray *subviews) +{ + if (YGNodeGetChildCount(node) != subviews.count) { + return NO; + } + + for (int i=0; i *subviewsToInclude = [[NSMutableArray alloc] initWithCapacity:view.subviews.count]; + for (UIView *subview in view.subviews) { + if ([subview yg_includeInLayout]) { + [subviewsToInclude addObject:subview]; + } + } + + if (!YGNodeHasExactSameChildren(node, subviewsToInclude)) { + YGRemoveAllChildren(node); + for (int i=0; i 0) { + YGNodeRemoveChild(node, YGNodeGetChild(node, YGNodeGetChildCount(node) - 1)); + } +} + +static CGFloat YGRoundPixelValue(CGFloat value) +{ + static CGFloat scale; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^(){ + scale = [UIScreen mainScreen].scale; + }); + + return round(value * scale) / scale; +} + +static void YGApplyLayoutToViewHierarchy(UIView *view) +{ + NSCAssert([NSThread isMainThread], @"Framesetting should only be done on the main thread."); + if (![view yg_includeInLayout]) { + return; + } + + YGNodeRef node = [view ygNode]; + const CGPoint topLeft = { + YGNodeLayoutGetLeft(node), + YGNodeLayoutGetTop(node), + }; + + const CGPoint bottomRight = { + topLeft.x + YGNodeLayoutGetWidth(node), + topLeft.y + YGNodeLayoutGetHeight(node), + }; + + view.frame = (CGRect) { + .origin = { + .x = YGRoundPixelValue(topLeft.x), + .y = YGRoundPixelValue(topLeft.y), + }, + .size = { + .width = YGRoundPixelValue(bottomRight.x) - YGRoundPixelValue(topLeft.x), + .height = YGRoundPixelValue(bottomRight.y) - YGRoundPixelValue(topLeft.y), + }, + }; + + if (!view.yg_isLeaf) { + for (NSUInteger i=0; i -#import - -@interface YGLayout : NSObject - -/** - The property that decides if we should include this view when calculating layout. Defaults to YES. - */ -@property (nonatomic, readwrite, assign, setter=setIncludedInLayout:) BOOL isIncludedInLayout; - -/** - The property that decides during layout/sizing whether or not styling properties should be applied. Defaults to NO. - */ -@property (nonatomic, readwrite, assign, setter=setEnabled:) BOOL isEnabled; - -@property (nonatomic, readwrite, assign) YGDirection direction; -@property (nonatomic, readwrite, assign) YGFlexDirection flexDirection; -@property (nonatomic, readwrite, assign) YGJustify justifyContent; -@property (nonatomic, readwrite, assign) YGAlign alignContent; -@property (nonatomic, readwrite, assign) YGAlign alignItems; -@property (nonatomic, readwrite, assign) YGAlign alignSelf; -@property (nonatomic, readwrite, assign) YGPositionType position; -@property (nonatomic, readwrite, assign) YGWrap flexWrap; -@property (nonatomic, readwrite, assign) YGOverflow overflow; - -@property (nonatomic, readwrite, assign) CGFloat flexGrow; -@property (nonatomic, readwrite, assign) CGFloat flexShrink; -@property (nonatomic, readwrite, assign) CGFloat flexBasis; - -@property (nonatomic, readwrite, assign) CGFloat left; -@property (nonatomic, readwrite, assign) CGFloat top; -@property (nonatomic, readwrite, assign) CGFloat right; -@property (nonatomic, readwrite, assign) CGFloat bottom; -@property (nonatomic, readwrite, assign) CGFloat start; -@property (nonatomic, readwrite, assign) CGFloat end; - -@property (nonatomic, readwrite, assign) CGFloat marginLeft; -@property (nonatomic, readwrite, assign) CGFloat marginTop; -@property (nonatomic, readwrite, assign) CGFloat marginRight; -@property (nonatomic, readwrite, assign) CGFloat marginBottom; -@property (nonatomic, readwrite, assign) CGFloat marginStart; -@property (nonatomic, readwrite, assign) CGFloat marginEnd; -@property (nonatomic, readwrite, assign) CGFloat marginHorizontal; -@property (nonatomic, readwrite, assign) CGFloat marginVertical; -@property (nonatomic, readwrite, assign) CGFloat margin; - -@property (nonatomic, readwrite, assign) CGFloat paddingLeft; -@property (nonatomic, readwrite, assign) CGFloat paddingTop; -@property (nonatomic, readwrite, assign) CGFloat paddingRight; -@property (nonatomic, readwrite, assign) CGFloat paddingBottom; -@property (nonatomic, readwrite, assign) CGFloat paddingStart; -@property (nonatomic, readwrite, assign) CGFloat paddingEnd; -@property (nonatomic, readwrite, assign) CGFloat paddingHorizontal; -@property (nonatomic, readwrite, assign) CGFloat paddingVertical; -@property (nonatomic, readwrite, assign) CGFloat padding; - -@property (nonatomic, readwrite, assign) CGFloat borderLeftWidth; -@property (nonatomic, readwrite, assign) CGFloat borderTopWidth; -@property (nonatomic, readwrite, assign) CGFloat borderRightWidth; -@property (nonatomic, readwrite, assign) CGFloat borderBottomWidth; -@property (nonatomic, readwrite, assign) CGFloat borderStartWidth; -@property (nonatomic, readwrite, assign) CGFloat borderEndWidth; -@property (nonatomic, readwrite, assign) CGFloat borderWidth; - -@property (nonatomic, readwrite, assign) CGFloat width; -@property (nonatomic, readwrite, assign) CGFloat height; -@property (nonatomic, readwrite, assign) CGFloat minWidth; -@property (nonatomic, readwrite, assign) CGFloat minHeight; -@property (nonatomic, readwrite, assign) CGFloat maxWidth; -@property (nonatomic, readwrite, assign) CGFloat maxHeight; - -// Yoga specific properties, not compatible with flexbox specification -@property (nonatomic, readwrite, assign) CGFloat aspectRatio; - -/** - Get the resolved direction of this node. This won't be YGDirectionInherit - */ - @property (nonatomic, readonly, assign) YGDirection resolvedDirection; - -/** - Perform a layout calculation and update the frames of the views in the hierarchy with the results - */ -- (void)applyLayout NS_SWIFT_NAME(applyLayout()); - -/** - Returns the size of the view if no constraints were given. This could equivalent to calling [self sizeThatFits:CGSizeMake(CGFLOAT_MAX, CGFLOAT_MAX)]; - */ - @property (nonatomic, readonly, assign) CGSize intrinsicSize; - -/** - Returns the number of children that are using Flexbox. - */ - @property (nonatomic, readonly, assign) NSUInteger numberOfChildren; - -/** - Return a BOOL indiciating whether or not we this node contains any subviews that are included in Yoga's layout. - */ - @property (nonatomic, readonly, assign) BOOL isLeaf; - -/** - Mark that a view's layout needs to be recalculated. Only works for leaf views. - */ -- (void)markDirty; - -@end diff --git a/YogaKit/YGLayout.m b/YogaKit/YGLayout.m deleted file mode 100644 index d6a2baf0..00000000 --- a/YogaKit/YGLayout.m +++ /dev/null @@ -1,380 +0,0 @@ -/** - * 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. - */ - -#import "YGLayout+Private.h" -#import "UIView+Yoga.h" -#import - -#define YG_STYLE_PROPERTY_IMPL(type, lowercased_name, capitalized_name) \ -- (type)lowercased_name \ -{ \ - return YGNodeStyleGet##capitalized_name(self.node); \ -} \ - \ -- (void)set##capitalized_name:(type)lowercased_name \ -{ \ - YGNodeStyleSet##capitalized_name(self.node, lowercased_name); \ -} - -#define YG_STYLE_EDGE_PROPERTY_IMPL(lowercased_name, capitalized_name, property, edge) \ -- (CGFloat)lowercased_name { \ - return YGNodeStyleGet##property(self.node, edge); \ -} \ - \ -- (void)set##capitalized_name:(CGFloat)lowercased_name { \ - YGNodeStyleSet##property(self.node, edge, lowercased_name); \ -} - -#define YG_STYLE_VALUE_PROPERTY_IMPL(lowercased_name, capitalized_name) \ -- (CGFloat)lowercased_name \ -{ \ - YGValue value = YGNodeStyleGet##capitalized_name(self.node); \ - if (value.unit == YGUnitPixel) { \ - return value.value; \ - } else { \ - return YGUndefined; \ - } \ -} \ - \ -- (void)set##capitalized_name:(CGFloat)lowercased_name \ -{ \ - YGNodeStyleSet##capitalized_name(self.node, lowercased_name); \ -} - -#define YG_STYLE_EDGE_PROPERTY_UNIT_IMPL(lowercased_name, capitalized_name, edge, edge_suffix) \ -- (CGFloat)lowercased_name##edge_suffix \ -{ \ - YGValue value = YGNodeStyleGet##capitalized_name(self.node, edge); \ - if (value.unit == YGUnitPixel) { \ - return value.value; \ - } else { \ - return YGUndefined; \ - } \ -} \ - \ -- (void)set##capitalized_name##edge_suffix:(CGFloat)lowercased_name \ -{ \ - YGNodeStyleSet##capitalized_name(self.node, edge, lowercased_name); \ -} - -#define YG_STYLE_ALL_EDGE_PROPERTY_UNIT_IMPL(lowercased_name, capitalized_name) \ -YG_STYLE_EDGE_PROPERTY_UNIT_IMPL(lowercased_name, capitalized_name, YGEdgeLeft, Left) \ -YG_STYLE_EDGE_PROPERTY_UNIT_IMPL(lowercased_name, capitalized_name, YGEdgeTop, Top) \ -YG_STYLE_EDGE_PROPERTY_UNIT_IMPL(lowercased_name, capitalized_name, YGEdgeRight, Right) \ -YG_STYLE_EDGE_PROPERTY_UNIT_IMPL(lowercased_name, capitalized_name, YGEdgeBottom, Bottom) \ -YG_STYLE_EDGE_PROPERTY_UNIT_IMPL(lowercased_name, capitalized_name, YGEdgeStart, Start) \ -YG_STYLE_EDGE_PROPERTY_UNIT_IMPL(lowercased_name, capitalized_name, YGEdgeEnd, End) \ -YG_STYLE_EDGE_PROPERTY_UNIT_IMPL(lowercased_name, capitalized_name, YGEdgeHorizontal, Horizontal) \ -YG_STYLE_EDGE_PROPERTY_UNIT_IMPL(lowercased_name, capitalized_name, YGEdgeVertical, Vertical) \ -YG_STYLE_EDGE_PROPERTY_UNIT_IMPL(lowercased_name, capitalized_name, YGEdgeAll, ) - -@interface YGLayout () - -@property (nonatomic, weak, readonly) UIView *view; -@property (nonatomic, assign, readonly) YGNodeRef node; - -@end - -@implementation YGLayout - -@synthesize isEnabled=_isEnabled; -@synthesize isIncludedInLayout=_isIncludedInLayout; - -+ (void)initialize -{ - YGSetExperimentalFeatureEnabled(YGExperimentalFeatureWebFlexBasis, true); -} - -- (instancetype)initWithView:(UIView*)view -{ - if (self = [super init]) { - _view = view; - _node = YGNodeNew(); - YGNodeSetContext(_node, (__bridge void *) view); - _isEnabled = NO; - _isIncludedInLayout = YES; - } - - return self; -} - -- (void)dealloc -{ - YGNodeFree(self.node); -} - -- (void)markDirty -{ - if (self.isLeaf) { - YGNodeMarkDirty(self.node); - } -} - -- (NSUInteger)numberOfChildren -{ - return YGNodeGetChildCount(self.node); -} - -- (BOOL)isLeaf -{ - NSAssert([NSThread isMainThread], @"This method must be called on the main thread."); - if (self.isEnabled) { - for (UIView *subview in self.view.subviews) { - YGLayout *const yoga = subview.yoga; - if (yoga.isEnabled && yoga.isIncludedInLayout) { - return NO; - } - } - } - - return YES; -} - -#pragma mark - Style - -- (YGPositionType)position -{ - return YGNodeStyleGetPositionType(self.node); -} - -- (void)setPosition:(YGPositionType)position -{ - YGNodeStyleSetPositionType(self.node, position); -} - -YG_STYLE_PROPERTY_IMPL(YGDirection, direction, Direction) -YG_STYLE_PROPERTY_IMPL(YGFlexDirection, flexDirection, FlexDirection) -YG_STYLE_PROPERTY_IMPL(YGJustify, justifyContent, JustifyContent) -YG_STYLE_PROPERTY_IMPL(YGAlign, alignContent, AlignContent) -YG_STYLE_PROPERTY_IMPL(YGAlign, alignItems, AlignItems) -YG_STYLE_PROPERTY_IMPL(YGAlign, alignSelf, AlignSelf) -YG_STYLE_PROPERTY_IMPL(YGWrap, flexWrap, FlexWrap) -YG_STYLE_PROPERTY_IMPL(YGOverflow, overflow, Overflow) - -YG_STYLE_PROPERTY_IMPL(CGFloat, flexGrow, FlexGrow) -YG_STYLE_PROPERTY_IMPL(CGFloat, flexShrink, FlexShrink) -YG_STYLE_VALUE_PROPERTY_IMPL(flexBasis, FlexBasis) - -YG_STYLE_EDGE_PROPERTY_UNIT_IMPL(position, Position, YGEdgeLeft, Left) -YG_STYLE_EDGE_PROPERTY_UNIT_IMPL(position, Position, YGEdgeTop, Top) -YG_STYLE_EDGE_PROPERTY_UNIT_IMPL(position, Position, YGEdgeRight, Right) -YG_STYLE_EDGE_PROPERTY_UNIT_IMPL(position, Position, YGEdgeBottom, Bottom) -YG_STYLE_EDGE_PROPERTY_UNIT_IMPL(position, Position, YGEdgeStart, Start) -YG_STYLE_EDGE_PROPERTY_UNIT_IMPL(position, Position, YGEdgeEnd, End) -YG_STYLE_ALL_EDGE_PROPERTY_UNIT_IMPL(margin, Margin) -YG_STYLE_ALL_EDGE_PROPERTY_UNIT_IMPL(padding, Padding) - -YG_STYLE_EDGE_PROPERTY_IMPL(borderLeftWidth, BorderLeftWidth, Border, YGEdgeLeft) -YG_STYLE_EDGE_PROPERTY_IMPL(borderTopWidth, BorderTopWidth, Border, YGEdgeTop) -YG_STYLE_EDGE_PROPERTY_IMPL(borderRightWidth, BorderRightWidth, Border, YGEdgeRight) -YG_STYLE_EDGE_PROPERTY_IMPL(borderBottomWidth, BorderBottomWidth, Border, YGEdgeBottom) -YG_STYLE_EDGE_PROPERTY_IMPL(borderStartWidth, BorderStartWidth, Border, YGEdgeStart) -YG_STYLE_EDGE_PROPERTY_IMPL(borderEndWidth, BorderEndWidth, Border, YGEdgeEnd) -YG_STYLE_EDGE_PROPERTY_IMPL(borderWidth, BorderWidth, Border, YGEdgeAll) - -YG_STYLE_VALUE_PROPERTY_IMPL(width, Width) -YG_STYLE_VALUE_PROPERTY_IMPL(height, Height) -YG_STYLE_VALUE_PROPERTY_IMPL(minWidth, MinWidth) -YG_STYLE_VALUE_PROPERTY_IMPL(minHeight, MinHeight) -YG_STYLE_VALUE_PROPERTY_IMPL(maxWidth, MaxWidth) -YG_STYLE_VALUE_PROPERTY_IMPL(maxHeight, MaxHeight) -YG_STYLE_PROPERTY_IMPL(CGFloat, aspectRatio, AspectRatio) - -#pragma mark - Layout and Sizing - -- (YGDirection)resolvedDirection -{ - return YGNodeLayoutGetDirection(self.node); -} - -- (void)applyLayout -{ - [self calculateLayoutWithSize:self.view.bounds.size]; - YGApplyLayoutToViewHierarchy(self.view); -} - -- (CGSize)intrinsicSize -{ - const CGSize constrainedSize = { - .width = YGUndefined, - .height = YGUndefined, - }; - return [self calculateLayoutWithSize:constrainedSize]; -} - -#pragma mark - Private - -- (CGSize)calculateLayoutWithSize:(CGSize)size -{ - NSAssert([NSThread isMainThread], @"Yoga calculation must be done on main."); - NSAssert(self.isEnabled, @"Yoga is not enabled for this view."); - - YGAttachNodesFromViewHierachy(self.view); - - const YGNodeRef node = self.node; - YGNodeCalculateLayout( - node, - size.width, - size.height, - YGNodeStyleGetDirection(node)); - - return (CGSize) { - .width = YGNodeLayoutGetWidth(node), - .height = YGNodeLayoutGetHeight(node), - }; -} - -static YGSize YGMeasureView( - YGNodeRef node, - float width, - YGMeasureMode widthMode, - float height, - YGMeasureMode heightMode) -{ - const CGFloat constrainedWidth = (widthMode == YGMeasureModeUndefined) ? CGFLOAT_MAX : width; - const CGFloat constrainedHeight = (heightMode == YGMeasureModeUndefined) ? CGFLOAT_MAX: height; - - UIView *view = (__bridge UIView*) YGNodeGetContext(node); - const CGSize sizeThatFits = [view sizeThatFits:(CGSize) { - .width = constrainedWidth, - .height = constrainedHeight, - }]; - - return (YGSize) { - .width = YGSanitizeMeasurement(constrainedWidth, sizeThatFits.width, widthMode), - .height = YGSanitizeMeasurement(constrainedHeight, sizeThatFits.height, heightMode), - }; -} - -static CGFloat YGSanitizeMeasurement( - CGFloat constrainedSize, - CGFloat measuredSize, - YGMeasureMode measureMode) -{ - CGFloat result; - if (measureMode == YGMeasureModeExactly) { - result = constrainedSize; - } else if (measureMode == YGMeasureModeAtMost) { - result = MIN(constrainedSize, measuredSize); - } else { - result = measuredSize; - } - - return result; -} - -static BOOL YGNodeHasExactSameChildren(const YGNodeRef node, NSArray *subviews) -{ - if (YGNodeGetChildCount(node) != subviews.count) { - return NO; - } - - for (int i=0; i *subviewsToInclude = [[NSMutableArray alloc] initWithCapacity:view.subviews.count]; - for (UIView *subview in view.subviews) { - if (subview.yoga.isIncludedInLayout) { - [subviewsToInclude addObject:subview]; - } - } - - if (!YGNodeHasExactSameChildren(node, subviewsToInclude)) { - YGRemoveAllChildren(node); - for (int i=0; i 0) { - YGNodeRemoveChild(node, YGNodeGetChild(node, YGNodeGetChildCount(node) - 1)); - } -} - -static CGFloat YGRoundPixelValue(CGFloat value) -{ - static CGFloat scale; - static dispatch_once_t onceToken; - dispatch_once(&onceToken, ^(){ - scale = [UIScreen mainScreen].scale; - }); - - return round(value * scale) / scale; -} - -static void YGApplyLayoutToViewHierarchy(UIView *view) -{ - NSCAssert([NSThread isMainThread], @"Framesetting should only be done on the main thread."); - - const YGLayout *yoga = view.yoga; - - if (!yoga.isIncludedInLayout) { - return; - } - - YGNodeRef node = yoga.node; - const CGPoint topLeft = { - YGNodeLayoutGetLeft(node), - YGNodeLayoutGetTop(node), - }; - - const CGPoint bottomRight = { - topLeft.x + YGNodeLayoutGetWidth(node), - topLeft.y + YGNodeLayoutGetHeight(node), - }; - - view.frame = (CGRect) { - .origin = { - .x = YGRoundPixelValue(topLeft.x), - .y = YGRoundPixelValue(topLeft.y), - }, - .size = { - .width = YGRoundPixelValue(bottomRight.x) - YGRoundPixelValue(topLeft.x), - .height = YGRoundPixelValue(bottomRight.y) - YGRoundPixelValue(topLeft.y), - }, - }; - - if (!yoga.isLeaf) { - for (NSUInteger i=0; i diff --git a/enums.py b/enums.py index 2f388ccc..53b2ab53 100644 --- a/enums.py +++ b/enums.py @@ -119,21 +119,21 @@ def to_java_upper(symbol): root = os.path.dirname(os.path.abspath(__file__)) -# write out C & Objective-C headers +# write out C headers with open(root + '/yoga/YGEnums.h', 'w') as f: f.write(LICENSE) f.write('#pragma once\n\n') f.write('#include "YGMacros.h"\n\n') f.write('YG_EXTERN_C_BEGIN\n\n') for name, values in ENUMS.items(): - f.write('#define YG%sCount %s\n' % (name, len(values))) - f.write('typedef YG_ENUM_BEGIN(YG%s) {\n' % name) + f.write('#define YG%sCount %s\n' % (name, len(values))) + f.write('typedef enum YG%s {\n' % name) for value in values: if isinstance(value, tuple): f.write(' YG%s%s = %d,\n' % (name, value[0], value[1])) else: f.write(' YG%s%s,\n' % (name, value)) - f.write('} YG_ENUM_END(YG%s);\n' % name) + f.write('} YG%s;\n' % name) f.write('\n') f.write('YG_EXTERN_C_END\n') diff --git a/yoga/YGEnums.h b/yoga/YGEnums.h index 0a10bbc2..24606bcd 100644 --- a/yoga/YGEnums.h +++ b/yoga/YGEnums.h @@ -14,29 +14,29 @@ YG_EXTERN_C_BEGIN #define YGFlexDirectionCount 4 -typedef YG_ENUM_BEGIN(YGFlexDirection) { +typedef enum YGFlexDirection { YGFlexDirectionColumn, YGFlexDirectionColumnReverse, YGFlexDirectionRow, YGFlexDirectionRowReverse, -} YG_ENUM_END(YGFlexDirection); +} YGFlexDirection; #define YGMeasureModeCount 3 -typedef YG_ENUM_BEGIN(YGMeasureMode) { +typedef enum YGMeasureMode { YGMeasureModeUndefined, YGMeasureModeExactly, YGMeasureModeAtMost, -} YG_ENUM_END(YGMeasureMode); +} YGMeasureMode; #define YGPrintOptionsCount 3 -typedef YG_ENUM_BEGIN(YGPrintOptions) { +typedef enum YGPrintOptions { YGPrintOptionsLayout = 1, YGPrintOptionsStyle = 2, YGPrintOptionsChildren = 4, -} YG_ENUM_END(YGPrintOptions); +} YGPrintOptions; #define YGEdgeCount 9 -typedef YG_ENUM_BEGIN(YGEdge) { +typedef enum YGEdge { YGEdgeLeft, YGEdgeTop, YGEdgeRight, @@ -46,79 +46,79 @@ typedef YG_ENUM_BEGIN(YGEdge) { YGEdgeHorizontal, YGEdgeVertical, YGEdgeAll, -} YG_ENUM_END(YGEdge); +} YGEdge; #define YGPositionTypeCount 2 -typedef YG_ENUM_BEGIN(YGPositionType) { +typedef enum YGPositionType { YGPositionTypeRelative, YGPositionTypeAbsolute, -} YG_ENUM_END(YGPositionType); +} YGPositionType; #define YGDimensionCount 2 -typedef YG_ENUM_BEGIN(YGDimension) { +typedef enum YGDimension { YGDimensionWidth, YGDimensionHeight, -} YG_ENUM_END(YGDimension); +} YGDimension; #define YGJustifyCount 5 -typedef YG_ENUM_BEGIN(YGJustify) { +typedef enum YGJustify { YGJustifyFlexStart, YGJustifyCenter, YGJustifyFlexEnd, YGJustifySpaceBetween, YGJustifySpaceAround, -} YG_ENUM_END(YGJustify); +} YGJustify; #define YGDirectionCount 3 -typedef YG_ENUM_BEGIN(YGDirection) { +typedef enum YGDirection { YGDirectionInherit, YGDirectionLTR, YGDirectionRTL, -} YG_ENUM_END(YGDirection); +} YGDirection; #define YGLogLevelCount 5 -typedef YG_ENUM_BEGIN(YGLogLevel) { +typedef enum YGLogLevel { YGLogLevelError, YGLogLevelWarn, YGLogLevelInfo, YGLogLevelDebug, YGLogLevelVerbose, -} YG_ENUM_END(YGLogLevel); +} YGLogLevel; #define YGWrapCount 2 -typedef YG_ENUM_BEGIN(YGWrap) { +typedef enum YGWrap { YGWrapNoWrap, YGWrapWrap, -} YG_ENUM_END(YGWrap); +} YGWrap; #define YGOverflowCount 3 -typedef YG_ENUM_BEGIN(YGOverflow) { +typedef enum YGOverflow { YGOverflowVisible, YGOverflowHidden, YGOverflowScroll, -} YG_ENUM_END(YGOverflow); +} YGOverflow; #define YGExperimentalFeatureCount 2 -typedef YG_ENUM_BEGIN(YGExperimentalFeature) { +typedef enum YGExperimentalFeature { YGExperimentalFeatureRounding, YGExperimentalFeatureWebFlexBasis, -} YG_ENUM_END(YGExperimentalFeature); +} YGExperimentalFeature; #define YGAlignCount 6 -typedef YG_ENUM_BEGIN(YGAlign) { +typedef enum YGAlign { YGAlignAuto, YGAlignFlexStart, YGAlignCenter, YGAlignFlexEnd, YGAlignStretch, YGAlignBaseline, -} YG_ENUM_END(YGAlign); +} YGAlign; #define YGUnitCount 3 -typedef YG_ENUM_BEGIN(YGUnit) { +typedef enum YGUnit { YGUnitUndefined, YGUnitPixel, YGUnitPercent, -} YG_ENUM_END(YGUnit); +} YGUnit; YG_EXTERN_C_END diff --git a/yoga/YGMacros.h b/yoga/YGMacros.h index d6724272..def8371a 100644 --- a/yoga/YGMacros.h +++ b/yoga/YGMacros.h @@ -40,19 +40,3 @@ YG_ABORT(); \ } #endif - -#ifndef YG_ENUM_BEGIN -#ifndef NS_ENUM -#define YG_ENUM_BEGIN(name) enum name -#else -#define YG_ENUM_BEGIN(name) NS_ENUM(NSInteger, name) -#endif -#endif - -#ifndef YG_ENUM_END -#ifndef NS_ENUM -#define YG_ENUM_END(name) name -#else -#define YG_ENUM_END(name) -#endif -#endif