├── .gitattributes ├── HMStackView ├── HMStackView.h ├── HMStackView.m ├── HMStackViewConstraints.h ├── HMStackViewConstraints.m ├── HMStackViewLayoutHelper.h ├── HMStackViewLayoutHelper.m ├── HMStackViewProtocol.h └── Weakify │ ├── EXTScope.h │ ├── EXTScope.m │ └── metamacros.h ├── LICENSE └── README.md /.gitattributes: -------------------------------------------------------------------------------- 1 | *.h linguist-language=Objective-C 2 | -------------------------------------------------------------------------------- /HMStackView/HMStackView.h: -------------------------------------------------------------------------------- 1 | // 2 | // BSStackView.h 3 | // stack 4 | // 5 | // Created by Oleg Musinov on 7/10/17. 6 | // Copyright © 2017 iBlacksus. All rights reserved. 7 | // 8 | // Modify by Helio Martín on 15/11/2017 9 | 10 | #import 11 | #import "HMStackViewConstraints.h" 12 | #import "HMStackViewProtocol.h" 13 | 14 | @interface HMStackView : UIView 15 | 16 | @property (assign, nonatomic) UISwipeGestureRecognizerDirection swipeDirections; 17 | @property (assign, nonatomic) UISwipeGestureRecognizerDirection forwardDirections; 18 | @property (assign, nonatomic) UISwipeGestureRecognizerDirection backwardDirections; 19 | @property (strong, nonatomic, readonly) HMStackViewConstraints *contraintsConfigurator; 20 | @property (assign, nonatomic) CGFloat animationDuration; 21 | @property (assign, nonatomic) BOOL changeAlphaOnSendAnimation; 22 | @property (weak, nonatomic) id delegate; 23 | 24 | - (void)configureWithViewControllers:(NSArray *)views; 25 | 26 | - (void)swipe:(UISwipeGestureRecognizer *)gesture; 27 | 28 | @end 29 | -------------------------------------------------------------------------------- /HMStackView/HMStackView.m: -------------------------------------------------------------------------------- 1 | // 2 | // HMStackView.m 3 | // stack 4 | // 5 | // Created by Oleg Musinov on 7/10/17. 6 | // Copyright © 2017 iBlacksus. All rights reserved. 7 | // 8 | // Modify by Helio Martín on 15/11/2017 9 | 10 | #import "HMStackView.h" 11 | #import "EXTScope.h" 12 | #import "HMStackViewLayoutHelper.h" 13 | 14 | static CGFloat const HMStackViewMinAlpha = .50; 15 | static CGFloat const HMStackViewMinBackgroundWhite = .0; 16 | static CGFloat const HMStackViewAnimationDurationDefault = .25; 17 | 18 | @interface HMStackView () 19 | 20 | @property (copy, nonatomic) NSArray *views; 21 | @property (strong, nonatomic) NSMutableDictionary *viewConstraints; 22 | @property (copy, nonatomic) NSArray *gestures; 23 | @property (assign, nonatomic) UIViewController *dontUpdateItem; 24 | 25 | @end 26 | 27 | @implementation HMStackView 28 | 29 | #pragma mark - Accessors - 30 | 31 | - (void)setSwipeDirections:(UISwipeGestureRecognizerDirection)swipeDirections { 32 | _swipeDirections = swipeDirections; 33 | 34 | NSMutableArray *gestures = [NSMutableArray array]; 35 | 36 | if (swipeDirections & UISwipeGestureRecognizerDirectionLeft) { 37 | [gestures addObject:[self addSwipeWithDirection:UISwipeGestureRecognizerDirectionLeft]]; 38 | } 39 | 40 | if (swipeDirections & UISwipeGestureRecognizerDirectionUp) { 41 | [gestures addObject:[self addSwipeWithDirection:UISwipeGestureRecognizerDirectionUp]]; 42 | } 43 | 44 | if (swipeDirections & UISwipeGestureRecognizerDirectionRight) { 45 | [gestures addObject:[self addSwipeWithDirection:UISwipeGestureRecognizerDirectionRight]]; 46 | } 47 | 48 | if (swipeDirections & UISwipeGestureRecognizerDirectionDown) { 49 | [gestures addObject:[self addSwipeWithDirection:UISwipeGestureRecognizerDirectionDown]]; 50 | } 51 | 52 | self.gestures = gestures; 53 | 54 | [self enableGestures:self.views.count > 0]; 55 | } 56 | 57 | #pragma mark - Life cycle - 58 | 59 | - (instancetype)initWithCoder:(NSCoder *)aDecoder { 60 | if (self = [super initWithCoder:aDecoder]) { 61 | [self initialize]; 62 | } 63 | 64 | return self; 65 | } 66 | 67 | #pragma mark - Initialization - 68 | 69 | - (void)initialize { 70 | _viewConstraints = [NSMutableDictionary dictionary]; 71 | _gestures = @[]; 72 | _contraintsConfigurator = [[HMStackViewConstraints alloc] init]; 73 | _animationDuration = HMStackViewAnimationDurationDefault; 74 | } 75 | 76 | #pragma mark - Public - 77 | 78 | - (void)configureWithViewControllers:(NSArray *)views { 79 | [self removeAllViews]; 80 | 81 | self.views = views; 82 | 83 | [self enableGestures:views.count > 0]; 84 | [self removeAllConstraints]; 85 | 86 | NSInteger index = 0; 87 | for (UIViewController *vc in views) { 88 | vc.view.layer.cornerRadius = 10.; 89 | vc.view.layer.masksToBounds = NO; 90 | vc.view.layer.shadowColor = [[UIColor blackColor] colorWithAlphaComponent:0.4].CGColor; 91 | vc.view.layer.shadowOffset = CGSizeMake(0.0f, 2.0f); 92 | vc.view.layer.shadowRadius = 5.f; 93 | vc.view.layer.shadowOpacity = 1.0f; 94 | [vc.view setTranslatesAutoresizingMaskIntoConstraints:NO]; 95 | vc.view.tag = index; 96 | [self addSubview:vc.view]; 97 | [self sendSubviewToBack:vc.view]; 98 | 99 | index++; 100 | } 101 | 102 | [self updateViews]; 103 | } 104 | 105 | #pragma mark - Private - 106 | 107 | - (void)removeAllViews { 108 | for (UIViewController *vc in self.views) { 109 | [vc.view removeFromSuperview]; 110 | } 111 | } 112 | 113 | - (void)enableGestures:(BOOL)enable { 114 | for (UIGestureRecognizer *gesture in self.gestures) { 115 | gesture.enabled = enable; 116 | } 117 | } 118 | 119 | - (void)removeAllConstraints { 120 | for (NSArray *constraints in self.viewConstraints) { 121 | [self removeConstraints:constraints]; 122 | } 123 | } 124 | 125 | - (UISwipeGestureRecognizer *)addSwipeWithDirection:(UISwipeGestureRecognizerDirection)direction { 126 | UISwipeGestureRecognizer *swipeGesture = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:@selector(swipe:)]; 127 | swipeGesture.direction = direction; 128 | [self addGestureRecognizer:swipeGesture]; 129 | 130 | return swipeGesture; 131 | } 132 | 133 | - (void)updateViews { 134 | for (NSInteger i = 0; i < self.views.count; i++) { 135 | [self updateViewAtIndex:i]; 136 | } 137 | } 138 | 139 | - (void)updateViewAtIndex:(NSInteger)index { 140 | if (index >= self.views.count) { 141 | return; 142 | } 143 | 144 | UIViewController *vc = self.views[index]; 145 | if (self.dontUpdateItem == vc) { 146 | return; 147 | } 148 | 149 | NSArray *oldConstraints = self.viewConstraints[@(vc.view.tag)]; 150 | vc.view.alpha = [self calculateAlphaForIndex:index]; 151 | 152 | NSArray *contraints = [self.contraintsConfigurator constraintsForView:vc.view index:index]; 153 | [self removeConstraints:oldConstraints]; 154 | [self addConstraints:contraints]; 155 | self.viewConstraints[@(vc.view.tag)] = contraints; 156 | } 157 | 158 | - (CGFloat)calculateAlphaForIndex:(NSInteger)index { 159 | return (1. - HMStackViewMinAlpha) / self.views.count * (self.views.count - index) + HMStackViewMinAlpha; 160 | } 161 | 162 | - (void)sendView:(UIViewController *)vc direction:(UISwipeGestureRecognizerDirection)direction { 163 | NSMutableArray *constraints = [NSMutableArray arrayWithArray:self.viewConstraints[@(vc.view.tag)]]; 164 | BOOL forward = [self isForwardDirection:direction]; 165 | 166 | NSLayoutAttribute attribute = [HMStackViewLayoutHelper layoutAttributeForDirection:direction]; 167 | NSLayoutAttribute invertAttribute = [HMStackViewLayoutHelper invertLayoutAttribute:attribute]; 168 | BOOL isVertical = [HMStackViewLayoutHelper isVerticalAttribute:attribute]; 169 | CGFloat x = isVertical ? CGRectGetHeight(self.frame) : CGRectGetWidth(self.frame); 170 | NSMutableArray *oldConstraints = [NSMutableArray array]; 171 | CGFloat firstConstraint = 0.; 172 | CGFloat secondConstraint = 0.; 173 | 174 | for (NSLayoutConstraint *constraint in constraints) { 175 | if ([HMStackViewLayoutHelper isConstraint:constraint hasAttribute:attribute forItem:self]) { 176 | [oldConstraints addObject:constraint]; 177 | firstConstraint = forward ? constraint.constant - x : constraint.constant + x; 178 | 179 | } else if ([HMStackViewLayoutHelper isConstraint:constraint hasAttribute:invertAttribute forItem:self]) { 180 | [oldConstraints addObject:constraint]; 181 | secondConstraint = forward ? constraint.constant + x : constraint.constant - x; 182 | } 183 | } 184 | 185 | [self removeConstraints:oldConstraints]; 186 | [constraints removeObjectsInArray:oldConstraints]; 187 | NSArray *newConstraints = @[]; 188 | 189 | if (isVertical) { 190 | CGFloat top = attribute == NSLayoutAttributeTop ? firstConstraint : secondConstraint; 191 | CGFloat bottom = attribute == NSLayoutAttributeBottom ? firstConstraint : secondConstraint; 192 | newConstraints = [self.contraintsConfigurator verticalConstraintsForView:vc.view top:top bottom:bottom]; 193 | } else { 194 | CGFloat leading = attribute == NSLayoutAttributeLeading ? firstConstraint : secondConstraint; 195 | CGFloat trailing = attribute == NSLayoutAttributeTrailing ? firstConstraint : secondConstraint; 196 | newConstraints = [self.contraintsConfigurator horizontalConstraintsForView:vc.view leading:leading trailing:trailing]; 197 | } 198 | 199 | [self addConstraints:newConstraints]; 200 | [constraints addObjectsFromArray:newConstraints]; 201 | self.viewConstraints[@(vc.view.tag)] = constraints; 202 | } 203 | 204 | - (void)sendViewAnimationCompletion:(UISwipeGestureRecognizerDirection)direction { 205 | self.dontUpdateItem = nil; 206 | BOOL forward = [self isForwardDirection:direction]; 207 | UIViewController *vc = forward ? self.views.lastObject : self.views.firstObject; 208 | NSInteger index = forward ? self.views.count - 1 : 0; 209 | [self updateViewAtIndex:index]; 210 | if (self.changeAlphaOnSendAnimation) { 211 | vc.view.alpha = 0.; 212 | } 213 | 214 | if (forward) { 215 | [self sendSubviewToBack:vc.view]; 216 | } else { 217 | [self bringSubviewToFront:vc.view]; 218 | } 219 | 220 | @weakify(self); 221 | [UIView animateWithDuration:self.animationDuration animations:^{ 222 | @strongify(self); 223 | if (self.changeAlphaOnSendAnimation) { 224 | vc.view.alpha = [self calculateAlphaForIndex:index]; 225 | } 226 | [self layoutIfNeeded]; 227 | } completion:^(BOOL finished) { 228 | @strongify(self); 229 | if (self.delegate && [self.delegate respondsToSelector:@selector(stackView:didSendItem:direction:)]) { 230 | HMStackViewItemDirection direction = forward ? HMStackViewItemDirectionBack : HMStackViewItemDirectionFront; 231 | [self.delegate stackView:self didSendItem:vc direction:direction]; 232 | } 233 | }]; 234 | } 235 | 236 | #pragma mark - Gestures - 237 | 238 | - (void)checkDirections { 239 | if (self.forwardDirections == 0 && self.backwardDirections == 0) { 240 | self.forwardDirections = self.swipeDirections; 241 | } 242 | } 243 | 244 | - (BOOL)isForwardDirection:(UISwipeGestureRecognizerDirection)direction { 245 | return direction & self.forwardDirections; 246 | } 247 | 248 | - (void)swipe:(UISwipeGestureRecognizer *)gesture { 249 | [self checkDirections]; 250 | BOOL forward = [self isForwardDirection:gesture.direction]; 251 | UIViewController *vc = forward ? self.views.firstObject : self.views.lastObject; 252 | 253 | if (self.delegate && [self.delegate respondsToSelector:@selector(stackView:willSendItem:direction:)]) { 254 | HMStackViewItemDirection direction = forward ? HMStackViewItemDirectionBack : HMStackViewItemDirectionFront; 255 | [self.delegate stackView:self willSendItem:vc direction:direction]; 256 | } 257 | 258 | [self sendView:vc direction:gesture.direction]; 259 | 260 | NSMutableArray *views = self.views.mutableCopy; 261 | [views removeObject:vc]; 262 | if (forward) { 263 | [views addObject:vc]; 264 | } else { 265 | [views insertObject:vc atIndex:0]; 266 | } 267 | 268 | self.views = views; 269 | 270 | self.dontUpdateItem = vc; 271 | [self updateViews]; 272 | 273 | @weakify(self); 274 | [UIView animateWithDuration:self.animationDuration animations:^{ 275 | @strongify(self); 276 | if (self.changeAlphaOnSendAnimation) { 277 | vc.view.alpha = 0.; 278 | } 279 | [self layoutIfNeeded]; 280 | } completion:^(BOOL finished) { 281 | @strongify(self); 282 | [self sendViewAnimationCompletion:gesture.direction]; 283 | }]; 284 | } 285 | 286 | @end 287 | -------------------------------------------------------------------------------- /HMStackView/HMStackViewConstraints.h: -------------------------------------------------------------------------------- 1 | // 2 | // HMStackViewConstraints.h 3 | // stack 4 | // 5 | // Created by Oleg Musinov on 7/11/17. 6 | // Copyright © 2017 iBlacksus. All rights reserved. 7 | // 8 | // Modify by Helio Martín on 15/11/2017 9 | 10 | #import 11 | 12 | @interface HMStackViewConstraints : NSObject 13 | 14 | @property (nonatomic, assign) CGFloat leading; 15 | @property (nonatomic, assign) CGFloat trailing; 16 | @property (nonatomic, assign) CGFloat top; 17 | @property (nonatomic, assign) CGFloat bottom; 18 | @property (nonatomic, assign) CGFloat verticalCompression; 19 | @property (nonatomic, assign) CGFloat horizontalCompression; 20 | 21 | - (instancetype)init; 22 | 23 | - (NSArray *)constraintsForView:(UIView *)view index:(NSInteger)index; 24 | - (NSArray *)horizontalConstraintsForView:(UIView *)view index:(NSInteger)index; 25 | - (NSArray *)horizontalConstraintsForView:(UIView *)view leading:(CGFloat)leading trailing:(CGFloat)trailing; 26 | - (NSArray *)verticalConstraintsForView:(UIView *)view index:(NSInteger)index; 27 | - (NSArray *)verticalConstraintsForView:(UIView *)view top:(CGFloat)top bottom:(CGFloat)bottom; 28 | 29 | @end 30 | -------------------------------------------------------------------------------- /HMStackView/HMStackViewConstraints.m: -------------------------------------------------------------------------------- 1 | // 2 | // HMStackViewConstraints.m 3 | // stack 4 | // 5 | // Created by Oleg Musinov on 7/11/17. 6 | // Copyright © 2017 iBlacksus. All rights reserved. 7 | // 8 | // Modify by Helio Martín on 15/11/2017 9 | 10 | #import "HMStackViewConstraints.h" 11 | 12 | static CGFloat const HMStackViewConstraintsLeadingDefault = 40.; 13 | static CGFloat const HMStackViewConstraintsTrailingDefault = 40.; 14 | static CGFloat const HMStackViewConstraintsTopDefault = 100.; 15 | static CGFloat const HMStackViewConstraintsBottomDefault = 140.; 16 | static CGFloat const HMStackViewConstraintsCompressionHorizontalDefault = 10.; 17 | static CGFloat const HMStackViewConstraintsCompressionVerticalDefault = 10.; 18 | 19 | @implementation HMStackViewConstraints 20 | 21 | - (instancetype)init { 22 | if (self = [super init]) { 23 | _leading = HMStackViewConstraintsLeadingDefault; 24 | _trailing = HMStackViewConstraintsTrailingDefault; 25 | _top = HMStackViewConstraintsTopDefault; 26 | _bottom = HMStackViewConstraintsBottomDefault; 27 | _verticalCompression = HMStackViewConstraintsCompressionVerticalDefault; 28 | _horizontalCompression = HMStackViewConstraintsCompressionHorizontalDefault; 29 | } 30 | 31 | return self; 32 | } 33 | 34 | - (NSArray *)constraintsForView:(UIView *)view index:(NSInteger)index { 35 | NSMutableArray *contraints = [NSMutableArray array]; 36 | [contraints addObjectsFromArray:[self horizontalConstraintsForView:view index:index]]; 37 | [contraints addObjectsFromArray:[self verticalConstraintsForView:view index:index]]; 38 | 39 | return contraints; 40 | } 41 | 42 | - (NSArray *)horizontalConstraintsForView:(UIView *)view index:(NSInteger)index { 43 | CGFloat leading = self.leading + self.horizontalCompression * index; 44 | CGFloat trailing = self.trailing + self.horizontalCompression * index; 45 | 46 | return [self horizontalConstraintsForView:view leading:leading trailing:trailing]; 47 | } 48 | 49 | - (NSArray *)horizontalConstraintsForView:(UIView *)view leading:(CGFloat)leading trailing:(CGFloat)trailing { 50 | NSDictionary *views = NSDictionaryOfVariableBindings(view); 51 | NSString *format = [NSString stringWithFormat:@"H:|-(%.f)-[view]-(%.f)-|", leading, trailing]; 52 | 53 | return [NSLayoutConstraint constraintsWithVisualFormat:format options:0 metrics:nil views:views]; 54 | } 55 | 56 | - (NSArray *)verticalConstraintsForView:(UIView *)view index:(NSInteger)index { 57 | CGFloat top = self.top - self.verticalCompression * index; 58 | CGFloat bottom = self.bottom + self.verticalCompression * index; 59 | 60 | return [self verticalConstraintsForView:view top:top bottom:bottom]; 61 | } 62 | 63 | - (NSArray *)verticalConstraintsForView:(UIView *)view top:(CGFloat)top bottom:(CGFloat)bottom { 64 | NSDictionary *views = NSDictionaryOfVariableBindings(view); 65 | NSString *format = [NSString stringWithFormat:@"V:|-(%.f)-[view]-(%.f)-|", top, bottom]; 66 | 67 | return [NSLayoutConstraint constraintsWithVisualFormat:format options:0 metrics:nil views:views]; 68 | } 69 | 70 | @end 71 | -------------------------------------------------------------------------------- /HMStackView/HMStackViewLayoutHelper.h: -------------------------------------------------------------------------------- 1 | // 2 | // HMStackViewLayoutHelper.h 3 | // stack 4 | // 5 | // Created by Oleg Musinov on 7/11/17. 6 | // Copyright © 2017 iBlacksus. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface HMStackViewLayoutHelper : NSObject 12 | 13 | + (NSLayoutAttribute)layoutAttributeForDirection:(UISwipeGestureRecognizerDirection)direction; 14 | + (NSLayoutAttribute)invertLayoutAttribute:(NSLayoutAttribute)attribute; 15 | + (BOOL)isConstraint:(NSLayoutConstraint *)constraint hasAttribute:(NSLayoutAttribute)attribute forItem:(id)item; 16 | + (BOOL)isVerticalAttribute:(NSLayoutAttribute)attribute; 17 | 18 | @end 19 | -------------------------------------------------------------------------------- /HMStackView/HMStackViewLayoutHelper.m: -------------------------------------------------------------------------------- 1 | // 2 | // HMStackViewLayoutHelper.m 3 | // stack 4 | // 5 | // Created by Oleg Musinov on 7/11/17. 6 | // Copyright © 2017 iBlacksus. All rights reserved. 7 | // 8 | 9 | #import "HMStackViewLayoutHelper.h" 10 | 11 | @implementation HMStackViewLayoutHelper 12 | 13 | 14 | + (NSLayoutAttribute)layoutAttributeForDirection:(UISwipeGestureRecognizerDirection)direction { 15 | switch (direction) { 16 | case UISwipeGestureRecognizerDirectionLeft: 17 | return NSLayoutAttributeLeading; 18 | 19 | case UISwipeGestureRecognizerDirectionUp: 20 | return NSLayoutAttributeTop; 21 | 22 | case UISwipeGestureRecognizerDirectionRight: 23 | return NSLayoutAttributeTrailing; 24 | 25 | case UISwipeGestureRecognizerDirectionDown: 26 | return NSLayoutAttributeBottom; 27 | } 28 | } 29 | 30 | + (NSLayoutAttribute)invertLayoutAttribute:(NSLayoutAttribute)attribute { 31 | switch (attribute) { 32 | case NSLayoutAttributeLeading: 33 | return NSLayoutAttributeTrailing; 34 | 35 | case NSLayoutAttributeTop: 36 | return NSLayoutAttributeBottom; 37 | 38 | case NSLayoutAttributeTrailing: 39 | return NSLayoutAttributeLeading; 40 | 41 | case NSLayoutAttributeBottom: 42 | return NSLayoutAttributeTop; 43 | 44 | default: 45 | return NSLayoutAttributeTop; 46 | } 47 | } 48 | 49 | + (BOOL)isConstraint:(NSLayoutConstraint *)constraint hasAttribute:(NSLayoutAttribute)attribute forItem:(id)item { 50 | return (constraint.firstItem == item && constraint.firstAttribute == attribute) || 51 | (constraint.secondItem == item && constraint.secondAttribute == attribute); 52 | } 53 | 54 | + (BOOL)isVerticalAttribute:(NSLayoutAttribute)attribute { 55 | switch (attribute) { 56 | case NSLayoutAttributeLeading: 57 | case NSLayoutAttributeTrailing: 58 | return NO; 59 | 60 | case NSLayoutAttributeTop: 61 | case NSLayoutAttributeBottom: 62 | return YES; 63 | 64 | default: 65 | return NO; 66 | } 67 | } 68 | 69 | @end 70 | -------------------------------------------------------------------------------- /HMStackView/HMStackViewProtocol.h: -------------------------------------------------------------------------------- 1 | // 2 | // HMStackViewProtocol.h 3 | // stack 4 | // 5 | // Created by Oleg Musinov on 7/11/17. 6 | // Copyright © 2017 iBlacksus. All rights reserved. 7 | // 8 | 9 | #import 10 | @class HMStackView; 11 | 12 | typedef NS_ENUM(NSInteger, HMStackViewItemDirection) { 13 | HMStackViewItemDirectionBack, 14 | HMStackViewItemDirectionFront 15 | }; 16 | 17 | @protocol HMStackViewProtocol 18 | @optional 19 | 20 | - (void)stackView:(HMStackView *)stackView willSendItem:(UIViewController *)item direction:(HMStackViewItemDirection)direction; 21 | - (void)stackView:(HMStackView *)stackView didSendItem:(UIViewController *)item direction:(HMStackViewItemDirection)direction; 22 | 23 | @end 24 | -------------------------------------------------------------------------------- /HMStackView/Weakify/EXTScope.h: -------------------------------------------------------------------------------- 1 | // 2 | // EXTScope.h 3 | // extobjc 4 | // 5 | // Created by Justin Spahr-Summers on 2011-05-04. 6 | // Copyright (C) 2012 Justin Spahr-Summers. 7 | // Released under the MIT license. 8 | // 9 | 10 | #import "metamacros.h" 11 | 12 | /** 13 | * \@onExit defines some code to be executed when the current scope exits. The 14 | * code must be enclosed in braces and terminated with a semicolon, and will be 15 | * executed regardless of how the scope is exited, including from exceptions, 16 | * \c goto, \c return, \c break, and \c continue. 17 | * 18 | * Provided code will go into a block to be executed later. Keep this in mind as 19 | * it pertains to memory management, restrictions on assignment, etc. Because 20 | * the code is used within a block, \c return is a legal (though perhaps 21 | * confusing) way to exit the cleanup block early. 22 | * 23 | * Multiple \@onExit statements in the same scope are executed in reverse 24 | * lexical order. This helps when pairing resource acquisition with \@onExit 25 | * statements, as it guarantees teardown in the opposite order of acquisition. 26 | * 27 | * @note This statement cannot be used within scopes defined without braces 28 | * (like a one line \c if). In practice, this is not an issue, since \@onExit is 29 | * a useless construct in such a case anyways. 30 | */ 31 | #define onExit \ 32 | ext_keywordify \ 33 | __strong ext_cleanupBlock_t metamacro_concat(ext_exitBlock_, __LINE__) __attribute__((cleanup(ext_executeCleanupBlock), unused)) = ^ 34 | 35 | /** 36 | * Creates \c __weak shadow variables for each of the variables provided as 37 | * arguments, which can later be made strong again with #strongify. 38 | * 39 | * This is typically used to weakly reference variables in a block, but then 40 | * ensure that the variables stay alive during the actual execution of the block 41 | * (if they were live upon entry). 42 | * 43 | * See #strongify for an example of usage. 44 | */ 45 | #define weakify(...) \ 46 | ext_keywordify \ 47 | metamacro_foreach_cxt(ext_weakify_,, __weak, __VA_ARGS__) 48 | 49 | /** 50 | * Like #weakify, but uses \c __unsafe_unretained instead, for targets or 51 | * classes that do not support weak references. 52 | */ 53 | #define unsafeify(...) \ 54 | ext_keywordify \ 55 | metamacro_foreach_cxt(ext_weakify_,, __unsafe_unretained, __VA_ARGS__) 56 | 57 | /** 58 | * Strongly references each of the variables provided as arguments, which must 59 | * have previously been passed to #weakify. 60 | * 61 | * The strong references created will shadow the original variable names, such 62 | * that the original names can be used without issue (and a significantly 63 | * reduced risk of retain cycles) in the current scope. 64 | * 65 | * @code 66 | 67 | id foo = [[NSObject alloc] init]; 68 | id bar = [[NSObject alloc] init]; 69 | 70 | @weakify(foo, bar); 71 | 72 | // this block will not keep 'foo' or 'bar' alive 73 | BOOL (^matchesFooOrBar)(id) = ^ BOOL (id obj){ 74 | // but now, upon entry, 'foo' and 'bar' will stay alive until the block has 75 | // finished executing 76 | @strongify(foo, bar); 77 | 78 | return [foo isEqual:obj] || [bar isEqual:obj]; 79 | }; 80 | 81 | * @endcode 82 | */ 83 | #define strongify(...) \ 84 | ext_keywordify \ 85 | _Pragma("clang diagnostic push") \ 86 | _Pragma("clang diagnostic ignored \"-Wshadow\"") \ 87 | metamacro_foreach(ext_strongify_,, __VA_ARGS__) \ 88 | _Pragma("clang diagnostic pop") 89 | 90 | /*** implementation details follow ***/ 91 | typedef void (^ext_cleanupBlock_t)(); 92 | 93 | #if defined(__cplusplus) 94 | extern "C" { 95 | #endif 96 | void ext_executeCleanupBlock (__strong ext_cleanupBlock_t *block); 97 | #if defined(__cplusplus) 98 | } 99 | #endif 100 | 101 | #define ext_weakify_(INDEX, CONTEXT, VAR) \ 102 | CONTEXT __typeof__(VAR) metamacro_concat(VAR, _weak_) = (VAR); 103 | 104 | #define ext_strongify_(INDEX, VAR) \ 105 | __strong __typeof__(VAR) VAR = metamacro_concat(VAR, _weak_); 106 | 107 | // Details about the choice of backing keyword: 108 | // 109 | // The use of @try/@catch/@finally can cause the compiler to suppress 110 | // return-type warnings. 111 | // The use of @autoreleasepool {} is not optimized away by the compiler, 112 | // resulting in superfluous creation of autorelease pools. 113 | // 114 | // Since neither option is perfect, and with no other alternatives, the 115 | // compromise is to use @autorelease in DEBUG builds to maintain compiler 116 | // analysis, and to use @try/@catch otherwise to avoid insertion of unnecessary 117 | // autorelease pools. 118 | #if defined(DEBUG) && !defined(NDEBUG) 119 | #define ext_keywordify autoreleasepool {} 120 | #else 121 | #define ext_keywordify try {} @catch (...) {} 122 | #endif 123 | 124 | #define safeblock(block, ...) \ 125 | ext_keywordify \ 126 | block ? block(__VA_ARGS__) : nil 127 | -------------------------------------------------------------------------------- /HMStackView/Weakify/EXTScope.m: -------------------------------------------------------------------------------- 1 | // 2 | // EXTScope.m 3 | // extobjc 4 | // 5 | // Created by Justin Spahr-Summers on 2011-05-04. 6 | // Copyright (C) 2012 Justin Spahr-Summers. 7 | // Released under the MIT license. 8 | // 9 | 10 | #import "EXTScope.h" 11 | 12 | void ext_executeCleanupBlock (__strong ext_cleanupBlock_t *block) { 13 | (*block)(); 14 | } 15 | 16 | -------------------------------------------------------------------------------- /HMStackView/Weakify/metamacros.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Macros for metaprogramming 3 | * ExtendedC 4 | * 5 | * Copyright (C) 2012 Justin Spahr-Summers 6 | * Released under the MIT license 7 | */ 8 | 9 | #ifndef EXTC_METAMACROS_H 10 | #define EXTC_METAMACROS_H 11 | 12 | 13 | /** 14 | * Executes one or more expressions (which may have a void type, such as a call 15 | * to a function that returns no value) and always returns true. 16 | */ 17 | #define metamacro_exprify(...) \ 18 | ((__VA_ARGS__), true) 19 | 20 | /** 21 | * Returns a string representation of VALUE after full macro expansion. 22 | */ 23 | #define metamacro_stringify(VALUE) \ 24 | metamacro_stringify_(VALUE) 25 | 26 | /** 27 | * Returns A and B concatenated after full macro expansion. 28 | */ 29 | #define metamacro_concat(A, B) \ 30 | metamacro_concat_(A, B) 31 | 32 | /** 33 | * Returns the Nth variadic argument (starting from zero). At least 34 | * N + 1 variadic arguments must be given. N must be between zero and twenty, 35 | * inclusive. 36 | */ 37 | #define metamacro_at(N, ...) \ 38 | metamacro_concat(metamacro_at, N)(__VA_ARGS__) 39 | 40 | /** 41 | * Returns the number of arguments (up to twenty) provided to the macro. At 42 | * least one argument must be provided. 43 | * 44 | * Inspired by P99: http://p99.gforge.inria.fr 45 | */ 46 | #define metamacro_argcount(...) \ 47 | metamacro_at(20, __VA_ARGS__, 20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1) 48 | 49 | /** 50 | * Identical to #metamacro_foreach_cxt, except that no CONTEXT argument is 51 | * given. Only the index and current argument will thus be passed to MACRO. 52 | */ 53 | #define metamacro_foreach(MACRO, SEP, ...) \ 54 | metamacro_foreach_cxt(metamacro_foreach_iter, SEP, MACRO, __VA_ARGS__) 55 | 56 | /** 57 | * For each consecutive variadic argument (up to twenty), MACRO is passed the 58 | * zero-based index of the current argument, CONTEXT, and then the argument 59 | * itself. The results of adjoining invocations of MACRO are then separated by 60 | * SEP. 61 | * 62 | * Inspired by P99: http://p99.gforge.inria.fr 63 | */ 64 | #define metamacro_foreach_cxt(MACRO, SEP, CONTEXT, ...) \ 65 | metamacro_concat(metamacro_foreach_cxt, metamacro_argcount(__VA_ARGS__))(MACRO, SEP, CONTEXT, __VA_ARGS__) 66 | 67 | /** 68 | * Identical to #metamacro_foreach_cxt. This can be used when the former would 69 | * fail due to recursive macro expansion. 70 | */ 71 | #define metamacro_foreach_cxt_recursive(MACRO, SEP, CONTEXT, ...) \ 72 | metamacro_concat(metamacro_foreach_cxt_recursive, metamacro_argcount(__VA_ARGS__))(MACRO, SEP, CONTEXT, __VA_ARGS__) 73 | 74 | /** 75 | * In consecutive order, appends each variadic argument (up to twenty) onto 76 | * BASE. The resulting concatenations are then separated by SEP. 77 | * 78 | * This is primarily useful to manipulate a list of macro invocations into instead 79 | * invoking a different, possibly related macro. 80 | */ 81 | #define metamacro_foreach_concat(BASE, SEP, ...) \ 82 | metamacro_foreach_cxt(metamacro_foreach_concat_iter, SEP, BASE, __VA_ARGS__) 83 | 84 | /** 85 | * Iterates COUNT times, each time invoking MACRO with the current index 86 | * (starting at zero) and CONTEXT. The results of adjoining invocations of MACRO 87 | * are then separated by SEP. 88 | * 89 | * COUNT must be an integer between zero and twenty, inclusive. 90 | */ 91 | #define metamacro_for_cxt(COUNT, MACRO, SEP, CONTEXT) \ 92 | metamacro_concat(metamacro_for_cxt, COUNT)(MACRO, SEP, CONTEXT) 93 | 94 | /** 95 | * Returns the first argument given. At least one argument must be provided. 96 | * 97 | * This is useful when implementing a variadic macro, where you may have only 98 | * one variadic argument, but no way to retrieve it (for example, because \c ... 99 | * always needs to match at least one argument). 100 | * 101 | * @code 102 | 103 | #define varmacro(...) \ 104 | metamacro_head(__VA_ARGS__) 105 | 106 | * @endcode 107 | */ 108 | #define metamacro_head(...) \ 109 | metamacro_head_(__VA_ARGS__, 0) 110 | 111 | /** 112 | * Returns every argument except the first. At least two arguments must be 113 | * provided. 114 | */ 115 | #define metamacro_tail(...) \ 116 | metamacro_tail_(__VA_ARGS__) 117 | 118 | /** 119 | * Returns the first N (up to twenty) variadic arguments as a new argument list. 120 | * At least N variadic arguments must be provided. 121 | */ 122 | #define metamacro_take(N, ...) \ 123 | metamacro_concat(metamacro_take, N)(__VA_ARGS__) 124 | 125 | /** 126 | * Removes the first N (up to twenty) variadic arguments from the given argument 127 | * list. At least N variadic arguments must be provided. 128 | */ 129 | #define metamacro_drop(N, ...) \ 130 | metamacro_concat(metamacro_drop, N)(__VA_ARGS__) 131 | 132 | /** 133 | * Decrements VAL, which must be a number between zero and twenty, inclusive. 134 | * 135 | * This is primarily useful when dealing with indexes and counts in 136 | * metaprogramming. 137 | */ 138 | #define metamacro_dec(VAL) \ 139 | metamacro_at(VAL, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19) 140 | 141 | /** 142 | * Increments VAL, which must be a number between zero and twenty, inclusive. 143 | * 144 | * This is primarily useful when dealing with indexes and counts in 145 | * metaprogramming. 146 | */ 147 | #define metamacro_inc(VAL) \ 148 | metamacro_at(VAL, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21) 149 | 150 | /** 151 | * If A is equal to B, the next argument list is expanded; otherwise, the 152 | * argument list after that is expanded. A and B must be numbers between zero 153 | * and twenty, inclusive. Additionally, B must be greater than or equal to A. 154 | * 155 | * @code 156 | 157 | // expands to true 158 | metamacro_if_eq(0, 0)(true)(false) 159 | 160 | // expands to false 161 | metamacro_if_eq(0, 1)(true)(false) 162 | 163 | * @endcode 164 | * 165 | * This is primarily useful when dealing with indexes and counts in 166 | * metaprogramming. 167 | */ 168 | #define metamacro_if_eq(A, B) \ 169 | metamacro_concat(metamacro_if_eq, A)(B) 170 | 171 | /** 172 | * Identical to #metamacro_if_eq. This can be used when the former would fail 173 | * due to recursive macro expansion. 174 | */ 175 | #define metamacro_if_eq_recursive(A, B) \ 176 | metamacro_concat(metamacro_if_eq_recursive, A)(B) 177 | 178 | /** 179 | * Returns 1 if N is an even number, or 0 otherwise. N must be between zero and 180 | * twenty, inclusive. 181 | * 182 | * For the purposes of this test, zero is considered even. 183 | */ 184 | #define metamacro_is_even(N) \ 185 | metamacro_at(N, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1) 186 | 187 | /** 188 | * Returns the logical NOT of B, which must be the number zero or one. 189 | */ 190 | #define metamacro_not(B) \ 191 | metamacro_at(B, 1, 0) 192 | 193 | // IMPLEMENTATION DETAILS FOLLOW! 194 | // Do not write code that depends on anything below this line. 195 | #define metamacro_stringify_(VALUE) # VALUE 196 | #define metamacro_concat_(A, B) A ## B 197 | #define metamacro_foreach_iter(INDEX, MACRO, ARG) MACRO(INDEX, ARG) 198 | #define metamacro_head_(FIRST, ...) FIRST 199 | #define metamacro_tail_(FIRST, ...) __VA_ARGS__ 200 | #define metamacro_consume_(...) 201 | #define metamacro_expand_(...) __VA_ARGS__ 202 | 203 | // implemented from scratch so that metamacro_concat() doesn't end up nesting 204 | #define metamacro_foreach_concat_iter(INDEX, BASE, ARG) metamacro_foreach_concat_iter_(BASE, ARG) 205 | #define metamacro_foreach_concat_iter_(BASE, ARG) BASE ## ARG 206 | 207 | // metamacro_at expansions 208 | #define metamacro_at0(...) metamacro_head(__VA_ARGS__) 209 | #define metamacro_at1(_0, ...) metamacro_head(__VA_ARGS__) 210 | #define metamacro_at2(_0, _1, ...) metamacro_head(__VA_ARGS__) 211 | #define metamacro_at3(_0, _1, _2, ...) metamacro_head(__VA_ARGS__) 212 | #define metamacro_at4(_0, _1, _2, _3, ...) metamacro_head(__VA_ARGS__) 213 | #define metamacro_at5(_0, _1, _2, _3, _4, ...) metamacro_head(__VA_ARGS__) 214 | #define metamacro_at6(_0, _1, _2, _3, _4, _5, ...) metamacro_head(__VA_ARGS__) 215 | #define metamacro_at7(_0, _1, _2, _3, _4, _5, _6, ...) metamacro_head(__VA_ARGS__) 216 | #define metamacro_at8(_0, _1, _2, _3, _4, _5, _6, _7, ...) metamacro_head(__VA_ARGS__) 217 | #define metamacro_at9(_0, _1, _2, _3, _4, _5, _6, _7, _8, ...) metamacro_head(__VA_ARGS__) 218 | #define metamacro_at10(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, ...) metamacro_head(__VA_ARGS__) 219 | #define metamacro_at11(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, ...) metamacro_head(__VA_ARGS__) 220 | #define metamacro_at12(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, ...) metamacro_head(__VA_ARGS__) 221 | #define metamacro_at13(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, ...) metamacro_head(__VA_ARGS__) 222 | #define metamacro_at14(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, ...) metamacro_head(__VA_ARGS__) 223 | #define metamacro_at15(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, ...) metamacro_head(__VA_ARGS__) 224 | #define metamacro_at16(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, ...) metamacro_head(__VA_ARGS__) 225 | #define metamacro_at17(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, ...) metamacro_head(__VA_ARGS__) 226 | #define metamacro_at18(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, ...) metamacro_head(__VA_ARGS__) 227 | #define metamacro_at19(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, ...) metamacro_head(__VA_ARGS__) 228 | #define metamacro_at20(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, ...) metamacro_head(__VA_ARGS__) 229 | 230 | // metamacro_foreach_cxt expansions 231 | #define metamacro_foreach_cxt0(MACRO, SEP, CONTEXT) 232 | #define metamacro_foreach_cxt1(MACRO, SEP, CONTEXT, _0) MACRO(0, CONTEXT, _0) 233 | 234 | #define metamacro_foreach_cxt2(MACRO, SEP, CONTEXT, _0, _1) \ 235 | metamacro_foreach_cxt1(MACRO, SEP, CONTEXT, _0) \ 236 | SEP \ 237 | MACRO(1, CONTEXT, _1) 238 | 239 | #define metamacro_foreach_cxt3(MACRO, SEP, CONTEXT, _0, _1, _2) \ 240 | metamacro_foreach_cxt2(MACRO, SEP, CONTEXT, _0, _1) \ 241 | SEP \ 242 | MACRO(2, CONTEXT, _2) 243 | 244 | #define metamacro_foreach_cxt4(MACRO, SEP, CONTEXT, _0, _1, _2, _3) \ 245 | metamacro_foreach_cxt3(MACRO, SEP, CONTEXT, _0, _1, _2) \ 246 | SEP \ 247 | MACRO(3, CONTEXT, _3) 248 | 249 | #define metamacro_foreach_cxt5(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4) \ 250 | metamacro_foreach_cxt4(MACRO, SEP, CONTEXT, _0, _1, _2, _3) \ 251 | SEP \ 252 | MACRO(4, CONTEXT, _4) 253 | 254 | #define metamacro_foreach_cxt6(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5) \ 255 | metamacro_foreach_cxt5(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4) \ 256 | SEP \ 257 | MACRO(5, CONTEXT, _5) 258 | 259 | #define metamacro_foreach_cxt7(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6) \ 260 | metamacro_foreach_cxt6(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5) \ 261 | SEP \ 262 | MACRO(6, CONTEXT, _6) 263 | 264 | #define metamacro_foreach_cxt8(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7) \ 265 | metamacro_foreach_cxt7(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6) \ 266 | SEP \ 267 | MACRO(7, CONTEXT, _7) 268 | 269 | #define metamacro_foreach_cxt9(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8) \ 270 | metamacro_foreach_cxt8(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7) \ 271 | SEP \ 272 | MACRO(8, CONTEXT, _8) 273 | 274 | #define metamacro_foreach_cxt10(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9) \ 275 | metamacro_foreach_cxt9(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8) \ 276 | SEP \ 277 | MACRO(9, CONTEXT, _9) 278 | 279 | #define metamacro_foreach_cxt11(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10) \ 280 | metamacro_foreach_cxt10(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9) \ 281 | SEP \ 282 | MACRO(10, CONTEXT, _10) 283 | 284 | #define metamacro_foreach_cxt12(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11) \ 285 | metamacro_foreach_cxt11(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10) \ 286 | SEP \ 287 | MACRO(11, CONTEXT, _11) 288 | 289 | #define metamacro_foreach_cxt13(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12) \ 290 | metamacro_foreach_cxt12(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11) \ 291 | SEP \ 292 | MACRO(12, CONTEXT, _12) 293 | 294 | #define metamacro_foreach_cxt14(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13) \ 295 | metamacro_foreach_cxt13(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12) \ 296 | SEP \ 297 | MACRO(13, CONTEXT, _13) 298 | 299 | #define metamacro_foreach_cxt15(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14) \ 300 | metamacro_foreach_cxt14(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13) \ 301 | SEP \ 302 | MACRO(14, CONTEXT, _14) 303 | 304 | #define metamacro_foreach_cxt16(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15) \ 305 | metamacro_foreach_cxt15(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14) \ 306 | SEP \ 307 | MACRO(15, CONTEXT, _15) 308 | 309 | #define metamacro_foreach_cxt17(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16) \ 310 | metamacro_foreach_cxt16(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15) \ 311 | SEP \ 312 | MACRO(16, CONTEXT, _16) 313 | 314 | #define metamacro_foreach_cxt18(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17) \ 315 | metamacro_foreach_cxt17(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16) \ 316 | SEP \ 317 | MACRO(17, CONTEXT, _17) 318 | 319 | #define metamacro_foreach_cxt19(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18) \ 320 | metamacro_foreach_cxt18(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17) \ 321 | SEP \ 322 | MACRO(18, CONTEXT, _18) 323 | 324 | #define metamacro_foreach_cxt20(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19) \ 325 | metamacro_foreach_cxt19(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18) \ 326 | SEP \ 327 | MACRO(19, CONTEXT, _19) 328 | 329 | // metamacro_foreach_cxt_recursive expansions 330 | #define metamacro_foreach_cxt_recursive0(MACRO, SEP, CONTEXT) 331 | #define metamacro_foreach_cxt_recursive1(MACRO, SEP, CONTEXT, _0) MACRO(0, CONTEXT, _0) 332 | 333 | #define metamacro_foreach_cxt_recursive2(MACRO, SEP, CONTEXT, _0, _1) \ 334 | metamacro_foreach_cxt_recursive1(MACRO, SEP, CONTEXT, _0) \ 335 | SEP \ 336 | MACRO(1, CONTEXT, _1) 337 | 338 | #define metamacro_foreach_cxt_recursive3(MACRO, SEP, CONTEXT, _0, _1, _2) \ 339 | metamacro_foreach_cxt_recursive2(MACRO, SEP, CONTEXT, _0, _1) \ 340 | SEP \ 341 | MACRO(2, CONTEXT, _2) 342 | 343 | #define metamacro_foreach_cxt_recursive4(MACRO, SEP, CONTEXT, _0, _1, _2, _3) \ 344 | metamacro_foreach_cxt_recursive3(MACRO, SEP, CONTEXT, _0, _1, _2) \ 345 | SEP \ 346 | MACRO(3, CONTEXT, _3) 347 | 348 | #define metamacro_foreach_cxt_recursive5(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4) \ 349 | metamacro_foreach_cxt_recursive4(MACRO, SEP, CONTEXT, _0, _1, _2, _3) \ 350 | SEP \ 351 | MACRO(4, CONTEXT, _4) 352 | 353 | #define metamacro_foreach_cxt_recursive6(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5) \ 354 | metamacro_foreach_cxt_recursive5(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4) \ 355 | SEP \ 356 | MACRO(5, CONTEXT, _5) 357 | 358 | #define metamacro_foreach_cxt_recursive7(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6) \ 359 | metamacro_foreach_cxt_recursive6(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5) \ 360 | SEP \ 361 | MACRO(6, CONTEXT, _6) 362 | 363 | #define metamacro_foreach_cxt_recursive8(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7) \ 364 | metamacro_foreach_cxt_recursive7(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6) \ 365 | SEP \ 366 | MACRO(7, CONTEXT, _7) 367 | 368 | #define metamacro_foreach_cxt_recursive9(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8) \ 369 | metamacro_foreach_cxt_recursive8(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7) \ 370 | SEP \ 371 | MACRO(8, CONTEXT, _8) 372 | 373 | #define metamacro_foreach_cxt_recursive10(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9) \ 374 | metamacro_foreach_cxt_recursive9(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8) \ 375 | SEP \ 376 | MACRO(9, CONTEXT, _9) 377 | 378 | #define metamacro_foreach_cxt_recursive11(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10) \ 379 | metamacro_foreach_cxt_recursive10(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9) \ 380 | SEP \ 381 | MACRO(10, CONTEXT, _10) 382 | 383 | #define metamacro_foreach_cxt_recursive12(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11) \ 384 | metamacro_foreach_cxt_recursive11(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10) \ 385 | SEP \ 386 | MACRO(11, CONTEXT, _11) 387 | 388 | #define metamacro_foreach_cxt_recursive13(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12) \ 389 | metamacro_foreach_cxt_recursive12(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11) \ 390 | SEP \ 391 | MACRO(12, CONTEXT, _12) 392 | 393 | #define metamacro_foreach_cxt_recursive14(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13) \ 394 | metamacro_foreach_cxt_recursive13(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12) \ 395 | SEP \ 396 | MACRO(13, CONTEXT, _13) 397 | 398 | #define metamacro_foreach_cxt_recursive15(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14) \ 399 | metamacro_foreach_cxt_recursive14(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13) \ 400 | SEP \ 401 | MACRO(14, CONTEXT, _14) 402 | 403 | #define metamacro_foreach_cxt_recursive16(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15) \ 404 | metamacro_foreach_cxt_recursive15(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14) \ 405 | SEP \ 406 | MACRO(15, CONTEXT, _15) 407 | 408 | #define metamacro_foreach_cxt_recursive17(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16) \ 409 | metamacro_foreach_cxt_recursive16(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15) \ 410 | SEP \ 411 | MACRO(16, CONTEXT, _16) 412 | 413 | #define metamacro_foreach_cxt_recursive18(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17) \ 414 | metamacro_foreach_cxt_recursive17(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16) \ 415 | SEP \ 416 | MACRO(17, CONTEXT, _17) 417 | 418 | #define metamacro_foreach_cxt_recursive19(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18) \ 419 | metamacro_foreach_cxt_recursive18(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17) \ 420 | SEP \ 421 | MACRO(18, CONTEXT, _18) 422 | 423 | #define metamacro_foreach_cxt_recursive20(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19) \ 424 | metamacro_foreach_cxt_recursive19(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18) \ 425 | SEP \ 426 | MACRO(19, CONTEXT, _19) 427 | 428 | // metamacro_for_cxt expansions 429 | #define metamacro_for_cxt0(MACRO, SEP, CONTEXT) 430 | #define metamacro_for_cxt1(MACRO, SEP, CONTEXT) MACRO(0, CONTEXT) 431 | 432 | #define metamacro_for_cxt2(MACRO, SEP, CONTEXT) \ 433 | metamacro_for_cxt1(MACRO, SEP, CONTEXT) \ 434 | SEP \ 435 | MACRO(1, CONTEXT) 436 | 437 | #define metamacro_for_cxt3(MACRO, SEP, CONTEXT) \ 438 | metamacro_for_cxt2(MACRO, SEP, CONTEXT) \ 439 | SEP \ 440 | MACRO(2, CONTEXT) 441 | 442 | #define metamacro_for_cxt4(MACRO, SEP, CONTEXT) \ 443 | metamacro_for_cxt3(MACRO, SEP, CONTEXT) \ 444 | SEP \ 445 | MACRO(3, CONTEXT) 446 | 447 | #define metamacro_for_cxt5(MACRO, SEP, CONTEXT) \ 448 | metamacro_for_cxt4(MACRO, SEP, CONTEXT) \ 449 | SEP \ 450 | MACRO(4, CONTEXT) 451 | 452 | #define metamacro_for_cxt6(MACRO, SEP, CONTEXT) \ 453 | metamacro_for_cxt5(MACRO, SEP, CONTEXT) \ 454 | SEP \ 455 | MACRO(5, CONTEXT) 456 | 457 | #define metamacro_for_cxt7(MACRO, SEP, CONTEXT) \ 458 | metamacro_for_cxt6(MACRO, SEP, CONTEXT) \ 459 | SEP \ 460 | MACRO(6, CONTEXT) 461 | 462 | #define metamacro_for_cxt8(MACRO, SEP, CONTEXT) \ 463 | metamacro_for_cxt7(MACRO, SEP, CONTEXT) \ 464 | SEP \ 465 | MACRO(7, CONTEXT) 466 | 467 | #define metamacro_for_cxt9(MACRO, SEP, CONTEXT) \ 468 | metamacro_for_cxt8(MACRO, SEP, CONTEXT) \ 469 | SEP \ 470 | MACRO(8, CONTEXT) 471 | 472 | #define metamacro_for_cxt10(MACRO, SEP, CONTEXT) \ 473 | metamacro_for_cxt9(MACRO, SEP, CONTEXT) \ 474 | SEP \ 475 | MACRO(9, CONTEXT) 476 | 477 | #define metamacro_for_cxt11(MACRO, SEP, CONTEXT) \ 478 | metamacro_for_cxt10(MACRO, SEP, CONTEXT) \ 479 | SEP \ 480 | MACRO(10, CONTEXT) 481 | 482 | #define metamacro_for_cxt12(MACRO, SEP, CONTEXT) \ 483 | metamacro_for_cxt11(MACRO, SEP, CONTEXT) \ 484 | SEP \ 485 | MACRO(11, CONTEXT) 486 | 487 | #define metamacro_for_cxt13(MACRO, SEP, CONTEXT) \ 488 | metamacro_for_cxt12(MACRO, SEP, CONTEXT) \ 489 | SEP \ 490 | MACRO(12, CONTEXT) 491 | 492 | #define metamacro_for_cxt14(MACRO, SEP, CONTEXT) \ 493 | metamacro_for_cxt13(MACRO, SEP, CONTEXT) \ 494 | SEP \ 495 | MACRO(13, CONTEXT) 496 | 497 | #define metamacro_for_cxt15(MACRO, SEP, CONTEXT) \ 498 | metamacro_for_cxt14(MACRO, SEP, CONTEXT) \ 499 | SEP \ 500 | MACRO(14, CONTEXT) 501 | 502 | #define metamacro_for_cxt16(MACRO, SEP, CONTEXT) \ 503 | metamacro_for_cxt15(MACRO, SEP, CONTEXT) \ 504 | SEP \ 505 | MACRO(15, CONTEXT) 506 | 507 | #define metamacro_for_cxt17(MACRO, SEP, CONTEXT) \ 508 | metamacro_for_cxt16(MACRO, SEP, CONTEXT) \ 509 | SEP \ 510 | MACRO(16, CONTEXT) 511 | 512 | #define metamacro_for_cxt18(MACRO, SEP, CONTEXT) \ 513 | metamacro_for_cxt17(MACRO, SEP, CONTEXT) \ 514 | SEP \ 515 | MACRO(17, CONTEXT) 516 | 517 | #define metamacro_for_cxt19(MACRO, SEP, CONTEXT) \ 518 | metamacro_for_cxt18(MACRO, SEP, CONTEXT) \ 519 | SEP \ 520 | MACRO(18, CONTEXT) 521 | 522 | #define metamacro_for_cxt20(MACRO, SEP, CONTEXT) \ 523 | metamacro_for_cxt19(MACRO, SEP, CONTEXT) \ 524 | SEP \ 525 | MACRO(19, CONTEXT) 526 | 527 | // metamacro_if_eq expansions 528 | #define metamacro_if_eq0(VALUE) \ 529 | metamacro_concat(metamacro_if_eq0_, VALUE) 530 | 531 | #define metamacro_if_eq0_0(...) __VA_ARGS__ metamacro_consume_ 532 | #define metamacro_if_eq0_1(...) metamacro_expand_ 533 | #define metamacro_if_eq0_2(...) metamacro_expand_ 534 | #define metamacro_if_eq0_3(...) metamacro_expand_ 535 | #define metamacro_if_eq0_4(...) metamacro_expand_ 536 | #define metamacro_if_eq0_5(...) metamacro_expand_ 537 | #define metamacro_if_eq0_6(...) metamacro_expand_ 538 | #define metamacro_if_eq0_7(...) metamacro_expand_ 539 | #define metamacro_if_eq0_8(...) metamacro_expand_ 540 | #define metamacro_if_eq0_9(...) metamacro_expand_ 541 | #define metamacro_if_eq0_10(...) metamacro_expand_ 542 | #define metamacro_if_eq0_11(...) metamacro_expand_ 543 | #define metamacro_if_eq0_12(...) metamacro_expand_ 544 | #define metamacro_if_eq0_13(...) metamacro_expand_ 545 | #define metamacro_if_eq0_14(...) metamacro_expand_ 546 | #define metamacro_if_eq0_15(...) metamacro_expand_ 547 | #define metamacro_if_eq0_16(...) metamacro_expand_ 548 | #define metamacro_if_eq0_17(...) metamacro_expand_ 549 | #define metamacro_if_eq0_18(...) metamacro_expand_ 550 | #define metamacro_if_eq0_19(...) metamacro_expand_ 551 | #define metamacro_if_eq0_20(...) metamacro_expand_ 552 | 553 | #define metamacro_if_eq1(VALUE) metamacro_if_eq0(metamacro_dec(VALUE)) 554 | #define metamacro_if_eq2(VALUE) metamacro_if_eq1(metamacro_dec(VALUE)) 555 | #define metamacro_if_eq3(VALUE) metamacro_if_eq2(metamacro_dec(VALUE)) 556 | #define metamacro_if_eq4(VALUE) metamacro_if_eq3(metamacro_dec(VALUE)) 557 | #define metamacro_if_eq5(VALUE) metamacro_if_eq4(metamacro_dec(VALUE)) 558 | #define metamacro_if_eq6(VALUE) metamacro_if_eq5(metamacro_dec(VALUE)) 559 | #define metamacro_if_eq7(VALUE) metamacro_if_eq6(metamacro_dec(VALUE)) 560 | #define metamacro_if_eq8(VALUE) metamacro_if_eq7(metamacro_dec(VALUE)) 561 | #define metamacro_if_eq9(VALUE) metamacro_if_eq8(metamacro_dec(VALUE)) 562 | #define metamacro_if_eq10(VALUE) metamacro_if_eq9(metamacro_dec(VALUE)) 563 | #define metamacro_if_eq11(VALUE) metamacro_if_eq10(metamacro_dec(VALUE)) 564 | #define metamacro_if_eq12(VALUE) metamacro_if_eq11(metamacro_dec(VALUE)) 565 | #define metamacro_if_eq13(VALUE) metamacro_if_eq12(metamacro_dec(VALUE)) 566 | #define metamacro_if_eq14(VALUE) metamacro_if_eq13(metamacro_dec(VALUE)) 567 | #define metamacro_if_eq15(VALUE) metamacro_if_eq14(metamacro_dec(VALUE)) 568 | #define metamacro_if_eq16(VALUE) metamacro_if_eq15(metamacro_dec(VALUE)) 569 | #define metamacro_if_eq17(VALUE) metamacro_if_eq16(metamacro_dec(VALUE)) 570 | #define metamacro_if_eq18(VALUE) metamacro_if_eq17(metamacro_dec(VALUE)) 571 | #define metamacro_if_eq19(VALUE) metamacro_if_eq18(metamacro_dec(VALUE)) 572 | #define metamacro_if_eq20(VALUE) metamacro_if_eq19(metamacro_dec(VALUE)) 573 | 574 | // metamacro_if_eq_recursive expansions 575 | #define metamacro_if_eq_recursive0(VALUE) \ 576 | metamacro_concat(metamacro_if_eq_recursive0_, VALUE) 577 | 578 | #define metamacro_if_eq_recursive0_0(...) __VA_ARGS__ metamacro_consume_ 579 | #define metamacro_if_eq_recursive0_1(...) metamacro_expand_ 580 | #define metamacro_if_eq_recursive0_2(...) metamacro_expand_ 581 | #define metamacro_if_eq_recursive0_3(...) metamacro_expand_ 582 | #define metamacro_if_eq_recursive0_4(...) metamacro_expand_ 583 | #define metamacro_if_eq_recursive0_5(...) metamacro_expand_ 584 | #define metamacro_if_eq_recursive0_6(...) metamacro_expand_ 585 | #define metamacro_if_eq_recursive0_7(...) metamacro_expand_ 586 | #define metamacro_if_eq_recursive0_8(...) metamacro_expand_ 587 | #define metamacro_if_eq_recursive0_9(...) metamacro_expand_ 588 | #define metamacro_if_eq_recursive0_10(...) metamacro_expand_ 589 | #define metamacro_if_eq_recursive0_11(...) metamacro_expand_ 590 | #define metamacro_if_eq_recursive0_12(...) metamacro_expand_ 591 | #define metamacro_if_eq_recursive0_13(...) metamacro_expand_ 592 | #define metamacro_if_eq_recursive0_14(...) metamacro_expand_ 593 | #define metamacro_if_eq_recursive0_15(...) metamacro_expand_ 594 | #define metamacro_if_eq_recursive0_16(...) metamacro_expand_ 595 | #define metamacro_if_eq_recursive0_17(...) metamacro_expand_ 596 | #define metamacro_if_eq_recursive0_18(...) metamacro_expand_ 597 | #define metamacro_if_eq_recursive0_19(...) metamacro_expand_ 598 | #define metamacro_if_eq_recursive0_20(...) metamacro_expand_ 599 | 600 | #define metamacro_if_eq_recursive1(VALUE) metamacro_if_eq_recursive0(metamacro_dec(VALUE)) 601 | #define metamacro_if_eq_recursive2(VALUE) metamacro_if_eq_recursive1(metamacro_dec(VALUE)) 602 | #define metamacro_if_eq_recursive3(VALUE) metamacro_if_eq_recursive2(metamacro_dec(VALUE)) 603 | #define metamacro_if_eq_recursive4(VALUE) metamacro_if_eq_recursive3(metamacro_dec(VALUE)) 604 | #define metamacro_if_eq_recursive5(VALUE) metamacro_if_eq_recursive4(metamacro_dec(VALUE)) 605 | #define metamacro_if_eq_recursive6(VALUE) metamacro_if_eq_recursive5(metamacro_dec(VALUE)) 606 | #define metamacro_if_eq_recursive7(VALUE) metamacro_if_eq_recursive6(metamacro_dec(VALUE)) 607 | #define metamacro_if_eq_recursive8(VALUE) metamacro_if_eq_recursive7(metamacro_dec(VALUE)) 608 | #define metamacro_if_eq_recursive9(VALUE) metamacro_if_eq_recursive8(metamacro_dec(VALUE)) 609 | #define metamacro_if_eq_recursive10(VALUE) metamacro_if_eq_recursive9(metamacro_dec(VALUE)) 610 | #define metamacro_if_eq_recursive11(VALUE) metamacro_if_eq_recursive10(metamacro_dec(VALUE)) 611 | #define metamacro_if_eq_recursive12(VALUE) metamacro_if_eq_recursive11(metamacro_dec(VALUE)) 612 | #define metamacro_if_eq_recursive13(VALUE) metamacro_if_eq_recursive12(metamacro_dec(VALUE)) 613 | #define metamacro_if_eq_recursive14(VALUE) metamacro_if_eq_recursive13(metamacro_dec(VALUE)) 614 | #define metamacro_if_eq_recursive15(VALUE) metamacro_if_eq_recursive14(metamacro_dec(VALUE)) 615 | #define metamacro_if_eq_recursive16(VALUE) metamacro_if_eq_recursive15(metamacro_dec(VALUE)) 616 | #define metamacro_if_eq_recursive17(VALUE) metamacro_if_eq_recursive16(metamacro_dec(VALUE)) 617 | #define metamacro_if_eq_recursive18(VALUE) metamacro_if_eq_recursive17(metamacro_dec(VALUE)) 618 | #define metamacro_if_eq_recursive19(VALUE) metamacro_if_eq_recursive18(metamacro_dec(VALUE)) 619 | #define metamacro_if_eq_recursive20(VALUE) metamacro_if_eq_recursive19(metamacro_dec(VALUE)) 620 | 621 | // metamacro_take expansions 622 | #define metamacro_take0(...) 623 | #define metamacro_take1(...) metamacro_head(__VA_ARGS__) 624 | #define metamacro_take2(...) metamacro_head(__VA_ARGS__), metamacro_take1(metamacro_tail(__VA_ARGS__)) 625 | #define metamacro_take3(...) metamacro_head(__VA_ARGS__), metamacro_take2(metamacro_tail(__VA_ARGS__)) 626 | #define metamacro_take4(...) metamacro_head(__VA_ARGS__), metamacro_take3(metamacro_tail(__VA_ARGS__)) 627 | #define metamacro_take5(...) metamacro_head(__VA_ARGS__), metamacro_take4(metamacro_tail(__VA_ARGS__)) 628 | #define metamacro_take6(...) metamacro_head(__VA_ARGS__), metamacro_take5(metamacro_tail(__VA_ARGS__)) 629 | #define metamacro_take7(...) metamacro_head(__VA_ARGS__), metamacro_take6(metamacro_tail(__VA_ARGS__)) 630 | #define metamacro_take8(...) metamacro_head(__VA_ARGS__), metamacro_take7(metamacro_tail(__VA_ARGS__)) 631 | #define metamacro_take9(...) metamacro_head(__VA_ARGS__), metamacro_take8(metamacro_tail(__VA_ARGS__)) 632 | #define metamacro_take10(...) metamacro_head(__VA_ARGS__), metamacro_take9(metamacro_tail(__VA_ARGS__)) 633 | #define metamacro_take11(...) metamacro_head(__VA_ARGS__), metamacro_take10(metamacro_tail(__VA_ARGS__)) 634 | #define metamacro_take12(...) metamacro_head(__VA_ARGS__), metamacro_take11(metamacro_tail(__VA_ARGS__)) 635 | #define metamacro_take13(...) metamacro_head(__VA_ARGS__), metamacro_take12(metamacro_tail(__VA_ARGS__)) 636 | #define metamacro_take14(...) metamacro_head(__VA_ARGS__), metamacro_take13(metamacro_tail(__VA_ARGS__)) 637 | #define metamacro_take15(...) metamacro_head(__VA_ARGS__), metamacro_take14(metamacro_tail(__VA_ARGS__)) 638 | #define metamacro_take16(...) metamacro_head(__VA_ARGS__), metamacro_take15(metamacro_tail(__VA_ARGS__)) 639 | #define metamacro_take17(...) metamacro_head(__VA_ARGS__), metamacro_take16(metamacro_tail(__VA_ARGS__)) 640 | #define metamacro_take18(...) metamacro_head(__VA_ARGS__), metamacro_take17(metamacro_tail(__VA_ARGS__)) 641 | #define metamacro_take19(...) metamacro_head(__VA_ARGS__), metamacro_take18(metamacro_tail(__VA_ARGS__)) 642 | #define metamacro_take20(...) metamacro_head(__VA_ARGS__), metamacro_take19(metamacro_tail(__VA_ARGS__)) 643 | 644 | // metamacro_drop expansions 645 | #define metamacro_drop0(...) __VA_ARGS__ 646 | #define metamacro_drop1(...) metamacro_tail(__VA_ARGS__) 647 | #define metamacro_drop2(...) metamacro_drop1(metamacro_tail(__VA_ARGS__)) 648 | #define metamacro_drop3(...) metamacro_drop2(metamacro_tail(__VA_ARGS__)) 649 | #define metamacro_drop4(...) metamacro_drop3(metamacro_tail(__VA_ARGS__)) 650 | #define metamacro_drop5(...) metamacro_drop4(metamacro_tail(__VA_ARGS__)) 651 | #define metamacro_drop6(...) metamacro_drop5(metamacro_tail(__VA_ARGS__)) 652 | #define metamacro_drop7(...) metamacro_drop6(metamacro_tail(__VA_ARGS__)) 653 | #define metamacro_drop8(...) metamacro_drop7(metamacro_tail(__VA_ARGS__)) 654 | #define metamacro_drop9(...) metamacro_drop8(metamacro_tail(__VA_ARGS__)) 655 | #define metamacro_drop10(...) metamacro_drop9(metamacro_tail(__VA_ARGS__)) 656 | #define metamacro_drop11(...) metamacro_drop10(metamacro_tail(__VA_ARGS__)) 657 | #define metamacro_drop12(...) metamacro_drop11(metamacro_tail(__VA_ARGS__)) 658 | #define metamacro_drop13(...) metamacro_drop12(metamacro_tail(__VA_ARGS__)) 659 | #define metamacro_drop14(...) metamacro_drop13(metamacro_tail(__VA_ARGS__)) 660 | #define metamacro_drop15(...) metamacro_drop14(metamacro_tail(__VA_ARGS__)) 661 | #define metamacro_drop16(...) metamacro_drop15(metamacro_tail(__VA_ARGS__)) 662 | #define metamacro_drop17(...) metamacro_drop16(metamacro_tail(__VA_ARGS__)) 663 | #define metamacro_drop18(...) metamacro_drop17(metamacro_tail(__VA_ARGS__)) 664 | #define metamacro_drop19(...) metamacro_drop18(metamacro_tail(__VA_ARGS__)) 665 | #define metamacro_drop20(...) metamacro_drop19(metamacro_tail(__VA_ARGS__)) 666 | 667 | #endif 668 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Helio Martín 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # HMStackView 2 | 3 | Now you can insert UIViewControllers instead of UIViews to the stack. 4 | Modification of the great component [BSStackView](https://github.com/iBlacksus/BSStackView). 5 | 6 | Install manually by downloading the files from GitHub and then use 7 | ```ObjC 8 | #import "HMStackView.h" 9 | ``` 10 | 11 | ## Usage 12 | 13 | Add the below reference to the @interface method in the header file(.h) 14 | ```ObjC 15 | @property (nonatomic, strong) IBOutlet HMStackView *stackView; 16 | ``` 17 | 18 | Initialize the HMStackView in the Implementation File (.m) 19 | ```ObjC 20 | self.stackView.swipeDirections = UISwipeGestureRecognizerDirectionLeft | UISwipeGestureRecognizerDirectionRight | UISwipeGestureRecognizerDirectionUp | UISwipeGestureRecognizerDirectionDown; 21 | self.stackView.forwardDirections = UISwipeGestureRecognizerDirectionRight | UISwipeGestureRecognizerDirectionUp; 22 | self.stackView.backwardDirections = UISwipeGestureRecognizerDirectionLeft | UISwipeGestureRecognizerDirectionDown; 23 | self.stackView.changeAlphaOnSendAnimation = YES; 24 | [self.stackView configureWithViewControllers:viewControllers]; 25 | self.stackView.delegate = self; 26 | ``` 27 | 28 | Customize constraints 29 | ```ObjC 30 | self.stackView.contraintsConfigurator.top = 20.; 31 | self.stackView.contraintsConfigurator.bottom = 50.; 32 | self.stackView.contraintsConfigurator.leading = 10.; 33 | self.stackView.contraintsConfigurator.trailing = 10.; 34 | [self.stackView configureWithViewControllers:viewControllers]; 35 | ``` 36 | 37 | ## Requirements 38 | * iOS 8.0 or higher 39 | * ARC 40 | 41 | ## Author 42 | 43 | Helio Martín - helio.martin@icloud.com 44 | 45 | ## License 46 | 47 | HMStackView is available under the MIT license. See the LICENSE file for more info. 48 | --------------------------------------------------------------------------------