Authored by Jonas Budelmann

Merge pull request #55 from Ahti/master

add "make.attribute(...)"
@@ -9,6 +9,20 @@ @@ -9,6 +9,20 @@
9 #import "MASConstraint.h" 9 #import "MASConstraint.h"
10 #import "MASUtilities.h" 10 #import "MASUtilities.h"
11 11
  12 +typedef NS_OPTIONS(NSInteger, MASAttribute) {
  13 + MASAttributeLeft = 1 << NSLayoutAttributeLeft,
  14 + MASAttributeRight = 1 << NSLayoutAttributeRight,
  15 + MASAttributeTop = 1 << NSLayoutAttributeTop,
  16 + MASAttributeBottom = 1 << NSLayoutAttributeBottom,
  17 + MASAttributeLeading = 1 << NSLayoutAttributeLeading,
  18 + MASAttributeTrailing = 1 << NSLayoutAttributeTrailing,
  19 + MASAttributeWidth = 1 << NSLayoutAttributeWidth,
  20 + MASAttributeHeight = 1 << NSLayoutAttributeHeight,
  21 + MASAttributeCenterX = 1 << NSLayoutAttributeCenterX,
  22 + MASAttributeCenterY = 1 << NSLayoutAttributeCenterY,
  23 + MASAttributeBaseline = 1 << NSLayoutAttributeBaseline,
  24 +};
  25 +
12 /** 26 /**
13 * Provides factory methods for creating MASConstraints. 27 * Provides factory methods for creating MASConstraints.
14 * Constraints are collected until they are ready to be installed 28 * Constraints are collected until they are ready to be installed
@@ -33,6 +47,13 @@ @@ -33,6 +47,13 @@
33 @property (nonatomic, strong, readonly) MASConstraint *baseline; 47 @property (nonatomic, strong, readonly) MASConstraint *baseline;
34 48
35 /** 49 /**
  50 + * Returns a block which creates a new MASCompositeConstraint with the first item set
  51 + * to the makers associated view and children corresponding to the set bits in the
  52 + * MASAttribute parameter. Combine multiple attributes via binary-or.
  53 + */
  54 +@property (nonatomic, strong, readonly) MASConstraint *(^attributes)(MASAttribute attrs);
  55 +
  56 +/**
36 * Creates a MASCompositeConstraint with type MASCompositeConstraintTypeEdges 57 * Creates a MASCompositeConstraint with type MASCompositeConstraintTypeEdges
37 * which generates the appropriate MASViewConstraint children (top, left, bottom, right) 58 * which generates the appropriate MASViewConstraint children (top, left, bottom, right)
38 * with the first item set to the makers associated view 59 * with the first item set to the makers associated view
@@ -59,6 +59,37 @@ @@ -59,6 +59,37 @@
59 return constraint; 59 return constraint;
60 } 60 }
61 61
  62 +- (MASConstraint *)addConstraintWithAttributes:(MASAttribute)attrs {
  63 + MASAttribute anyAttribute = MASAttributeLeft | MASAttributeRight | MASAttributeTop | MASAttributeBottom | MASAttributeLeading | MASAttributeTrailing | MASAttributeWidth | MASAttributeHeight | MASAttributeCenterX | MASAttributeCenterY | MASAttributeBaseline;
  64 +
  65 + NSAssert((attrs & anyAttribute) != 0, @"You didn't pass any attribute to make.attributes(...)");
  66 +
  67 + NSMutableArray *attributes = [NSMutableArray array];
  68 +
  69 + if (attrs & MASAttributeLeft) [attributes addObject:self.view.mas_left];
  70 + if (attrs & MASAttributeRight) [attributes addObject:self.view.mas_right];
  71 + if (attrs & MASAttributeTop) [attributes addObject:self.view.mas_top];
  72 + if (attrs & MASAttributeBottom) [attributes addObject:self.view.mas_bottom];
  73 + if (attrs & MASAttributeLeading) [attributes addObject:self.view.mas_leading];
  74 + if (attrs & MASAttributeTrailing) [attributes addObject:self.view.mas_trailing];
  75 + if (attrs & MASAttributeWidth) [attributes addObject:self.view.mas_width];
  76 + if (attrs & MASAttributeHeight) [attributes addObject:self.view.mas_height];
  77 + if (attrs & MASAttributeCenterX) [attributes addObject:self.view.mas_centerX];
  78 + if (attrs & MASAttributeCenterY) [attributes addObject:self.view.mas_centerY];
  79 + if (attrs & MASAttributeBaseline) [attributes addObject:self.view.mas_baseline];
  80 +
  81 + NSMutableArray *children = [NSMutableArray arrayWithCapacity:attributes.count];
  82 +
  83 + for (MASViewAttribute *a in attributes) {
  84 + [children addObject:[[MASViewConstraint alloc] initWithFirstViewAttribute:a]];
  85 + }
  86 +
  87 + MASCompositeConstraint *constraint = [[MASCompositeConstraint alloc] initWithChildren:children];
  88 + constraint.delegate = self;
  89 + [self.constraints addObject:constraint];
  90 + return constraint;
  91 +}
  92 +
62 #pragma mark - standard Attributes 93 #pragma mark - standard Attributes
63 94
64 - (MASConstraint *)left { 95 - (MASConstraint *)left {
@@ -105,42 +136,25 @@ @@ -105,42 +136,25 @@
105 return [self addConstraintWithLayoutAttribute:NSLayoutAttributeBaseline]; 136 return [self addConstraintWithLayoutAttribute:NSLayoutAttributeBaseline];
106 } 137 }
107 138
  139 +- (MASConstraint *(^)(MASAttribute))attributes {
  140 + return ^(MASAttribute attrs){
  141 + return [self addConstraintWithAttributes:attrs];
  142 + };
  143 +}
  144 +
108 145
109 #pragma mark - composite Attributes 146 #pragma mark - composite Attributes
110 147
111 - (MASConstraint *)edges { 148 - (MASConstraint *)edges {
112 - NSArray *children = @[  
113 - [[MASViewConstraint alloc] initWithFirstViewAttribute:self.view.mas_top],  
114 - [[MASViewConstraint alloc] initWithFirstViewAttribute:self.view.mas_left],  
115 - [[MASViewConstraint alloc] initWithFirstViewAttribute:self.view.mas_bottom],  
116 - [[MASViewConstraint alloc] initWithFirstViewAttribute:self.view.mas_right]  
117 - ];  
118 - MASCompositeConstraint *constraint = [[MASCompositeConstraint alloc] initWithChildren:children];  
119 - constraint.delegate = self;  
120 - [self.constraints addObject:constraint];  
121 - return constraint; 149 + return [self addConstraintWithAttributes:MASAttributeTop | MASAttributeLeft | MASAttributeRight | MASAttributeBottom];
122 } 150 }
123 151
124 - (MASConstraint *)size { 152 - (MASConstraint *)size {
125 - NSArray *children = @[  
126 - [[MASViewConstraint alloc] initWithFirstViewAttribute:self.view.mas_width],  
127 - [[MASViewConstraint alloc] initWithFirstViewAttribute:self.view.mas_height]  
128 - ];  
129 - MASCompositeConstraint *constraint = [[MASCompositeConstraint alloc] initWithChildren:children];  
130 - constraint.delegate = self;  
131 - [self.constraints addObject:constraint];  
132 - return constraint; 153 + return [self addConstraintWithAttributes:MASAttributeWidth | MASAttributeHeight];
133 } 154 }
134 155
135 - (MASConstraint *)center { 156 - (MASConstraint *)center {
136 - NSArray *children = @[  
137 - [[MASViewConstraint alloc] initWithFirstViewAttribute:self.view.mas_centerX],  
138 - [[MASViewConstraint alloc] initWithFirstViewAttribute:self.view.mas_centerY]  
139 - ];  
140 - MASCompositeConstraint *constraint = [[MASCompositeConstraint alloc] initWithChildren:children];  
141 - constraint.delegate = self;  
142 - [self.constraints addObject:constraint];  
143 - return constraint; 157 + return [self addConstraintWithAttributes:MASAttributeCenterX | MASAttributeCenterY];
144 } 158 }
145 159
146 #pragma mark - grouping 160 #pragma mark - grouping
@@ -30,6 +30,7 @@ @@ -30,6 +30,7 @@
30 @property (nonatomic, strong, readonly) MASViewAttribute *mas_centerX; 30 @property (nonatomic, strong, readonly) MASViewAttribute *mas_centerX;
31 @property (nonatomic, strong, readonly) MASViewAttribute *mas_centerY; 31 @property (nonatomic, strong, readonly) MASViewAttribute *mas_centerY;
32 @property (nonatomic, strong, readonly) MASViewAttribute *mas_baseline; 32 @property (nonatomic, strong, readonly) MASViewAttribute *mas_baseline;
  33 +@property (nonatomic, strong, readonly) MASViewAttribute *(^mas_attribute)(NSLayoutAttribute attr);
33 34
34 /** 35 /**
35 * a key to associate with this view 36 * a key to associate with this view
@@ -72,6 +72,13 @@ @@ -72,6 +72,13 @@
72 return [[MASViewAttribute alloc] initWithView:self layoutAttribute:NSLayoutAttributeBaseline]; 72 return [[MASViewAttribute alloc] initWithView:self layoutAttribute:NSLayoutAttributeBaseline];
73 } 73 }
74 74
  75 +- (MASViewAttribute *(^)(NSLayoutAttribute))mas_attribute
  76 +{
  77 + return ^(NSLayoutAttribute attr) {
  78 + return [[MASViewAttribute alloc] initWithView:self layoutAttribute:attr];
  79 + };
  80 +}
  81 +
75 #pragma mark - associated properties 82 #pragma mark - associated properties
76 83
77 - (id)mas_key { 84 - (id)mas_key {
@@ -27,6 +27,7 @@ @@ -27,6 +27,7 @@
27 @property (nonatomic, strong, readonly) MASViewAttribute *centerX; 27 @property (nonatomic, strong, readonly) MASViewAttribute *centerX;
28 @property (nonatomic, strong, readonly) MASViewAttribute *centerY; 28 @property (nonatomic, strong, readonly) MASViewAttribute *centerY;
29 @property (nonatomic, strong, readonly) MASViewAttribute *baseline; 29 @property (nonatomic, strong, readonly) MASViewAttribute *baseline;
  30 +@property (nonatomic, strong, readonly) MASViewAttribute *(^attribute)(NSLayoutAttribute attr);
30 31
31 - (NSArray *)makeConstraints:(void(^)(MASConstraintMaker *make))block; 32 - (NSArray *)makeConstraints:(void(^)(MASConstraintMaker *make))block;
32 - (NSArray *)updateConstraints:(void(^)(MASConstraintMaker *make))block; 33 - (NSArray *)updateConstraints:(void(^)(MASConstraintMaker *make))block;
@@ -51,6 +52,7 @@ MAS_ATTR_FORWARD(height); @@ -51,6 +52,7 @@ MAS_ATTR_FORWARD(height);
51 MAS_ATTR_FORWARD(centerX); 52 MAS_ATTR_FORWARD(centerX);
52 MAS_ATTR_FORWARD(centerY); 53 MAS_ATTR_FORWARD(centerY);
53 MAS_ATTR_FORWARD(baseline); 54 MAS_ATTR_FORWARD(baseline);
  55 +MAS_ATTR_FORWARD(attribute);
54 56
55 - (NSArray *)makeConstraints:(void(^)(MASConstraintMaker *))block { 57 - (NSArray *)makeConstraints:(void(^)(MASConstraintMaker *))block {
56 return [self mas_makeConstraints:block]; 58 return [self mas_makeConstraints:block];
@@ -39,6 +39,31 @@ SpecBegin(MASConstraintMaker) { @@ -39,6 +39,31 @@ SpecBegin(MASConstraintMaker) {
39 maker = [[MASConstraintMaker alloc] initWithView:view]; 39 maker = [[MASConstraintMaker alloc] initWithView:view];
40 } 40 }
41 41
  42 +- (void)testCreateSingleAttribute {
  43 + composite = (MASCompositeConstraint *)maker.attributes(MASAttributeHeight);
  44 +
  45 + expect(composite.childConstraints).to.haveCountOf(1);
  46 +
  47 + MASViewConstraint *viewConstraint = composite.childConstraints[0];
  48 + expect(viewConstraint.firstViewAttribute.view).to.beIdenticalTo(maker.view);
  49 + expect(viewConstraint.firstViewAttribute.layoutAttribute).to.equal(NSLayoutAttributeHeight);
  50 +}
  51 +
  52 +- (void)testCreateAttributes {
  53 + composite = (MASCompositeConstraint *)maker.attributes(MASAttributeCenterX | MASAttributeWidth);
  54 +
  55 + expect(composite.childConstraints).to.haveCountOf(2);
  56 +
  57 + // children are ordered like MASAttribute, so the first is width
  58 + MASViewConstraint *viewConstraint = composite.childConstraints[0];
  59 + expect(viewConstraint.firstViewAttribute.view).to.beIdenticalTo(maker.view);
  60 + expect(viewConstraint.firstViewAttribute.layoutAttribute).to.equal(NSLayoutAttributeWidth);
  61 +
  62 + viewConstraint = composite.childConstraints[1];
  63 + expect(viewConstraint.firstViewAttribute.view).to.beIdenticalTo(maker.view);
  64 + expect(viewConstraint.firstViewAttribute.layoutAttribute).to.equal(NSLayoutAttributeCenterX);
  65 +}
  66 +
42 - (void)testCreateCenterYAndCenterXChildren { 67 - (void)testCreateCenterYAndCenterXChildren {
43 composite = (MASCompositeConstraint *)maker.center; 68 composite = (MASCompositeConstraint *)maker.center;
44 69
@@ -60,25 +85,27 @@ SpecBegin(MASConstraintMaker) { @@ -60,25 +85,27 @@ SpecBegin(MASConstraintMaker) {
60 85
61 expect(composite.childConstraints).to.haveCountOf(4); 86 expect(composite.childConstraints).to.haveCountOf(4);
62 87
63 - //top  
64 - MASViewConstraint *viewConstraint = composite.childConstraints[0];  
65 - expect(viewConstraint.firstViewAttribute.view).to.beIdenticalTo(maker.view);  
66 - expect(viewConstraint.firstViewAttribute.layoutAttribute).to.equal(NSLayoutAttributeTop);  
67 - 88 + MASViewConstraint *viewConstraint;
  89 +
68 //left 90 //left
69 - viewConstraint = composite.childConstraints[1]; 91 + viewConstraint = composite.childConstraints[0];
70 expect(viewConstraint.firstViewAttribute.view).to.beIdenticalTo(maker.view); 92 expect(viewConstraint.firstViewAttribute.view).to.beIdenticalTo(maker.view);
71 expect(viewConstraint.firstViewAttribute.layoutAttribute).to.equal(NSLayoutAttributeLeft); 93 expect(viewConstraint.firstViewAttribute.layoutAttribute).to.equal(NSLayoutAttributeLeft);
72 -  
73 - //bottom 94 +
  95 + //right
  96 + viewConstraint = composite.childConstraints[1];
  97 + expect(viewConstraint.firstViewAttribute.view).to.beIdenticalTo(maker.view);
  98 + expect(viewConstraint.firstViewAttribute.layoutAttribute).to.equal(NSLayoutAttributeRight);
  99 +
  100 + //top
74 viewConstraint = composite.childConstraints[2]; 101 viewConstraint = composite.childConstraints[2];
75 expect(viewConstraint.firstViewAttribute.view).to.beIdenticalTo(maker.view); 102 expect(viewConstraint.firstViewAttribute.view).to.beIdenticalTo(maker.view);
76 - expect(viewConstraint.firstViewAttribute.layoutAttribute).to.equal(NSLayoutAttributeBottom); 103 + expect(viewConstraint.firstViewAttribute.layoutAttribute).to.equal(NSLayoutAttributeTop);
77 104
78 - //right 105 + //bottom
79 viewConstraint = composite.childConstraints[3]; 106 viewConstraint = composite.childConstraints[3];
80 expect(viewConstraint.firstViewAttribute.view).to.beIdenticalTo(maker.view); 107 expect(viewConstraint.firstViewAttribute.view).to.beIdenticalTo(maker.view);
81 - expect(viewConstraint.firstViewAttribute.layoutAttribute).to.equal(NSLayoutAttributeRight); 108 + expect(viewConstraint.firstViewAttribute.layoutAttribute).to.equal(NSLayoutAttributeBottom);
82 } 109 }
83 110
84 - (void)testCreateWidthAndHeightChildren { 111 - (void)testCreateWidthAndHeightChildren {