diff --git a/.gitignore b/.gitignore index 5b346768..8a2620f5 100644 --- a/.gitignore +++ b/.gitignore @@ -8,3 +8,6 @@ # Visual studio code .vscode + +# Xcode +xcuserdata \ No newline at end of file diff --git a/YogaKit/UIView+Yoga.h b/YogaKit/UIView+Yoga.h deleted file mode 100644 index 734c13d4..00000000 --- a/YogaKit/UIView+Yoga.h +++ /dev/null @@ -1,77 +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 -#import - -@interface UIView (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_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; - -@end diff --git a/YogaKit/UIView+Yoga.m b/YogaKit/UIView+Yoga.m deleted file mode 100644 index 980a7683..00000000 --- a/YogaKit/UIView+Yoga.m +++ /dev/null @@ -1,397 +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 "UIView+Yoga.h" - -#import - -@interface YGNodeBridge : NSObject -@property (nonatomic, assign, readonly) YGNodeRef cnode; -@end - -@implementation YGNodeBridge - -+ (void)initialize -{ - YGSetExperimentalFeatureEnabled(YGExperimentalFeatureWebFlexBasis, true); -} - -- (instancetype)init -{ - if ([super init]) { - _cnode = YGNodeNew(); - } - - return self; -} - -- (void)dealloc -{ - YGNodeFree(_cnode); -} -@end - -@implementation UIView (Yoga) - -- (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_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, @selector(ygNode)); - if (!node) { - node = [YGNodeBridge new]; - YGNodeSetContext(node.cnode, (__bridge void *) self); - objc_setAssociatedObject(self, @selector(ygNode), 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 UIView (YogaKit) + +@property (nonatomic, readonly) YKLayout* layout; + +@end diff --git a/YogaKit/UIView+YogaKit.m b/YogaKit/UIView+YogaKit.m new file mode 100644 index 00000000..a5221310 --- /dev/null +++ b/YogaKit/UIView+YogaKit.m @@ -0,0 +1,28 @@ +/** + * 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 +#import +#import + +@implementation UIView (YogaKit) + +- (YKLayout *)layout +{ + YKLayout *layout = objc_getAssociatedObject(self, @selector(layout)); + if (!layout) { + layout = [[YKLayout alloc] initWithView:self]; + objc_setAssociatedObject(self, @selector(layout), layout, OBJC_ASSOCIATION_RETAIN_NONATOMIC); + } + + return layout; +} + + +@end diff --git a/YogaKit/YKEnums.h b/YogaKit/YKEnums.h new file mode 100644 index 00000000..fdfb8721 --- /dev/null +++ b/YogaKit/YKEnums.h @@ -0,0 +1,48 @@ +/** + * 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. + */ + +typedef NS_ENUM(NSInteger, YKFlexDirection) { + YKFlexDirectionColumn, + YKFlexDirectionColumnReverse, + YKFlexDirectionRow, + YKFlexDirectionRowReverse, +} NS_SWIFT_NAME(FlexDirection); + +typedef NS_ENUM(NSInteger, YKPositionType) { + YKPositionTypeRelative, + YKPositionTypeAbsolute, +} NS_SWIFT_NAME(PositionType); + +typedef NS_ENUM(NSInteger, YKJustify) { + YKJustifyFlexStart, + YKJustifyCenter, + YKJustifyFlexEnd, + YKJustifySpaceBetween, + YKJustifySpaceAround, +} NS_SWIFT_NAME(Justify); + +typedef NS_ENUM(NSInteger, YKDirection) { + YKDirectionInherit, + YKDirectionLeftToRight, + YKDirectionRightToLeft, +} NS_SWIFT_NAME(Direction); + +typedef NS_ENUM(NSInteger, YKWrap) { + YKWrapNoWrap, + YKWrapWrap, +} NS_SWIFT_NAME(Wrap); + +typedef NS_ENUM(NSInteger, YKAlign) { + YKAlignAuto, + YKAlignFlexStart, + YKAlignCenter, + YKAlignFlexEnd, + YKAlignStretch, +} NS_SWIFT_NAME(Align); + diff --git a/YogaKit/YKLayout+Private.h b/YogaKit/YKLayout+Private.h new file mode 100644 index 00000000..c51d3ec3 --- /dev/null +++ b/YogaKit/YKLayout+Private.h @@ -0,0 +1,16 @@ +/** + * 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 + +@interface YKLayout () + +- (instancetype)initWithView:(UIView*)view; + +@end diff --git a/YogaKit/YKLayout.h b/YogaKit/YKLayout.h new file mode 100644 index 00000000..15ebadc7 --- /dev/null +++ b/YogaKit/YKLayout.h @@ -0,0 +1,97 @@ +/** + * 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 "YKEnums.h" + +@interface YKLayout : NSObject + +/** + The property that decides if we should include this view when calculating layout. Defaults to YES. + */ +@property (nonatomic, setter=setIncluded:) BOOL isIncluded; + +/** + The property that decides during layout/sizing whether or not yk_* properties should be applied. Defaults to NO. + */ +@property (nonatomic, setter=setEnabled:) BOOL isEnabled; + +@property (nonatomic) YKDirection direction; +@property (nonatomic) YKFlexDirection flexDirection; +@property (nonatomic) YKJustify justifyContent; +@property (nonatomic) YKAlign alignContent; +@property (nonatomic) YKAlign alignItems; +@property (nonatomic) YKAlign alignSelf; +@property (nonatomic) YKPositionType positionType; +@property (nonatomic) YKWrap flexWrap; + +@property (nonatomic) CGFloat flexGrow; +@property (nonatomic) CGFloat flexShrink; +@property (nonatomic) CGFloat flexBasis; + +@property (nonatomic) CGFloat positionLeft; +@property (nonatomic) CGFloat positionTop; +@property (nonatomic) CGFloat positionRight; +@property (nonatomic) CGFloat positionBottom; +@property (nonatomic) CGFloat positionStart; +@property (nonatomic) CGFloat positionEnd; +@property (nonatomic) CGFloat positionHorizontal; +@property (nonatomic) CGFloat positionVertical; +@property (nonatomic) CGFloat positionAll; + +@property (nonatomic) CGFloat marginLeft; +@property (nonatomic) CGFloat marginTop; +@property (nonatomic) CGFloat marginRight; +@property (nonatomic) CGFloat marginBottom; +@property (nonatomic) CGFloat marginStart; +@property (nonatomic) CGFloat marginEnd; +@property (nonatomic) CGFloat marginHorizontal; +@property (nonatomic) CGFloat marginVertical; +@property (nonatomic) CGFloat marginAll; + +@property (nonatomic) CGFloat paddingLeft; +@property (nonatomic) CGFloat paddingTop; +@property (nonatomic) CGFloat paddingRight; +@property (nonatomic) CGFloat paddingBottom; +@property (nonatomic) CGFloat paddingStart; +@property (nonatomic) CGFloat paddingEnd; +@property (nonatomic) CGFloat paddingHorizontal; +@property (nonatomic) CGFloat paddingVertical; +@property (nonatomic) CGFloat paddingAll; + +@property (nonatomic) CGFloat width; +@property (nonatomic) CGFloat height; +@property (nonatomic) CGFloat minWidth; +@property (nonatomic) CGFloat minHeight; +@property (nonatomic) CGFloat maxWidth; +@property (nonatomic) CGFloat maxHeight; + +// Yoga specific properties, not compatible with flexbox specification +@property (nonatomic) CGFloat aspectRatio; + +/** + Get the resolved direction of this node. This won't be YGDirectionInherit + */ +@property (nonatomic, readonly) YKDirection resolvedDirection; + +/** + Perform a layout calculation and update the frames of the views in the hierarchy with the results + */ +- (void)apply; + +/** + 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) CGSize intrinsicSize; + +/** + Returns the number of children that are using Flexbox. + */ +@property (nonatomic, readonly) NSUInteger numberOfChildren; + +@end diff --git a/YogaKit/YKLayout.m b/YogaKit/YKLayout.m new file mode 100644 index 00000000..bd4b32ff --- /dev/null +++ b/YogaKit/YKLayout.m @@ -0,0 +1,294 @@ +/** + * 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 +#import +#import +#import + +#define YK_STYLE_PROPERTY_IMPL(objc_type, c_type, lowercased_name, capitalized_name) \ +- (objc_type)lowercased_name \ +{ \ +return (objc_type)YGNodeStyleGet##capitalized_name(_node); \ +} \ +\ +- (void)set##capitalized_name:(objc_type)lowercased_name \ +{ \ +YGNodeStyleSet##capitalized_name(_node, (c_type)lowercased_name); \ +} + +#define _YK_STYLE_EDGE_PROPERTY_IMPL(lowercased_name, capitalized_name, edge) \ +- (CGFloat)lowercased_name##edge \ +{ \ +return YGNodeStyleGet##capitalized_name(_node, YGEdge##edge); \ +} \ +\ +- (void)set##capitalized_name##edge:(CGFloat)lowercased_name##edge \ +{ \ +YGNodeStyleSet##capitalized_name(_node, YGEdge##edge, lowercased_name##edge); \ +} + +#define YK_STYLE_EDGE_PROPERTY_IMPL(lowercased_name, capitalized_name) \ +_YK_STYLE_EDGE_PROPERTY_IMPL(lowercased_name, capitalized_name, Left) \ +_YK_STYLE_EDGE_PROPERTY_IMPL(lowercased_name, capitalized_name, Top) \ +_YK_STYLE_EDGE_PROPERTY_IMPL(lowercased_name, capitalized_name, Right) \ +_YK_STYLE_EDGE_PROPERTY_IMPL(lowercased_name, capitalized_name, Bottom) \ +_YK_STYLE_EDGE_PROPERTY_IMPL(lowercased_name, capitalized_name, Start) \ +_YK_STYLE_EDGE_PROPERTY_IMPL(lowercased_name, capitalized_name, End) \ +_YK_STYLE_EDGE_PROPERTY_IMPL(lowercased_name, capitalized_name, Horizontal) \ +_YK_STYLE_EDGE_PROPERTY_IMPL(lowercased_name, capitalized_name, Vertical) \ +_YK_STYLE_EDGE_PROPERTY_IMPL(lowercased_name, capitalized_name, All) + +@interface YKLayout () +@property (nonatomic, weak, readonly) UIView* view; +@property (nonatomic, assign, readonly) YGNodeRef node; +@end + +@implementation YKLayout + +@synthesize isEnabled=_isEnabled; +@synthesize isIncluded=_isIncluded; + ++ (void)initialize +{ + YGSetExperimentalFeatureEnabled(YGExperimentalFeatureWebFlexBasis, true); +} + +- (instancetype)initWithView:(UIView*)view +{ + if ([super init]) { + _view = view; + _node = YGNodeNew(); + YGNodeSetContext(_node, (__bridge void *) view); + _isEnabled = NO; + _isIncluded = YES; + } + + return self; +} + +- (void)dealloc +{ + YGNodeFree(_node); +} + +- (NSUInteger)numberOfChildren +{ + return YGNodeGetChildCount(_node); +} + +YK_STYLE_PROPERTY_IMPL(YKDirection, YGDirection, direction, Direction) +YK_STYLE_PROPERTY_IMPL(YKFlexDirection, YGFlexDirection, flexDirection, FlexDirection) +YK_STYLE_PROPERTY_IMPL(YKJustify, YGJustify, justifyContent, JustifyContent) +YK_STYLE_PROPERTY_IMPL(YKAlign, YGAlign, alignContent, AlignContent) +YK_STYLE_PROPERTY_IMPL(YKAlign, YGAlign, alignItems, AlignItems) +YK_STYLE_PROPERTY_IMPL(YKAlign, YGAlign, alignSelf, AlignSelf) +YK_STYLE_PROPERTY_IMPL(YKPositionType, YGPositionType, positionType, PositionType) +YK_STYLE_PROPERTY_IMPL(YKWrap, YGWrap, flexWrap, FlexWrap) +YK_STYLE_PROPERTY_IMPL(CGFloat, CGFloat, flexGrow, FlexGrow) +YK_STYLE_PROPERTY_IMPL(CGFloat, CGFloat, flexShrink, FlexShrink) +YK_STYLE_PROPERTY_IMPL(CGFloat, CGFloat, flexBasis, FlexBasis) +YK_STYLE_EDGE_PROPERTY_IMPL(position, Position) +YK_STYLE_EDGE_PROPERTY_IMPL(margin, Margin) +YK_STYLE_EDGE_PROPERTY_IMPL(padding, Padding) +YK_STYLE_PROPERTY_IMPL(CGFloat, CGFloat, width, Width) +YK_STYLE_PROPERTY_IMPL(CGFloat, CGFloat, height, Height) +YK_STYLE_PROPERTY_IMPL(CGFloat, CGFloat, minWidth, MinWidth) +YK_STYLE_PROPERTY_IMPL(CGFloat, CGFloat, minHeight, MinHeight) +YK_STYLE_PROPERTY_IMPL(CGFloat, CGFloat, maxWidth, MaxWidth) +YK_STYLE_PROPERTY_IMPL(CGFloat, CGFloat, maxHeight, MaxHeight) +YK_STYLE_PROPERTY_IMPL(CGFloat, CGFloat, aspectRatio, AspectRatio) + +#pragma mark - Layout and Sizing + +- (YKDirection)resolvedDirection +{ + return (YKDirection)YGNodeLayoutGetDirection(_node); +} + +- (void)apply +{ + [self calculateLayoutWithSize:self.view.bounds.size]; + YKApplyLayoutToViewHierarchy(self); +} + +- (CGSize)intrinsicSize +{ + const CGSize constrainedSize = { + .width = YGUndefined, + .height = YGUndefined, + }; + return [self calculateLayoutWithSize:constrainedSize]; +} + +#pragma mark - Private + +- (CGSize)calculateLayoutWithSize:(CGSize)size +{ + NSAssert([NSThread isMainThread], @"YG Layout calculation must be done on main."); + NSAssert([self isEnabled], @"YG Layout is not enabled for this view."); + + YKAttachNodesFromViewHierachy(self); + + const YGNodeRef node = _node; + YGNodeCalculateLayout( + node, + size.width, + size.height, + YGNodeStyleGetDirection(node)); + + return (CGSize) { + .width = YGNodeLayoutGetWidth(node), + .height = YGNodeLayoutGetHeight(node), + }; +} + +static YGSize YKMeasureView( + 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 = YKSanitizeMeasurement(constrainedWidth, sizeThatFits.width, widthMode), + .height = YKSanitizeMeasurement(constrainedHeight, sizeThatFits.height, heightMode), + }; +} + +static CGFloat YKSanitizeMeasurement( + 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 void YKAttachNodesFromViewHierachy(YKLayout *layout) { + YGNodeRef node = layout.node; + UIView *view = layout.view; + + // Only leaf nodes should have a measure function + if (![layout isEnabled] || view.subviews.count == 0) { + YGNodeSetMeasureFunc(node, YKMeasureView); + YKRemoveAllChildren(node); + } else { + YGNodeSetMeasureFunc(node, NULL); + + // Create a list of all the subviews that we are going to use for layout. + NSMutableArray *subviewsToInclude = [[NSMutableArray alloc] initWithCapacity:view.subviews.count]; + for (UIView *subview in view.subviews) { + if (subview.layout.isIncluded) { + [subviewsToInclude addObject:subview]; + } + } + + BOOL shouldReconstructChildList = NO; + if (YGNodeGetChildCount(node) != subviewsToInclude.count) { + shouldReconstructChildList = YES; + } else { + for (int i = 0; i < subviewsToInclude.count; i++) { + if (YGNodeGetChild(node, i) != subviewsToInclude[i].layout.node) { + shouldReconstructChildList = YES; + break; + } + } + } + + if (shouldReconstructChildList) { + YKRemoveAllChildren(node); + + for (int i = 0 ; i < subviewsToInclude.count; i++) { + UIView *const subview = subviewsToInclude[i]; + YGNodeInsertChild(node, subview.layout.node, i); + YKAttachNodesFromViewHierachy(subview.layout); + } + } + } +} + +static void YKRemoveAllChildren(const YGNodeRef node) +{ + if (node == NULL) { + return; + } + + while (YGNodeGetChildCount(node) > 0) { + YGNodeRemoveChild(node, YGNodeGetChild(node, YGNodeGetChildCount(node) - 1)); + } +} + +static CGFloat YKRoundPixelValue(CGFloat value) +{ + static CGFloat scale; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^(){ + scale = [UIScreen mainScreen].scale; + }); + + return round(value * scale) / scale; +} + +static void YKApplyLayoutToViewHierarchy(YKLayout *layout) { + NSCAssert([NSThread isMainThread], @"Framesetting should only be done on the main thread."); + + if (!layout.isIncluded) { + return; + } + + YGNodeRef node = layout.node; + const CGPoint topLeft = { + YGNodeLayoutGetLeft(node), + YGNodeLayoutGetTop(node), + }; + + const CGPoint bottomRight = { + topLeft.x + YGNodeLayoutGetWidth(node), + topLeft.y + YGNodeLayoutGetHeight(node), + }; + + UIView *view = layout.view; + view.frame = (CGRect) { + .origin = { + .x = YKRoundPixelValue(topLeft.x), + .y = YKRoundPixelValue(topLeft.y), + }, + .size = { + .width = YKRoundPixelValue(bottomRight.x) - YKRoundPixelValue(topLeft.x), + .height = YKRoundPixelValue(bottomRight.y) - YKRoundPixelValue(topLeft.y), + }, + }; + + const BOOL isLeaf = !layout.isEnabled || view.subviews.count == 0; + if (!isLeaf) { + for (NSUInteger i = 0; i < view.subviews.count; i++) { + YKApplyLayoutToViewHierarchy(view.subviews[i].layout); + } + } +} + +@end diff --git a/YogaKit/YogaKitSample/YogaKitSample.xcodeproj/project.pbxproj b/YogaKit/YogaKit/YogaKit.xcodeproj/project.pbxproj similarity index 56% rename from YogaKit/YogaKitSample/YogaKitSample.xcodeproj/project.pbxproj rename to YogaKit/YogaKit/YogaKit.xcodeproj/project.pbxproj index 7232ec9f..ae667b6f 100644 --- a/YogaKit/YogaKitSample/YogaKitSample.xcodeproj/project.pbxproj +++ b/YogaKit/YogaKit/YogaKit.xcodeproj/project.pbxproj @@ -11,40 +11,45 @@ 13687D4B1DF8748400E7C260 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 13687D4A1DF8748400E7C260 /* AppDelegate.m */; }; 13687D4E1DF8748400E7C260 /* ViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 13687D4D1DF8748400E7C260 /* ViewController.m */; }; 13687D531DF8748400E7C260 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 13687D521DF8748400E7C260 /* Assets.xcassets */; }; - 13687D781DF878C600E7C260 /* YGEnums.h in yoga */ = {isa = PBXBuildFile; fileRef = 13687D5E1DF8778F00E7C260 /* YGEnums.h */; }; - 13687D791DF878C600E7C260 /* YGMacros.h in yoga */ = {isa = PBXBuildFile; fileRef = 13687D5F1DF8778F00E7C260 /* YGMacros.h */; }; - 13687D7A1DF878C600E7C260 /* Yoga.h in yoga */ = {isa = PBXBuildFile; fileRef = 13687D631DF8778F00E7C260 /* Yoga.h */; }; - 13687D7C1DF878DD00E7C260 /* UIView+Yoga.h in YogaKit */ = {isa = PBXBuildFile; fileRef = 13687D691DF8778F00E7C260 /* UIView+Yoga.h */; }; - 13687D801DF87CEC00E7C260 /* UIView+Yoga.m in Sources */ = {isa = PBXBuildFile; fileRef = 13687D6A1DF8778F00E7C260 /* UIView+Yoga.m */; }; - 13687D811DF87CF200E7C260 /* YGNodeList.c in Sources */ = {isa = PBXBuildFile; fileRef = 13687D601DF8778F00E7C260 /* YGNodeList.c */; }; - 13687D821DF87CF200E7C260 /* Yoga.c in Sources */ = {isa = PBXBuildFile; fileRef = 13687D621DF8778F00E7C260 /* Yoga.c */; }; 13687D851DF87D1E00E7C260 /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 13687D841DF87D1E00E7C260 /* UIKit.framework */; }; 13687D871DF87D2400E7C260 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 13687D861DF87D2400E7C260 /* Foundation.framework */; }; + 63EE08411E06ED3D00EE5F9A /* YogaKit.h in Headers */ = {isa = PBXBuildFile; fileRef = 63EE083F1E06ED3D00EE5F9A /* YogaKit.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 63EE08441E06ED3D00EE5F9A /* YogaKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 63EE083D1E06ED3D00EE5F9A /* YogaKit.framework */; }; + 63EE08451E06ED3D00EE5F9A /* YogaKit.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 63EE083D1E06ED3D00EE5F9A /* YogaKit.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; + 63EE084A1E06EEB700EE5F9A /* YGNodeList.c in Sources */ = {isa = PBXBuildFile; fileRef = 13687D601DF8778F00E7C260 /* YGNodeList.c */; }; + 63EE084B1E06EEB700EE5F9A /* Yoga.c in Sources */ = {isa = PBXBuildFile; fileRef = 13687D621DF8778F00E7C260 /* Yoga.c */; }; + 63EE084C1E06EEB700EE5F9A /* UIView+YogaKit.m in Sources */ = {isa = PBXBuildFile; fileRef = 13687D6A1DF8778F00E7C260 /* UIView+YogaKit.m */; }; + 63EE084E1E06EECB00EE5F9A /* YGMacros.h in Headers */ = {isa = PBXBuildFile; fileRef = 13687D5F1DF8778F00E7C260 /* YGMacros.h */; }; + 63EE084F1E06EECB00EE5F9A /* YGNodeList.h in Headers */ = {isa = PBXBuildFile; fileRef = 13687D611DF8778F00E7C260 /* YGNodeList.h */; }; + 63EE08501E06EECB00EE5F9A /* Yoga.h in Headers */ = {isa = PBXBuildFile; fileRef = 13687D631DF8778F00E7C260 /* Yoga.h */; }; + 63EE08511E06EECB00EE5F9A /* UIView+YogaKit.h in Headers */ = {isa = PBXBuildFile; fileRef = 13687D691DF8778F00E7C260 /* UIView+YogaKit.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 63EE08531E06F3D100EE5F9A /* YKEnums.h in Headers */ = {isa = PBXBuildFile; fileRef = 63EE08521E06F3D100EE5F9A /* YKEnums.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 63EE08551E072EF800EE5F9A /* SwiftViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 63EE08541E072EF800EE5F9A /* SwiftViewController.swift */; }; + 63EE08571E07590C00EE5F9A /* YKLayout.m in Sources */ = {isa = PBXBuildFile; fileRef = 63EE08561E07590C00EE5F9A /* YKLayout.m */; }; + 63EE08591E07598A00EE5F9A /* YKLayout.h in Headers */ = {isa = PBXBuildFile; fileRef = 63EE08581E07591A00EE5F9A /* YKLayout.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 63EE085B1E075B0B00EE5F9A /* YKLayout+Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 63EE085A1E075AAA00EE5F9A /* YKLayout+Private.h */; }; /* End PBXBuildFile section */ -/* Begin PBXCopyFilesBuildPhase section */ - 13687D771DF878A000E7C260 /* yoga */ = { - isa = PBXCopyFilesBuildPhase; - buildActionMask = 2147483647; - dstPath = include/yoga; - dstSubfolderSpec = 16; - files = ( - 13687D781DF878C600E7C260 /* YGEnums.h in yoga */, - 13687D791DF878C600E7C260 /* YGMacros.h in yoga */, - 13687D7A1DF878C600E7C260 /* Yoga.h in yoga */, - ); - name = yoga; - runOnlyForDeploymentPostprocessing = 0; +/* Begin PBXContainerItemProxy section */ + 63EE08421E06ED3D00EE5F9A /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 13687D3B1DF8748300E7C260 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 63EE083C1E06ED3D00EE5F9A; + remoteInfo = YogaKit; }; - 13687D7B1DF878CE00E7C260 /* YogaKit */ = { +/* End PBXContainerItemProxy section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 63EE08491E06ED3D00EE5F9A /* Embed Frameworks */ = { isa = PBXCopyFilesBuildPhase; buildActionMask = 2147483647; - dstPath = include/YogaKit; - dstSubfolderSpec = 16; + dstPath = ""; + dstSubfolderSpec = 10; files = ( - 13687D7C1DF878DD00E7C260 /* UIView+Yoga.h in YogaKit */, + 63EE08451E06ED3D00EE5F9A /* YogaKit.framework in Embed Frameworks */, ); - name = YogaKit; + name = "Embed Frameworks"; runOnlyForDeploymentPostprocessing = 0; }; /* End PBXCopyFilesBuildPhase section */ @@ -58,16 +63,23 @@ 13687D4D1DF8748400E7C260 /* ViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ViewController.m; sourceTree = ""; }; 13687D521DF8748400E7C260 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 13687D571DF8748400E7C260 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; - 13687D5E1DF8778F00E7C260 /* YGEnums.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = YGEnums.h; sourceTree = ""; }; 13687D5F1DF8778F00E7C260 /* YGMacros.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = YGMacros.h; sourceTree = ""; }; 13687D601DF8778F00E7C260 /* YGNodeList.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = YGNodeList.c; sourceTree = ""; }; 13687D611DF8778F00E7C260 /* YGNodeList.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = YGNodeList.h; sourceTree = ""; }; 13687D621DF8778F00E7C260 /* Yoga.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = Yoga.c; sourceTree = ""; }; 13687D631DF8778F00E7C260 /* Yoga.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Yoga.h; sourceTree = ""; }; - 13687D691DF8778F00E7C260 /* UIView+Yoga.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "UIView+Yoga.h"; sourceTree = ""; }; - 13687D6A1DF8778F00E7C260 /* UIView+Yoga.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = "UIView+Yoga.m"; sourceTree = ""; }; + 13687D691DF8778F00E7C260 /* UIView+YogaKit.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "UIView+YogaKit.h"; path = "../../UIView+YogaKit.h"; sourceTree = ""; }; + 13687D6A1DF8778F00E7C260 /* UIView+YogaKit.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = "UIView+YogaKit.m"; path = "../../UIView+YogaKit.m"; sourceTree = ""; }; 13687D841DF87D1E00E7C260 /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; }; 13687D861DF87D2400E7C260 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; + 63EE083D1E06ED3D00EE5F9A /* YogaKit.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = YogaKit.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 63EE083F1E06ED3D00EE5F9A /* YogaKit.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = YogaKit.h; sourceTree = ""; }; + 63EE08401E06ED3D00EE5F9A /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 63EE08521E06F3D100EE5F9A /* YKEnums.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = YKEnums.h; path = ../../YKEnums.h; sourceTree = ""; }; + 63EE08541E072EF800EE5F9A /* SwiftViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SwiftViewController.swift; sourceTree = ""; }; + 63EE08561E07590C00EE5F9A /* YKLayout.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = YKLayout.m; path = ../../YKLayout.m; sourceTree = ""; }; + 63EE08581E07591A00EE5F9A /* YKLayout.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = YKLayout.h; path = ../../YKLayout.h; sourceTree = ""; }; + 63EE085A1E075AAA00EE5F9A /* YKLayout+Private.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "YKLayout+Private.h"; path = "../../YKLayout+Private.h"; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -77,6 +89,14 @@ files = ( 13687D871DF87D2400E7C260 /* Foundation.framework in Frameworks */, 13687D851DF87D1E00E7C260 /* UIKit.framework in Frameworks */, + 63EE08441E06ED3D00EE5F9A /* YogaKit.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 63EE08391E06ED3D00EE5F9A /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( ); runOnlyForDeploymentPostprocessing = 0; }; @@ -86,9 +106,8 @@ 13687D3A1DF8748300E7C260 = { isa = PBXGroup; children = ( - 13687D5D1DF8778F00E7C260 /* yoga */, - 13687D641DF8778F00E7C260 /* YogaKit */, 13687D451DF8748400E7C260 /* YogaKitSample */, + 63EE083E1E06ED3D00EE5F9A /* YogaKit */, 13687D441DF8748400E7C260 /* Products */, 13687D831DF87D1E00E7C260 /* Frameworks */, ); @@ -98,6 +117,7 @@ isa = PBXGroup; children = ( 13687D431DF8748400E7C260 /* YogaKitSample.app */, + 63EE083D1E06ED3D00EE5F9A /* YogaKit.framework */, ); name = Products; sourceTree = ""; @@ -109,6 +129,7 @@ 13687D4A1DF8748400E7C260 /* AppDelegate.m */, 13687D4C1DF8748400E7C260 /* ViewController.h */, 13687D4D1DF8748400E7C260 /* ViewController.m */, + 63EE08541E072EF800EE5F9A /* SwiftViewController.swift */, 13687D521DF8748400E7C260 /* Assets.xcassets */, 13687D571DF8748400E7C260 /* Info.plist */, 13687D461DF8748400E7C260 /* Supporting Files */, @@ -127,7 +148,6 @@ 13687D5D1DF8778F00E7C260 /* yoga */ = { isa = PBXGroup; children = ( - 13687D5E1DF8778F00E7C260 /* YGEnums.h */, 13687D5F1DF8778F00E7C260 /* YGMacros.h */, 13687D601DF8778F00E7C260 /* YGNodeList.c */, 13687D611DF8778F00E7C260 /* YGNodeList.h */, @@ -135,17 +155,7 @@ 13687D631DF8778F00E7C260 /* Yoga.h */, ); name = yoga; - path = ../../yoga; - sourceTree = ""; - }; - 13687D641DF8778F00E7C260 /* YogaKit */ = { - isa = PBXGroup; - children = ( - 13687D691DF8778F00E7C260 /* UIView+Yoga.h */, - 13687D6A1DF8778F00E7C260 /* UIView+Yoga.m */, - ); - name = YogaKit; - path = ..; + path = ../../../yoga; sourceTree = ""; }; 13687D831DF87D1E00E7C260 /* Frameworks */ = { @@ -157,44 +167,101 @@ name = Frameworks; sourceTree = ""; }; + 63EE083E1E06ED3D00EE5F9A /* YogaKit */ = { + isa = PBXGroup; + children = ( + 13687D5D1DF8778F00E7C260 /* yoga */, + 63EE083F1E06ED3D00EE5F9A /* YogaKit.h */, + 63EE08521E06F3D100EE5F9A /* YKEnums.h */, + 13687D691DF8778F00E7C260 /* UIView+YogaKit.h */, + 13687D6A1DF8778F00E7C260 /* UIView+YogaKit.m */, + 63EE08581E07591A00EE5F9A /* YKLayout.h */, + 63EE085A1E075AAA00EE5F9A /* YKLayout+Private.h */, + 63EE08561E07590C00EE5F9A /* YKLayout.m */, + 63EE08401E06ED3D00EE5F9A /* Info.plist */, + ); + path = YogaKit; + sourceTree = ""; + }; /* End PBXGroup section */ +/* Begin PBXHeadersBuildPhase section */ + 63EE083A1E06ED3D00EE5F9A /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + 63EE085B1E075B0B00EE5F9A /* YKLayout+Private.h in Headers */, + 63EE08591E07598A00EE5F9A /* YKLayout.h in Headers */, + 63EE08411E06ED3D00EE5F9A /* YogaKit.h in Headers */, + 63EE08531E06F3D100EE5F9A /* YKEnums.h in Headers */, + 63EE08511E06EECB00EE5F9A /* UIView+YogaKit.h in Headers */, + 63EE084E1E06EECB00EE5F9A /* YGMacros.h in Headers */, + 63EE084F1E06EECB00EE5F9A /* YGNodeList.h in Headers */, + 63EE08501E06EECB00EE5F9A /* Yoga.h in Headers */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXHeadersBuildPhase section */ + /* Begin PBXNativeTarget section */ 13687D421DF8748300E7C260 /* YogaKitSample */ = { isa = PBXNativeTarget; buildConfigurationList = 13687D5A1DF8748400E7C260 /* Build configuration list for PBXNativeTarget "YogaKitSample" */; buildPhases = ( - 13687D771DF878A000E7C260 /* yoga */, - 13687D7B1DF878CE00E7C260 /* YogaKit */, 13687D3F1DF8748300E7C260 /* Sources */, 13687D401DF8748300E7C260 /* Frameworks */, 13687D411DF8748300E7C260 /* Resources */, + 63EE08491E06ED3D00EE5F9A /* Embed Frameworks */, ); buildRules = ( ); dependencies = ( + 63EE08431E06ED3D00EE5F9A /* PBXTargetDependency */, ); name = YogaKitSample; productName = YogaKitSample; productReference = 13687D431DF8748400E7C260 /* YogaKitSample.app */; productType = "com.apple.product-type.application"; }; + 63EE083C1E06ED3D00EE5F9A /* YogaKit */ = { + isa = PBXNativeTarget; + buildConfigurationList = 63EE08481E06ED3D00EE5F9A /* Build configuration list for PBXNativeTarget "YogaKit" */; + buildPhases = ( + 63EE08381E06ED3D00EE5F9A /* Sources */, + 63EE08391E06ED3D00EE5F9A /* Frameworks */, + 63EE083A1E06ED3D00EE5F9A /* Headers */, + 63EE083B1E06ED3D00EE5F9A /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = YogaKit; + productName = YogaKit; + productReference = 63EE083D1E06ED3D00EE5F9A /* YogaKit.framework */; + productType = "com.apple.product-type.framework"; + }; /* End PBXNativeTarget section */ /* Begin PBXProject section */ 13687D3B1DF8748300E7C260 /* Project object */ = { isa = PBXProject; attributes = { - LastUpgradeCheck = 0810; + LastUpgradeCheck = 0820; ORGANIZATIONNAME = facebook; TargetAttributes = { 13687D421DF8748300E7C260 = { CreatedOnToolsVersion = 8.1; + LastSwiftMigration = 0820; + ProvisioningStyle = Automatic; + }; + 63EE083C1E06ED3D00EE5F9A = { + CreatedOnToolsVersion = 8.2; ProvisioningStyle = Automatic; }; }; }; - buildConfigurationList = 13687D3E1DF8748300E7C260 /* Build configuration list for PBXProject "YogaKitSample" */; + buildConfigurationList = 13687D3E1DF8748300E7C260 /* Build configuration list for PBXProject "YogaKit" */; compatibilityVersion = "Xcode 3.2"; developmentRegion = English; hasScannedForEncodings = 0; @@ -207,6 +274,7 @@ projectDirPath = ""; projectRoot = ""; targets = ( + 63EE083C1E06ED3D00EE5F9A /* YogaKit */, 13687D421DF8748300E7C260 /* YogaKitSample */, ); }; @@ -221,6 +289,13 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + 63EE083B1E06ED3D00EE5F9A /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; /* End PBXResourcesBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ @@ -228,17 +303,34 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - 13687D801DF87CEC00E7C260 /* UIView+Yoga.m in Sources */, + 63EE08551E072EF800EE5F9A /* SwiftViewController.swift in Sources */, 13687D4E1DF8748400E7C260 /* ViewController.m in Sources */, 13687D4B1DF8748400E7C260 /* AppDelegate.m in Sources */, - 13687D821DF87CF200E7C260 /* Yoga.c in Sources */, - 13687D811DF87CF200E7C260 /* YGNodeList.c in Sources */, 13687D481DF8748400E7C260 /* main.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; + 63EE08381E06ED3D00EE5F9A /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 63EE084A1E06EEB700EE5F9A /* YGNodeList.c in Sources */, + 63EE084B1E06EEB700EE5F9A /* Yoga.c in Sources */, + 63EE084C1E06EEB700EE5F9A /* UIView+YogaKit.m in Sources */, + 63EE08571E07590C00EE5F9A /* YKLayout.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; /* End PBXSourcesBuildPhase section */ +/* Begin PBXTargetDependency section */ + 63EE08431E06ED3D00EE5F9A /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 63EE083C1E06ED3D00EE5F9A /* YogaKit */; + targetProxy = 63EE08421E06ED3D00EE5F9A /* PBXContainerItemProxy */; + }; +/* End PBXTargetDependency section */ + /* Begin XCBuildConfiguration section */ 13687D581DF8748400E7C260 /* Debug */ = { isa = XCBuildConfiguration; @@ -258,6 +350,7 @@ CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_SUSPICIOUS_MOVES = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; @@ -305,6 +398,7 @@ CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_SUSPICIOUS_MOVES = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; @@ -332,10 +426,13 @@ isa = XCBuildConfiguration; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; INFOPLIST_FILE = YogaKitSample/Info.plist; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = com.facebook.YogaKitSample; PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 3.0; }; name = Debug; }; @@ -343,17 +440,65 @@ isa = XCBuildConfiguration; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; INFOPLIST_FILE = YogaKitSample/Info.plist; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = com.facebook.YogaKitSample; PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 3.0; + }; + name = Release; + }; + 63EE08461E06ED3D00EE5F9A /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CODE_SIGN_IDENTITY = ""; + CURRENT_PROJECT_VERSION = 1; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + INFOPLIST_FILE = YogaKit/Info.plist; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 10.2; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = com.facebook.YogaKit; + PRODUCT_NAME = "$(TARGET_NAME)"; + SKIP_INSTALL = YES; + TARGETED_DEVICE_FAMILY = "1,2"; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = Debug; + }; + 63EE08471E06ED3D00EE5F9A /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CODE_SIGN_IDENTITY = ""; + CURRENT_PROJECT_VERSION = 1; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + INFOPLIST_FILE = YogaKit/Info.plist; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 10.2; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = com.facebook.YogaKit; + PRODUCT_NAME = "$(TARGET_NAME)"; + SKIP_INSTALL = YES; + TARGETED_DEVICE_FAMILY = "1,2"; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; }; name = Release; }; /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ - 13687D3E1DF8748300E7C260 /* Build configuration list for PBXProject "YogaKitSample" */ = { + 13687D3E1DF8748300E7C260 /* Build configuration list for PBXProject "YogaKit" */ = { isa = XCConfigurationList; buildConfigurations = ( 13687D581DF8748400E7C260 /* Debug */, @@ -369,6 +514,16 @@ 13687D5C1DF8748400E7C260 /* Release */, ); defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 63EE08481E06ED3D00EE5F9A /* Build configuration list for PBXNativeTarget "YogaKit" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 63EE08461E06ED3D00EE5F9A /* Debug */, + 63EE08471E06ED3D00EE5F9A /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; }; /* End XCConfigurationList section */ }; diff --git a/YogaKit/YogaKitSample/YogaKitSample.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/YogaKit/YogaKit/YogaKit.xcodeproj/project.xcworkspace/contents.xcworkspacedata similarity index 55% rename from YogaKit/YogaKitSample/YogaKitSample.xcodeproj/project.xcworkspace/contents.xcworkspacedata rename to YogaKit/YogaKit/YogaKit.xcodeproj/project.xcworkspace/contents.xcworkspacedata index b8f12e0b..40735f9b 100644 --- a/YogaKit/YogaKitSample/YogaKitSample.xcodeproj/project.xcworkspace/contents.xcworkspacedata +++ b/YogaKit/YogaKit/YogaKit.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -2,6 +2,6 @@ + location = "self:/Users/david/Projects/yoga/YogaKit/YogaKit/YogaKit.xcodeproj"> diff --git a/YogaKit/YogaKitSample/YogaKitSample.xcodeproj/xcuserdata/emilsj.xcuserdatad/xcschemes/YogaKitSample.xcscheme b/YogaKit/YogaKit/YogaKit.xcodeproj/xcshareddata/xcschemes/YogaKit.xcscheme similarity index 62% rename from YogaKit/YogaKitSample/YogaKitSample.xcodeproj/xcuserdata/emilsj.xcuserdatad/xcschemes/YogaKitSample.xcscheme rename to YogaKit/YogaKit/YogaKit.xcodeproj/xcshareddata/xcschemes/YogaKit.xcscheme index e785e85e..238c84b0 100644 --- a/YogaKit/YogaKitSample/YogaKitSample.xcodeproj/xcuserdata/emilsj.xcuserdatad/xcschemes/YogaKitSample.xcscheme +++ b/YogaKit/YogaKit/YogaKit.xcodeproj/xcshareddata/xcschemes/YogaKit.xcscheme @@ -1,6 +1,6 @@ + BlueprintIdentifier = "63EE083C1E06ED3D00EE5F9A" + BuildableName = "YogaKit.framework" + BlueprintName = "YogaKit" + ReferencedContainer = "container:YogaKit.xcodeproj"> @@ -29,15 +29,6 @@ shouldUseLaunchSchemeArgsEnv = "YES"> - - - - @@ -51,16 +42,15 @@ debugDocumentVersioning = "YES" debugServiceExtension = "internal" allowLocationSimulation = "YES"> - + + BlueprintIdentifier = "63EE083C1E06ED3D00EE5F9A" + BuildableName = "YogaKit.framework" + BlueprintName = "YogaKit" + ReferencedContainer = "container:YogaKit.xcodeproj"> - + @@ -70,16 +60,15 @@ savedToolIdentifier = "" useCustomWorkingDirectory = "NO" debugDocumentVersioning = "YES"> - + + BlueprintIdentifier = "63EE083C1E06ED3D00EE5F9A" + BuildableName = "YogaKit.framework" + BlueprintName = "YogaKit" + ReferencedContainer = "container:YogaKit.xcodeproj"> - + diff --git a/YogaKit/YogaKit/YogaKit/Info.plist b/YogaKit/YogaKit/YogaKit/Info.plist new file mode 100644 index 00000000..fbe1e6b3 --- /dev/null +++ b/YogaKit/YogaKit/YogaKit/Info.plist @@ -0,0 +1,24 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0 + CFBundleVersion + $(CURRENT_PROJECT_VERSION) + NSPrincipalClass + + + diff --git a/YogaKit/YogaKit/YogaKit/YogaKit.h b/YogaKit/YogaKit/YogaKit/YogaKit.h new file mode 100644 index 00000000..6b4620b9 --- /dev/null +++ b/YogaKit/YogaKit/YogaKit/YogaKit.h @@ -0,0 +1,18 @@ +// +// YogaKit.h +// YogaKit +// +// Created by David Hart on 18.12.16. +// Copyright © 2016 facebook. All rights reserved. +// + +#import + +//! Project version number for YogaKit. +FOUNDATION_EXPORT double YogaKitVersionNumber; + +//! Project version string for YogaKit. +FOUNDATION_EXPORT const unsigned char YogaKitVersionString[]; + +#import +#import diff --git a/YogaKit/YogaKitSample/YogaKitSample/AppDelegate.h b/YogaKit/YogaKit/YogaKitSample/AppDelegate.h similarity index 100% rename from YogaKit/YogaKitSample/YogaKitSample/AppDelegate.h rename to YogaKit/YogaKit/YogaKitSample/AppDelegate.h diff --git a/YogaKit/YogaKitSample/YogaKitSample/AppDelegate.m b/YogaKit/YogaKit/YogaKitSample/AppDelegate.m similarity index 100% rename from YogaKit/YogaKitSample/YogaKitSample/AppDelegate.m rename to YogaKit/YogaKit/YogaKitSample/AppDelegate.m diff --git a/YogaKit/YogaKitSample/YogaKitSample/Assets.xcassets/AppIcon.appiconset/Contents.json b/YogaKit/YogaKit/YogaKitSample/Assets.xcassets/AppIcon.appiconset/Contents.json similarity index 100% rename from YogaKit/YogaKitSample/YogaKitSample/Assets.xcassets/AppIcon.appiconset/Contents.json rename to YogaKit/YogaKit/YogaKitSample/Assets.xcassets/AppIcon.appiconset/Contents.json diff --git a/YogaKit/YogaKitSample/YogaKitSample/Info.plist b/YogaKit/YogaKit/YogaKitSample/Info.plist similarity index 100% rename from YogaKit/YogaKitSample/YogaKitSample/Info.plist rename to YogaKit/YogaKit/YogaKitSample/Info.plist diff --git a/YogaKit/YogaKit/YogaKitSample/SwiftViewController.swift b/YogaKit/YogaKit/YogaKitSample/SwiftViewController.swift new file mode 100644 index 00000000..60e6c3d2 --- /dev/null +++ b/YogaKit/YogaKit/YogaKitSample/SwiftViewController.swift @@ -0,0 +1,41 @@ +// +// SwiftViewController.swift +// YogaKit +// +// Created by David Hart on 18.12.16. +// Copyright © 2016 facebook. All rights reserved. +// + +import UIKit +import YogaKit + +class SwiftViewController : UIViewController { + override func viewDidLoad() { + let root = view! + root.backgroundColor = .red + root.layout.isEnabled = true + root.layout.width = view.bounds.size.width + root.layout.height = view.bounds.size.height + root.layout.alignItems = .center + root.layout.justifyContent = .center + + let child1 = UIView() + child1.backgroundColor = .blue + child1.layout.isEnabled = true + child1.layout.width = 100 + child1.layout.height = 100 + + let child2 = UIView() + child2.backgroundColor = .green + child2.frame = CGRect(origin: .zero, size: CGSize(width: 200, height: 100)) + + let child3 = UIView() + child3.backgroundColor = .yellow + child3.frame = CGRect(origin: .zero, size: CGSize(width: 100, height: 100)) + + child2.addSubview(child3) + root.addSubview(child1) + root.addSubview(child2) + root.layout.apply() + } +} diff --git a/YogaKit/YogaKitSample/YogaKitSample/ViewController.h b/YogaKit/YogaKit/YogaKitSample/ViewController.h similarity index 99% rename from YogaKit/YogaKitSample/YogaKitSample/ViewController.h rename to YogaKit/YogaKit/YogaKitSample/ViewController.h index f5642871..e9c49504 100644 --- a/YogaKit/YogaKitSample/YogaKitSample/ViewController.h +++ b/YogaKit/YogaKit/YogaKitSample/ViewController.h @@ -10,6 +10,5 @@ @interface ViewController : UIViewController - @end diff --git a/YogaKit/YogaKitSample/YogaKitSample/ViewController.m b/YogaKit/YogaKit/YogaKitSample/ViewController.m similarity index 72% rename from YogaKit/YogaKitSample/YogaKitSample/ViewController.m rename to YogaKit/YogaKit/YogaKitSample/ViewController.m index a13dae6f..02e565ee 100644 --- a/YogaKit/YogaKitSample/YogaKitSample/ViewController.m +++ b/YogaKit/YogaKit/YogaKitSample/ViewController.m @@ -7,8 +7,7 @@ */ #import "ViewController.h" - -#import +#import @interface ViewController () @@ -20,17 +19,17 @@ { UIView *root = self.view; root.backgroundColor = [UIColor redColor]; - [root yg_setUsesYoga:YES]; - [root yg_setWidth:self.view.bounds.size.width]; - [root yg_setHeight:self.view.bounds.size.height]; - [root yg_setAlignItems:YGAlignCenter]; - [root yg_setJustifyContent:YGJustifyCenter]; + root.layout.isEnabled = YES; + root.layout.width = self.view.bounds.size.width; + root.layout.height = self.view.bounds.size.height; + root.layout.alignItems = YKAlignCenter; + root.layout.justifyContent = YKJustifyCenter; UIView *child1 = [UIView new]; child1.backgroundColor = [UIColor blueColor]; - [child1 yg_setUsesYoga:YES]; - [child1 yg_setWidth:100]; - [child1 yg_setHeight:100]; + child1.layout.isEnabled = YES; + child1.layout.width = 100; + child1.layout.height = 100; UIView *child2 = [UIView new]; child2.backgroundColor = [UIColor greenColor]; @@ -53,7 +52,7 @@ [child2 addSubview:child3]; [root addSubview:child1]; [root addSubview:child2]; - [root yg_applyLayout]; + [root.layout apply]; } diff --git a/YogaKit/YogaKitSample/YogaKitSample/main.m b/YogaKit/YogaKit/YogaKitSample/main.m similarity index 100% rename from YogaKit/YogaKitSample/YogaKitSample/main.m rename to YogaKit/YogaKit/YogaKitSample/main.m diff --git a/YogaKit/YogaKitSample/YogaKitSample.xcodeproj/project.xcworkspace/xcuserdata/emilsj.xcuserdatad/UserInterfaceState.xcuserstate b/YogaKit/YogaKitSample/YogaKitSample.xcodeproj/project.xcworkspace/xcuserdata/emilsj.xcuserdatad/UserInterfaceState.xcuserstate deleted file mode 100644 index 47db969a..00000000 Binary files a/YogaKit/YogaKitSample/YogaKitSample.xcodeproj/project.xcworkspace/xcuserdata/emilsj.xcuserdatad/UserInterfaceState.xcuserstate and /dev/null differ diff --git a/YogaKit/YogaKitSample/YogaKitSample.xcodeproj/xcuserdata/emilsj.xcuserdatad/xcschemes/xcschememanagement.plist b/YogaKit/YogaKitSample/YogaKitSample.xcodeproj/xcuserdata/emilsj.xcuserdatad/xcschemes/xcschememanagement.plist deleted file mode 100644 index 336f995f..00000000 --- a/YogaKit/YogaKitSample/YogaKitSample.xcodeproj/xcuserdata/emilsj.xcuserdatad/xcschemes/xcschememanagement.plist +++ /dev/null @@ -1,22 +0,0 @@ - - - - - SchemeUserState - - YogaKitSample.xcscheme - - orderHint - 0 - - - SuppressBuildableAutocreation - - 13687D421DF8748300E7C260 - - primary - - - - - diff --git a/enums.py b/enums.py index 756c7c43..2ae25f2a 100644 --- a/enums.py +++ b/enums.py @@ -89,6 +89,21 @@ ENUMS = { ], } +OBJC_ENUMS = { + 'Direction': [ + 'Inherit', + 'LeftToRight', + 'RightToLeft', + ], + 'Edge': None, + 'MeasureMode': None, + 'PrintOptions': None, + 'Dimension': None, + 'LogLevel': None, + 'Overflow': None, + 'ExperimentalFeature': None +} + LICENSE = """/** * Copyright (c) 2014-present, Facebook, Inc. * All rights reserved. @@ -187,3 +202,19 @@ for name, values in ENUMS.items(): f.write(' %s,\n' % value) f.write(' }\n') f.write('}\n') + +# write out objc files +with open(root + '/YogaKit/YKEnums.h', 'w') as f: + objc_enums = ENUMS + objc_enums.update(OBJC_ENUMS) + f.write(LICENSE) + for name, values in objc_enums.items(): + if values is not None: + f.write('typedef NS_ENUM(NSInteger, YK%s) {\n' % name) + for value in values: + if isinstance(value, tuple): + f.write(' YK%s%s = %d,\n' % (name, value[0], value[1])) + else: + f.write(' YK%s%s,\n' % (name, value)) + f.write('} NS_SWIFT_NAME(%s);\n' % name) + f.write('\n')