bm-core-ui 2.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +1624 -0
- package/LICENSE +21 -0
- package/README.md +145 -0
- package/build/@types/index.d.ts +14078 -0
- package/build/BMCodeEditor/BMCodeEditor.js +707 -0
- package/build/BMCollectionView/BMCollectionView.js +5861 -0
- package/build/BMCollectionView/BMCollectionViewCell.js +688 -0
- package/build/BMCollectionView/BMCollectionViewFlowLayout.js +4467 -0
- package/build/BMCollectionView/BMCollectionViewLayout.js +830 -0
- package/build/BMCollectionView/BMCollectionViewLayoutAttributes.js +673 -0
- package/build/BMCollectionView/BMCollectionViewMasonryLayout.js +491 -0
- package/build/BMCollectionView/BMCollectionViewStackLayout.js +634 -0
- package/build/BMCollectionView/BMCollectionViewTileLayout.js +1121 -0
- package/build/BMCoreUI.css +2833 -0
- package/build/BMView/BMAttributedLabelView.js +310 -0
- package/build/BMView/BMLayoutConstraint_v2.5.js +1813 -0
- package/build/BMView/BMLayoutGuide.js +192 -0
- package/build/BMView/BMLayoutSizeClass.js +466 -0
- package/build/BMView/BMMenu.js +574 -0
- package/build/BMView/BMScrollView.js +247 -0
- package/build/BMView/BMTextField.js +512 -0
- package/build/BMView/BMTextFieldDelegate.js +71 -0
- package/build/BMView/BMView_v2.5.js +3572 -0
- package/build/BMView/BMViewport.js +221 -0
- package/build/BMViewLayoutEditor/BMLayoutEditor.js +6117 -0
- package/build/BMViewLayoutEditor/BMLayoutEditorConstraintSettings.js +417 -0
- package/build/BMViewLayoutEditor/BMLayoutEditorDelegate.js +59 -0
- package/build/BMViewLayoutEditor/BMLayoutEditorSettingCells.js +1653 -0
- package/build/BMViewLayoutEditor/BMLayoutEditorSettings.js +1480 -0
- package/build/BMViewLayoutEditor/BMLayoutEditorSettingsComplexCells.js +431 -0
- package/build/BMViewLayoutEditor/BMLayoutEditorSettingsDelegate.js +46 -0
- package/build/BMViewLayoutEditor/BMLayoutEditorVariablesController.js +460 -0
- package/build/BMViewLayoutEditor/BMLayoutEditorViewGroupSettings.js +293 -0
- package/build/BMViewLayoutEditor/BMLayoutEditorViewSettings.js +382 -0
- package/build/BMViewLayoutEditor/BMLayoutVariableProvider.js +202 -0
- package/build/BMWindow/BMConfirmationPopup.js +477 -0
- package/build/BMWindow/BMKeyboardShortcut.js +151 -0
- package/build/BMWindow/BMPopover/BMPopover.js +492 -0
- package/build/BMWindow/BMToolWindow.js +71 -0
- package/build/BMWindow/BMWindow.js +2000 -0
- package/build/Core/BMAnimationContext.js +1181 -0
- package/build/Core/BMColor.js +991 -0
- package/build/Core/BMCoreUI.js +470 -0
- package/build/Core/BMFunctionCollection.js +110 -0
- package/build/Core/BMIndexPath.js +165 -0
- package/build/Core/BMInset.js +138 -0
- package/build/Core/BMKeyPath.js +100 -0
- package/build/Core/BMPoint.js +291 -0
- package/build/Core/BMRect.js +556 -0
- package/build/Core/BMSize.js +137 -0
- package/build/iScroll/LICENSE +22 -0
- package/build/iScroll/iscroll-probe.js +2154 -0
- package/build/images/AlignBottom.png +0 -0
- package/build/images/AlignCenterX.png +0 -0
- package/build/images/AlignCenterY.png +0 -0
- package/build/images/AlignLeading.png +0 -0
- package/build/images/AlignTop.png +0 -0
- package/build/images/AlignTrailing.png +0 -0
- package/build/images/AllConstraints.png +0 -0
- package/build/images/BottomConstraint.png +0 -0
- package/build/images/CenterXConstraint.png +0 -0
- package/build/images/CenterYConstraint.png +0 -0
- package/build/images/CoreUI2.png +0 -0
- package/build/images/CoreUI2@2x.png +0 -0
- package/build/images/Desktop.png +0 -0
- package/build/images/DesktopMini.png +0 -0
- package/build/images/EqualHeight.png +0 -0
- package/build/images/EqualHorizontalSpacing.png +0 -0
- package/build/images/EqualHorizontalSpacingInSuperview.png +0 -0
- package/build/images/EqualVerticalSpacing.png +0 -0
- package/build/images/EqualVerticalSpacingInSuperview.png +0 -0
- package/build/images/EqualWidth.png +0 -0
- package/build/images/HeightConstraint.png +0 -0
- package/build/images/InactiveConstraints.png +0 -0
- package/build/images/Layout.png +0 -0
- package/build/images/LayoutVariables.png +0 -0
- package/build/images/LeftConstraint.png +0 -0
- package/build/images/OwnConstraints.png +0 -0
- package/build/images/Phone.png +0 -0
- package/build/images/PhoneLandscape.png +0 -0
- package/build/images/PhoneLandscapeMini.png +0 -0
- package/build/images/PhoneMini.png +0 -0
- package/build/images/PhonePortrait.png +0 -0
- package/build/images/PhonePortraitMini.png +0 -0
- package/build/images/Properties.png +0 -0
- package/build/images/RightConstraint.png +0 -0
- package/build/images/SubviewConstraints.png +0 -0
- package/build/images/Tablet.png +0 -0
- package/build/images/TabletLandscape.png +0 -0
- package/build/images/TabletLandscapeMini.png +0 -0
- package/build/images/TabletMini.png +0 -0
- package/build/images/TabletPortrait.png +0 -0
- package/build/images/TabletPortraitMini.png +0 -0
- package/build/images/TopConstraint.png +0 -0
- package/build/images/WidthConstraint.png +0 -0
- package/build/index.js +40 -0
- package/lib/@types/BMCoreUI.min.d.ts +14078 -0
- package/lib/BMCoreUI.min.js +1 -0
- package/package.json +58 -0
|
@@ -0,0 +1,1813 @@
|
|
|
1
|
+
// @ts-check
|
|
2
|
+
|
|
3
|
+
import {YES, NO, BMExtend, BMCopyProperties, BMUUIDMake} from '../Core/BMCoreUI'
|
|
4
|
+
import {BMLayoutSizeClass} from './BMLayoutSizeClass'
|
|
5
|
+
import * as kiwi from 'kiwi.js'
|
|
6
|
+
|
|
7
|
+
// @type BMLayoutAttribute
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Constants representing the layout attributes used by the CoreUI layout engine.
|
|
11
|
+
*/
|
|
12
|
+
export var BMLayoutAttribute = Object.freeze({ // <enum>
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* The attribute corresponding to a view's leading edge.
|
|
16
|
+
* This is the same as the left edge in a left-to-right layout and
|
|
17
|
+
* the same as the right edge in a right-to-left layout.
|
|
18
|
+
*/
|
|
19
|
+
Leading: 'Leading', // <enum>
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* The attribute corresponding to a view's trailing edge.
|
|
24
|
+
* This is the same as the right edge in a left-to-right layout and
|
|
25
|
+
* the same as the left edge in a right-to-left layout.
|
|
26
|
+
*/
|
|
27
|
+
Trailing: 'Trailing', // <enum>
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* The attribute corresponding to a view's left edge.
|
|
32
|
+
*/
|
|
33
|
+
Left: 'Left', // <enum>
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* The attribute corresponding to a view's right edge.
|
|
38
|
+
*/
|
|
39
|
+
Right: 'Right', // <enum>
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* The attribute corresponding to a view's top edge.
|
|
44
|
+
*/
|
|
45
|
+
Top: 'Top', // <enum>
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* The attribute corresponding to a view's bottom edge.
|
|
50
|
+
*/
|
|
51
|
+
Bottom: 'Bottom', // <enum>
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* The attribute corresponding to a view's horizontal center.
|
|
56
|
+
*/
|
|
57
|
+
CenterX: 'CenterX', // <enum>
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* The attribute corresponding to a view's vertical center.
|
|
62
|
+
*/
|
|
63
|
+
CenterY: 'CenterY', // <enum>
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* The attribute corresponding to a view's width.
|
|
68
|
+
*/
|
|
69
|
+
Width: 'Width', // <enum>
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* The attribute corresponding to a view's height.
|
|
74
|
+
*/
|
|
75
|
+
Height: 'Height', // <enum>
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* The attribute corresponding to a view's aspect ratio.
|
|
80
|
+
*/
|
|
81
|
+
AspectRatio: 'AspectRatio' // <enum>
|
|
82
|
+
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
// @endtype
|
|
86
|
+
|
|
87
|
+
// @type BMLayoutConstraintRelation
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* Constants that describe the equality or inequality relation between the two sides of a constraint.
|
|
91
|
+
*/
|
|
92
|
+
export var BMLayoutConstraintRelation = Object.freeze({ // <enum>
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* Indicates that the two sides of the constraint's equation should be equal.
|
|
97
|
+
*/
|
|
98
|
+
Equals: kiwi.Operator.Eq, // <enum>
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* Indicates that the source view's attribute's value should be less than the right-hand side expression's value.
|
|
103
|
+
*/
|
|
104
|
+
LessThanOrEquals: kiwi.Operator.Le, // <enum>
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* Indicates that the source view's attribute's value should be greater than the right-hand side expression's value.
|
|
109
|
+
*/
|
|
110
|
+
GreaterThanOrEquals: kiwi.Operator.Ge, // <enum>
|
|
111
|
+
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
// @endtype
|
|
115
|
+
|
|
116
|
+
// @type BMLayoutConstraintKind
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* Constants that describe what type of view attribute a layout constraint affects.
|
|
120
|
+
*/
|
|
121
|
+
export var BMLayoutConstraintKind = Object.freeze({ // <enum>
|
|
122
|
+
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* Indicates that this constraint affects a horizontal attribute.
|
|
126
|
+
*/
|
|
127
|
+
Horizontal: 'BMLayoutConstraintKindHorizontal', // <enum>
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* Indicates that this constraint affects a vertical attribute.
|
|
132
|
+
*/
|
|
133
|
+
Vertical: 'BMLayoutConstraintKindVertical', // <enum>
|
|
134
|
+
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* Indicates that this constraint affects the aspect ratio.
|
|
138
|
+
*/
|
|
139
|
+
AspectRatio: 'BMLayoutConstraintKindAspectRatio', // <enum>
|
|
140
|
+
|
|
141
|
+
});
|
|
142
|
+
|
|
143
|
+
// @endtype
|
|
144
|
+
|
|
145
|
+
const _BMLayoutConstraintClasses = {BMLayoutConstraint, BMEqualAttributeLayoutConstraint, BMEqualSpacingLayoutConstraint}
|
|
146
|
+
|
|
147
|
+
// @type BMLayoutConstraint
|
|
148
|
+
|
|
149
|
+
/**
|
|
150
|
+
* A layout constraint is a mathematical equality or inequality between two layout attributes on a view.
|
|
151
|
+
*
|
|
152
|
+
* They are used as rules by the CoreUI layout engine to lay out views.
|
|
153
|
+
*
|
|
154
|
+
* A constraint is a linear equation that takes the form of
|
|
155
|
+
* ```js
|
|
156
|
+
view1.attribute1 = multiplier * view2.attribute2 + constant
|
|
157
|
+
```
|
|
158
|
+
* where the equals sign can be replaced with an inequality sign as needed.
|
|
159
|
+
* Note that despite looking like an assignment statement, the constraint expression is a mathematical equation and the layout
|
|
160
|
+
* system may choose to modify either side (or even both) of the equation to fulfill the constraint's requirements.
|
|
161
|
+
*
|
|
162
|
+
* There are four types of layout constraints: vertical position, horizontal position, width and height.
|
|
163
|
+
* Each of them controls a specific aspect of a view's layout. A view must have constraints which clearly define all four of those
|
|
164
|
+
* attributes for the layout system to be able to size it and position it correctly.
|
|
165
|
+
* Additionally, constraints having an attribute of a type on the left hand side of the equation can only have an attribute of the same type on the right hand side.
|
|
166
|
+
* In other words, for example, a view's vertical positioning can only depend on the vertical positioning of another view and not on its horizontal positioning or its size.
|
|
167
|
+
* For views that have intrinsic sizes, the sizing constraints are optional as the intrinsic sizes of the views will be used by default as size constraint inequalities.
|
|
168
|
+
* In addition, it is also possible to specify a constraint for a view's aspect ratio by linking its width to its own height.
|
|
169
|
+
* Similarly, it is also possible to specify a constraint that makes a view's aspect ratio depend upon the aspect ratio of another view.
|
|
170
|
+
* When creating an aspect ratio constraint, this may only be to another view's aspect ratio.
|
|
171
|
+
*
|
|
172
|
+
* Constraints may also have a priority value assigned to them. All constraints with a priority value lower than <code>BMLayoutConstraintPriorityRequired</code> are considered
|
|
173
|
+
* optional. The layout system will try to fulfill them, but it does not guarantee that it will do so and optional constraints may be ignored if it is needed to do so to fulfill
|
|
174
|
+
* the required constraints. When an optional constraint cannot be fulfilled, the layout system may nevertheless attempt to change the values of the attributes so that they are
|
|
175
|
+
* as close as possible to fulfill the optional constraint without breaking the required constraints.
|
|
176
|
+
*/
|
|
177
|
+
export function BMLayoutConstraint() {} // <constructor>
|
|
178
|
+
|
|
179
|
+
/**
|
|
180
|
+
* The priority value indicating that the constraint is required to be fulfilled.
|
|
181
|
+
*/
|
|
182
|
+
export var BMLayoutConstraintPriorityRequired = 1000; // <Number>
|
|
183
|
+
|
|
184
|
+
/**
|
|
185
|
+
* Constructs and returns an internal layout constraint initialized with the given values.
|
|
186
|
+
* The constraint will be marked inactive by default. Internal constraints are marked automatically as active
|
|
187
|
+
* by CoreUI when needed.
|
|
188
|
+
* @param view <BMView> The source view.
|
|
189
|
+
* {
|
|
190
|
+
* @param attribute <BMLayoutAttribute> The source view's attribute.
|
|
191
|
+
* @param relatedBy <BMLayoutConstraintRelation, nullable> Defaults to .Equals. The equation's equality or inequality sign.
|
|
192
|
+
* @param toView <BMView, nullable> The view to which the source view's attribute is related.
|
|
193
|
+
* If omitted, the constraint will cause the view's attribute to be
|
|
194
|
+
* solely related to the equation's constant component.
|
|
195
|
+
* @param secondAttribute <BMLayoutAttribute, nullable> The second view's attribute. May only be omitted if the second view is also omitted.
|
|
196
|
+
* @param multiplier <Number, nullable> Defaults to 1. The equation's multiplier.
|
|
197
|
+
* @param constant <Number, nullable> Defaults to 0. The equation's constant component.
|
|
198
|
+
* @param priority <Number, nullable> Defaults to </code>BMLayoutConstraintPriorityRequired</code>.
|
|
199
|
+
* The constraint's priority.
|
|
200
|
+
* }
|
|
201
|
+
*/
|
|
202
|
+
BMLayoutConstraint.internalConstraintWithView = function (view, args) {
|
|
203
|
+
args._internal = YES;
|
|
204
|
+
let constraint = BMLayoutConstraint.constraintWithView(view, args);
|
|
205
|
+
return constraint;
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
/**
|
|
209
|
+
* Constructs and returns a layout constraint initialized with the given values.
|
|
210
|
+
* The constraint will be marked inactive by default. You must set the constraint's
|
|
211
|
+
* <code>isActive</code> property to <code>YES</code> to make this constraint take part in layout calculations.
|
|
212
|
+
* @param view <BMView> The source view.
|
|
213
|
+
* {
|
|
214
|
+
* @param attribute <BMLayoutAttribute> The source view's attribute.
|
|
215
|
+
* @param relatedBy <BMLayoutConstraintRelation, nullable> Defaults to .Equals. The equation's equality or inequality sign.
|
|
216
|
+
* @param toView <BMView, nullable> The view to which the source view's attribute is related.
|
|
217
|
+
* If omitted, the constraint will cause the view's attribute to be
|
|
218
|
+
* solely related to the equation's constant component.
|
|
219
|
+
* @param secondAttribute <BMLayoutAttribute, nullable> The second view's attribute. May only be omitted if the second view is also omitted.
|
|
220
|
+
* @param multiplier <Number, nullable> Defaults to 1. The equation's multiplier.
|
|
221
|
+
* @param constant <Number or String, nullable> Defaults to 0. The equation's constant component.
|
|
222
|
+
* @param priority <Number, nullable> Defaults to </code>BMLayoutConstraintPriorityRequired</code>.
|
|
223
|
+
* The constraint's priority.
|
|
224
|
+
* }
|
|
225
|
+
* @return <BMLayoutConstraint> A layout constraint.
|
|
226
|
+
*/
|
|
227
|
+
BMLayoutConstraint.constraintWithView = function (view, args) {
|
|
228
|
+
var constraint = new BMLayoutConstraint();
|
|
229
|
+
|
|
230
|
+
constraint._identifier = BMUUIDMake();
|
|
231
|
+
|
|
232
|
+
constraint._sourceView = view;
|
|
233
|
+
constraint._sourceViewAttribute = args.attribute;
|
|
234
|
+
|
|
235
|
+
constraint._relation = args.relatedBy === undefined ? BMLayoutConstraintRelation.Equals : args.relatedBy;
|
|
236
|
+
|
|
237
|
+
constraint._targetView = args.toView;
|
|
238
|
+
constraint._targetViewAttribute = args.secondAttribute;
|
|
239
|
+
|
|
240
|
+
constraint._multiplier = isNaN(args.multiplier) ? 1 : args.multiplier;
|
|
241
|
+
constraint._constant = args.constant || 0;
|
|
242
|
+
|
|
243
|
+
if (args.priority) {
|
|
244
|
+
constraint._priority = args.priority;
|
|
245
|
+
}
|
|
246
|
+
else {
|
|
247
|
+
constraint._priority = BMLayoutConstraintPriorityRequired;
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
if (args.attribute === BMLayoutAttribute.AspectRatio) {
|
|
251
|
+
constraint._kind = BMLayoutConstraintKind.AspectRatio;
|
|
252
|
+
}
|
|
253
|
+
else if (args.attribute === BMLayoutAttribute.Top || args.attribute == BMLayoutAttribute.Bottom || args.attribute === BMLayoutAttribute.Height || args.attribute === BMLayoutAttribute.CenterY) {
|
|
254
|
+
constraint._kind = BMLayoutConstraintKind.Vertical;
|
|
255
|
+
}
|
|
256
|
+
else {
|
|
257
|
+
constraint._kind = BMLayoutConstraintKind.Horizontal;
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
constraint._variations = {};
|
|
261
|
+
constraint._configuration = {constant: constraint._constant, priority: constraint._priority, isActive: constraint._isActive};
|
|
262
|
+
if (typeof constraint._constant == 'string') {
|
|
263
|
+
constraint._configuration.constantValue = view.rootView.valueForLayoutVariable(constraint._constant);
|
|
264
|
+
}
|
|
265
|
+
else {
|
|
266
|
+
constraint._configuration.constantValue = constraint._constant;
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
|
|
270
|
+
// When creating temporary internal constraints, they should not be added to the views
|
|
271
|
+
if (!args._internal) {
|
|
272
|
+
constraint._install();
|
|
273
|
+
}
|
|
274
|
+
else {
|
|
275
|
+
constraint._internal = YES;
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
return constraint;
|
|
279
|
+
|
|
280
|
+
};
|
|
281
|
+
|
|
282
|
+
|
|
283
|
+
/**
|
|
284
|
+
* Creates and returns a constraint with the values of the given serialized constraint.
|
|
285
|
+
* @param constraint <AnyObject> The serialized constraint.
|
|
286
|
+
* {
|
|
287
|
+
* @param viewIDs <BMView ^(String)> A block that is invoked for each view ID affected by the constraint.
|
|
288
|
+
* The block is given a String ID and is expected to return the corresponding
|
|
289
|
+
* view instance.
|
|
290
|
+
* }
|
|
291
|
+
* @return <BMLayoutConstraint, nullable> The constraint, or `undefined` if the constraint could not be deserialized.
|
|
292
|
+
*/
|
|
293
|
+
BMLayoutConstraint.constraintWithSerializedConstraint = function (constraint, args) {
|
|
294
|
+
return Object.create(_BMLayoutConstraintClasses[constraint._class || 'BMLayoutConstraint'].prototype).initWithSerializedConstraint(constraint, args);
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
BMLayoutConstraint.prototype = {
|
|
298
|
+
|
|
299
|
+
/**
|
|
300
|
+
* A unique identifier assigned to this constraint. A random identifier is generated by CoreUI whenever a constraint
|
|
301
|
+
* is created, but the value of this property is not currently not used by CoreUI and can be freely modified after
|
|
302
|
+
* the constraint has been created.
|
|
303
|
+
*
|
|
304
|
+
* The identifier can be used to quickly obtain a reference to a specific constraint from its view hierarchy via the
|
|
305
|
+
* `constraintWithIdentifier(_)` method on views.
|
|
306
|
+
*/
|
|
307
|
+
_identifier: undefined, // <String>
|
|
308
|
+
get identifier() { return this._identifier },
|
|
309
|
+
set identifier(identifier) {
|
|
310
|
+
this._identifier = identifier;
|
|
311
|
+
},
|
|
312
|
+
|
|
313
|
+
/**
|
|
314
|
+
* The Cassowary solver to which this layout constraint has been attached.
|
|
315
|
+
*/
|
|
316
|
+
_solver: undefined, // <kiwi.Solver>
|
|
317
|
+
|
|
318
|
+
/**
|
|
319
|
+
* The Cassowary constraint represented by this layout constraint.
|
|
320
|
+
*/
|
|
321
|
+
_constraint: undefined, // <kiwi.Constraint>
|
|
322
|
+
|
|
323
|
+
/**
|
|
324
|
+
* Initializes this constraint with the values of the given serialized constraint.
|
|
325
|
+
* @param constraint <AnyObject> The serialized constraint.
|
|
326
|
+
* {
|
|
327
|
+
* @param viewIDs <BMView ^(String)> A block that is invoked for each view ID affected by the constraint.
|
|
328
|
+
* The block is given a String ID and is expected to return the corresponding
|
|
329
|
+
* view instance.
|
|
330
|
+
* }
|
|
331
|
+
* @return <BMLayoutConstraint, nullable> This constraint, or `undefined` if the constraint could not be deserialized.
|
|
332
|
+
*/
|
|
333
|
+
initWithSerializedConstraint(constraint, args) {
|
|
334
|
+
this._sourceViewAttribute = constraint._sourceViewAttribute;
|
|
335
|
+
this._relation = constraint._relation;
|
|
336
|
+
this._targetViewAttribute = constraint._targetViewAttribute;
|
|
337
|
+
this._multiplier = constraint._multiplier;
|
|
338
|
+
this._constant = constraint._constant;
|
|
339
|
+
this._kind = constraint._kind;
|
|
340
|
+
this._priority = constraint._priority;
|
|
341
|
+
this._sourceView = args.viewIDs(constraint._sourceView);
|
|
342
|
+
this._identifier = constraint._identifier || BMUUIDMake();
|
|
343
|
+
|
|
344
|
+
this._isActive = (constraint._isActive === undefined) ? YES : constraint._isActive;
|
|
345
|
+
|
|
346
|
+
if (!this._sourceView) return undefined;
|
|
347
|
+
if (constraint._targetView) {
|
|
348
|
+
this._targetView = args.viewIDs(constraint._targetView);
|
|
349
|
+
if (!this._targetView) return undefined;
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
// For variations, it is required to re-create the size class object references from their hash strings
|
|
353
|
+
this._variations = constraint._variations || {};
|
|
354
|
+
for (let key in this._variations) {
|
|
355
|
+
this._variations[key].sizeClass = BMLayoutSizeClass._layoutSizeClassForHashString(key);
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
// Create the configuration
|
|
359
|
+
this._configuration = {constant: constraint._constant, priority: constraint._priority, isActive: constraint._isActive};
|
|
360
|
+
this._updateConfiguration();
|
|
361
|
+
|
|
362
|
+
this._install();
|
|
363
|
+
|
|
364
|
+
return this;
|
|
365
|
+
},
|
|
366
|
+
|
|
367
|
+
/**
|
|
368
|
+
* Returns an array containing the attributes that this constraint affects
|
|
369
|
+
* for the given view. If this constraint does not affect that view, an empty
|
|
370
|
+
* array will be returned.
|
|
371
|
+
* @param view <BMView> The view.
|
|
372
|
+
* @return <[BMLayoutAttribute]> The list off affected attributes.
|
|
373
|
+
*/
|
|
374
|
+
affectedAttributesForView(view) {
|
|
375
|
+
let attributes = [];
|
|
376
|
+
|
|
377
|
+
if (view == this._sourceView) return [this._sourceViewAttribute];
|
|
378
|
+
if (view == this._targetView) return [this._targetViewAttribute];
|
|
379
|
+
|
|
380
|
+
return attributes;
|
|
381
|
+
},
|
|
382
|
+
|
|
383
|
+
/**
|
|
384
|
+
* Returns <code>YES</code> if this constraint represents a constraint collection.
|
|
385
|
+
*/
|
|
386
|
+
get isConstraintCollection() {
|
|
387
|
+
return NO;
|
|
388
|
+
},
|
|
389
|
+
|
|
390
|
+
/**
|
|
391
|
+
* Returns an array of primitive constraints that make up this constraint.
|
|
392
|
+
* For primitive constraints, this will return an array containing only this constraint.
|
|
393
|
+
*/
|
|
394
|
+
get constituentConstraints() {
|
|
395
|
+
return [this];
|
|
396
|
+
},
|
|
397
|
+
|
|
398
|
+
/**
|
|
399
|
+
* Used by the CoreUI layout editor to determine if the constant for this constraint may be modified.
|
|
400
|
+
* For primitive constraints this is always `YES`.
|
|
401
|
+
*/
|
|
402
|
+
get _hasEditableConstant() {
|
|
403
|
+
return YES;
|
|
404
|
+
},
|
|
405
|
+
|
|
406
|
+
/**
|
|
407
|
+
* The source view, on the left hand side of the equation.
|
|
408
|
+
*/
|
|
409
|
+
_sourceView: undefined, // <BMView>
|
|
410
|
+
|
|
411
|
+
/**
|
|
412
|
+
* The source view's attribute involved in the equation.
|
|
413
|
+
*/
|
|
414
|
+
_sourceViewAttribute: undefined, // <BMLayoutAttribute>
|
|
415
|
+
|
|
416
|
+
/**
|
|
417
|
+
* The target view, on the right hand side of the equation.
|
|
418
|
+
* If this property is not specified, this will be interpreted as a constant constraint.
|
|
419
|
+
*/
|
|
420
|
+
_targetView: undefined, // <BMView, nullable>
|
|
421
|
+
|
|
422
|
+
/**
|
|
423
|
+
* The target view's attribute involved in the equation.
|
|
424
|
+
* This property must be specified if <code>targetView</code> is also specified.
|
|
425
|
+
*/
|
|
426
|
+
_targetViewAttribute: undefined, // <BMLayoutAttribute, nullable>
|
|
427
|
+
|
|
428
|
+
/**
|
|
429
|
+
* The equation's multiplier component.
|
|
430
|
+
*/
|
|
431
|
+
_multiplier: 1, // <Number>
|
|
432
|
+
|
|
433
|
+
/**
|
|
434
|
+
* An object that describes the active configuration for the properties that can vary
|
|
435
|
+
* based on size classes for this layout constraint.
|
|
436
|
+
*/
|
|
437
|
+
_configuration: undefined, // <Object>
|
|
438
|
+
|
|
439
|
+
/**
|
|
440
|
+
* Invoked by CoreUI when the active size classes change for the view hierarchy
|
|
441
|
+
* to which this constraint belongs. This causes the constraint to update its configuration
|
|
442
|
+
* to match the new size classes, based on its variations.
|
|
443
|
+
* @param sizeClasses <[BMLayoutSizeClass]> The active size classes.
|
|
444
|
+
*/
|
|
445
|
+
activeSizeClassesDidChange(sizeClasses) {
|
|
446
|
+
this._updateConfiguration();
|
|
447
|
+
},
|
|
448
|
+
|
|
449
|
+
/**
|
|
450
|
+
* Invoked by CoreUI when the value of any layout variable changes for the view hierarchy to which this contraint
|
|
451
|
+
* belongs. If this constraint uses a layout variable as its constant value, it will update the value of its constant accordingly.
|
|
452
|
+
*/
|
|
453
|
+
layoutVariablesDidChange() {
|
|
454
|
+
if (typeof this._configuration.constant == 'string') {
|
|
455
|
+
this._updateConfiguration();
|
|
456
|
+
}
|
|
457
|
+
},
|
|
458
|
+
|
|
459
|
+
/**
|
|
460
|
+
* Invoked by CoreUI whenever size classes are invalidated or variations are introduced for this
|
|
461
|
+
* layout constraint to cause the configuration used by this layout constraint to be updated.
|
|
462
|
+
*/
|
|
463
|
+
_updateConfiguration() {
|
|
464
|
+
return this._updateConfigurationSilently(NO);
|
|
465
|
+
},
|
|
466
|
+
|
|
467
|
+
/**
|
|
468
|
+
* Invoked by CoreUI whenever size classes are invalidated or variations are introduced for this
|
|
469
|
+
* layout constraint to cause the configuration used by this layout constraint to be updated.
|
|
470
|
+
* @param silently <Boolean> `YES` if this change should be silent, `NO` otherwise. If this change
|
|
471
|
+
* is silent, the internal configuration of this constraint will be updated, but this will
|
|
472
|
+
* not trigger any layout invalidations.
|
|
473
|
+
*/
|
|
474
|
+
_updateConfigurationSilently(silently) {
|
|
475
|
+
let baseConfiguration = {constant: this._constant, priority: this._priority, isActive: this._isActive};
|
|
476
|
+
let viewport = (this._sourceView || this._views[0]).viewport;
|
|
477
|
+
|
|
478
|
+
// Check which variations should be active and in which order
|
|
479
|
+
for (let key in this._variations) {
|
|
480
|
+
this._variations[key]._matchPriority = viewport.matchPriorityForSizeClass(this._variations[key].sizeClass);
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
Object.keys(this._variations).map(key => this._variations[key]).sort((a, b) => b._matchPriority - a._matchPriority).forEach(variation => {
|
|
484
|
+
if (!variation._matchPriority) return;
|
|
485
|
+
|
|
486
|
+
if ('constant' in variation) baseConfiguration.constant = variation.constant;
|
|
487
|
+
if ('priority' in variation) baseConfiguration.priority = variation.priority;
|
|
488
|
+
if ('isActive' in variation) baseConfiguration.isActive = variation.isActive;
|
|
489
|
+
});
|
|
490
|
+
|
|
491
|
+
// Set to YES if the new configuration is different from the current configuration
|
|
492
|
+
let hasChanges = NO;
|
|
493
|
+
|
|
494
|
+
// Update the constant value accordingly
|
|
495
|
+
if (typeof baseConfiguration.constant == 'string') {
|
|
496
|
+
baseConfiguration.constantValue = this._sourceView.valueForLayoutVariable(baseConfiguration.constant);
|
|
497
|
+
}
|
|
498
|
+
else {
|
|
499
|
+
baseConfiguration.constantValue = baseConfiguration.constant;
|
|
500
|
+
}
|
|
501
|
+
|
|
502
|
+
// Update the configuration to the newly computed configuration
|
|
503
|
+
let oldConfiguration = this._configuration || baseConfiguration;
|
|
504
|
+
this._configuration = baseConfiguration;
|
|
505
|
+
if (this._reversesConstant) {
|
|
506
|
+
baseConfiguration.constantValue = -baseConfiguration.constantValue;
|
|
507
|
+
}
|
|
508
|
+
|
|
509
|
+
if (this.isConstraintCollection) {
|
|
510
|
+
for (let constraint of this.constituentConstraints) {
|
|
511
|
+
constraint._updateConfiguration();
|
|
512
|
+
}
|
|
513
|
+
return;
|
|
514
|
+
}
|
|
515
|
+
|
|
516
|
+
if (silently) return;
|
|
517
|
+
|
|
518
|
+
// Check how the configuration has changed and invalidate the layout accordingly
|
|
519
|
+
if (oldConfiguration.isActive != baseConfiguration.isActive) {
|
|
520
|
+
this._sourceView.needsLayout = YES;
|
|
521
|
+
this._sourceView.rootView._invalidatedConstraints = YES;
|
|
522
|
+
this._sourceView._checkConstraints();
|
|
523
|
+
if (this._targetView) {
|
|
524
|
+
this._targetView._checkConstraints();
|
|
525
|
+
}
|
|
526
|
+
hasChanges = YES;
|
|
527
|
+
}
|
|
528
|
+
|
|
529
|
+
if (oldConfiguration.priority != baseConfiguration.priority) {
|
|
530
|
+
this._sourceView.needsLayout = YES;
|
|
531
|
+
this._sourceView.rootView._invalidatedConstraints = YES;
|
|
532
|
+
hasChanges = YES;
|
|
533
|
+
}
|
|
534
|
+
|
|
535
|
+
if (oldConfiguration.constantValue != baseConfiguration.constantValue) {
|
|
536
|
+
if (!hasChanges) {
|
|
537
|
+
// Only modify the constant directly if there are no other changes; otherwise the next layout pass will handle this
|
|
538
|
+
hasChanges = YES;
|
|
539
|
+
|
|
540
|
+
// When changing the constant, update the attached solver, if there is one
|
|
541
|
+
if (this._solver) {
|
|
542
|
+
if (this._constraint) {
|
|
543
|
+
try {
|
|
544
|
+
if (this._solver.hasConstraint(this._constraint)) this._solver.removeConstraint(this._constraint);
|
|
545
|
+
}
|
|
546
|
+
catch (layoutError) {
|
|
547
|
+
this._cassowaryConstraint = undefined;
|
|
548
|
+
this._sourceView.rootView._invalidatedConstraints = YES;
|
|
549
|
+
this._sourceView.needsLayout = YES;
|
|
550
|
+
}
|
|
551
|
+
this._constraint = undefined;
|
|
552
|
+
}
|
|
553
|
+
// If this constant change causes the layout to be unsolvable, catch the error
|
|
554
|
+
// and trigger a full layout pass afterwards to invalidate this constraint
|
|
555
|
+
try {
|
|
556
|
+
this._solver.addConstraint(this._cassowaryConstraint);
|
|
557
|
+
}
|
|
558
|
+
catch (layoutError) {
|
|
559
|
+
this._cassowaryConstraint = undefined;
|
|
560
|
+
this._sourceView.rootView._invalidatedConstraints = YES;
|
|
561
|
+
this._sourceView.needsLayout = YES;
|
|
562
|
+
}
|
|
563
|
+
}
|
|
564
|
+
|
|
565
|
+
if (baseConfiguration.isActive) {
|
|
566
|
+
this._sourceView.needsLayout = YES;
|
|
567
|
+
}
|
|
568
|
+
}
|
|
569
|
+
}
|
|
570
|
+
},
|
|
571
|
+
|
|
572
|
+
/**
|
|
573
|
+
* @deprecated - Unused
|
|
574
|
+
* Returns an object containing the configuration for the current size class.
|
|
575
|
+
*/
|
|
576
|
+
get _activeConfiguration() { // <Object>
|
|
577
|
+
let baseConfiguration = {constant: this._constant, priority: this._priority, isActive: this._isActive};
|
|
578
|
+
|
|
579
|
+
let sizeClass = this._sourceView.sizeClass;
|
|
580
|
+
|
|
581
|
+
// Find the list of size classes compatible with the view's size class
|
|
582
|
+
let compatibleVariations = [];
|
|
583
|
+
for (let key in this._variations) {
|
|
584
|
+
let variationSizeClass = this._variations[key].sizeClass;
|
|
585
|
+
|
|
586
|
+
if (variationSizeClass.matchesSizeClass(sizeClass)) {
|
|
587
|
+
compatibleVariations.push(this._variations[key]);
|
|
588
|
+
}
|
|
589
|
+
}
|
|
590
|
+
|
|
591
|
+
// Sort the size classes by priority, then copy over the variations in ascending priority order
|
|
592
|
+
compatibleVariations.sort((a, b) => b.sizeClass._priority - a.sizeClass._priority).forEach(variation => {
|
|
593
|
+
BMCopyProperties(baseConfiguration, variation);
|
|
594
|
+
});
|
|
595
|
+
|
|
596
|
+
// Return the composed configuration object
|
|
597
|
+
return baseConfiguration;
|
|
598
|
+
},
|
|
599
|
+
|
|
600
|
+
/**
|
|
601
|
+
* The equation's constant component.
|
|
602
|
+
*/
|
|
603
|
+
_constant: 0, // <Number or String>
|
|
604
|
+
get constant() {
|
|
605
|
+
return this._constant;
|
|
606
|
+
},
|
|
607
|
+
set constant(constant) {
|
|
608
|
+
if (constant == this._constant) return;
|
|
609
|
+
this._constant = constant;
|
|
610
|
+
return this._updateConfiguration();
|
|
611
|
+
|
|
612
|
+
// When changing the constant, update the attached solver, if there is one
|
|
613
|
+
if (this._solver) {
|
|
614
|
+
if (this._constraint) {
|
|
615
|
+
this._solver.removeConstraint(this._constraint);
|
|
616
|
+
this._constraint = undefined;
|
|
617
|
+
}
|
|
618
|
+
this._solver.addConstraint(this._cassowaryConstraint);
|
|
619
|
+
}
|
|
620
|
+
|
|
621
|
+
if (this.isActive) {
|
|
622
|
+
this._sourceView.needsLayout = YES;
|
|
623
|
+
}
|
|
624
|
+
},
|
|
625
|
+
|
|
626
|
+
/**
|
|
627
|
+
* Sets this constraint's constant value for the given size class.
|
|
628
|
+
* @param constant <Number or String> The constant.
|
|
629
|
+
* {
|
|
630
|
+
* @param forSizeClass <BMLayoutSizeClass> The layout size class to which the constant should apply.
|
|
631
|
+
* }
|
|
632
|
+
*/
|
|
633
|
+
setConstant(constant, args) {
|
|
634
|
+
if (!this._variations[args.forSizeClass._hashString]) {
|
|
635
|
+
this._variations[args.forSizeClass._hashString] = {sizeClass: args.forSizeClass};
|
|
636
|
+
if (this.isConstraintCollection) {
|
|
637
|
+
this._views[0].rootView._invalidatedSizeClasses = YES;
|
|
638
|
+
}
|
|
639
|
+
else {
|
|
640
|
+
this._sourceView.rootView._invalidatedSizeClasses = YES;
|
|
641
|
+
}
|
|
642
|
+
}
|
|
643
|
+
|
|
644
|
+
this._variations[args.forSizeClass._hashString].constant = constant;
|
|
645
|
+
|
|
646
|
+
// Update the configuration if this change affects the current size classes
|
|
647
|
+
if ((this._sourceView || this._views[0]).viewport.matchesSizeClass(args.forSizeClass)) {
|
|
648
|
+
this._updateConfiguration();
|
|
649
|
+
}
|
|
650
|
+
},
|
|
651
|
+
|
|
652
|
+
/**
|
|
653
|
+
* Removes this constraint's constant variation for the given size class.
|
|
654
|
+
* If this constraint doesn't have a constant variation for this size class, this method does nothing.
|
|
655
|
+
* @param sizeClass <BMLayoutSizeClass> The layout size class.
|
|
656
|
+
*/
|
|
657
|
+
removeConstantVariationForSizeClass(sizeClass) {
|
|
658
|
+
if (this._variations[sizeClass._hashString]) {
|
|
659
|
+
// Delete the constant variation
|
|
660
|
+
delete this._variations[sizeClass._hashString].constant;
|
|
661
|
+
|
|
662
|
+
// Remove the variations object for this size class if there are no other variations left
|
|
663
|
+
if (Object.keys(this._variations[sizeClass._hashString]).length == 1) {
|
|
664
|
+
delete this._variations[sizeClass._hashString];
|
|
665
|
+
if (this.isConstraintCollection) {
|
|
666
|
+
this._views[0].rootView._invalidatedSizeClasses = YES;
|
|
667
|
+
}
|
|
668
|
+
else {
|
|
669
|
+
this._sourceView.rootView._invalidatedSizeClasses = YES;
|
|
670
|
+
}
|
|
671
|
+
}
|
|
672
|
+
|
|
673
|
+
// Update the configuration if this change affects the current size classes
|
|
674
|
+
if ((this._sourceView || this._views[0]).viewport.matchesSizeClass(sizeClass)) {
|
|
675
|
+
this._updateConfiguration();
|
|
676
|
+
}
|
|
677
|
+
}
|
|
678
|
+
},
|
|
679
|
+
|
|
680
|
+
/**
|
|
681
|
+
* Used to verify if this layout constraint has a constant variation for the given size class.
|
|
682
|
+
* @param sizeClass <BMLayoutSizeClass> The size class.
|
|
683
|
+
* @return <Boolean> `YES` if this constraint has a constant variation for the size class, `NO` otherwise.
|
|
684
|
+
*/
|
|
685
|
+
hasConstantVariationForSizeClass(sizeClass) {
|
|
686
|
+
if (this._variations[sizeClass._hashString]) {
|
|
687
|
+
return 'constant' in this._variations[sizeClass._hashString];
|
|
688
|
+
}
|
|
689
|
+
return NO;
|
|
690
|
+
},
|
|
691
|
+
|
|
692
|
+
/**
|
|
693
|
+
* @deprecated - Unused
|
|
694
|
+
* Returns this constraint's constant for the currently active size class.
|
|
695
|
+
*/
|
|
696
|
+
get activeConstant() { // <Number or String>
|
|
697
|
+
// TODO:
|
|
698
|
+
return this._configuration.constant;
|
|
699
|
+
let sizeClassHash = this._sourceView.sizeClass._hashString;
|
|
700
|
+
|
|
701
|
+
if ('constant' in this._variations[sizeClassHash]) {
|
|
702
|
+
return this._variations[sizeClassHash].constant;
|
|
703
|
+
}
|
|
704
|
+
|
|
705
|
+
return this._constant;
|
|
706
|
+
},
|
|
707
|
+
|
|
708
|
+
/**
|
|
709
|
+
* The constraint's priority.
|
|
710
|
+
*/
|
|
711
|
+
_priority: BMLayoutConstraintPriorityRequired, // <Number>
|
|
712
|
+
|
|
713
|
+
get priority() {
|
|
714
|
+
return this._priority;
|
|
715
|
+
},
|
|
716
|
+
set priority(priority) {
|
|
717
|
+
if (this._priority != priority) {
|
|
718
|
+
this._priority = priority;
|
|
719
|
+
return this._updateConfiguration();
|
|
720
|
+
|
|
721
|
+
this._sourceView.needsLayout = YES;
|
|
722
|
+
|
|
723
|
+
if (this._targetView) this._targetView.needsLayout = YES;
|
|
724
|
+
this._sourceView.rootView._invalidatedConstraints = YES;
|
|
725
|
+
}
|
|
726
|
+
},
|
|
727
|
+
|
|
728
|
+
/**
|
|
729
|
+
* Sets this constraint's priority value for the given size class.
|
|
730
|
+
* @param priority <Number> The priority.
|
|
731
|
+
* {
|
|
732
|
+
* @param forSizeClass <BMLayoutSizeClass> The layout size class to which the priority should apply.
|
|
733
|
+
* }
|
|
734
|
+
*/
|
|
735
|
+
setPriority(priority, args) {
|
|
736
|
+
if (!this._variations[args.forSizeClass._hashString]) {
|
|
737
|
+
this._variations[args.forSizeClass._hashString] = {sizeClass: args.forSizeClass};
|
|
738
|
+
if (this.isConstraintCollection) {
|
|
739
|
+
this._views[0].rootView._invalidatedSizeClasses = YES;
|
|
740
|
+
}
|
|
741
|
+
else {
|
|
742
|
+
this._sourceView.rootView._invalidatedSizeClasses = YES;
|
|
743
|
+
}
|
|
744
|
+
}
|
|
745
|
+
|
|
746
|
+
this._variations[args.forSizeClass._hashString].priority = priority;
|
|
747
|
+
|
|
748
|
+
// Update the configuration if this change affects the current size classes
|
|
749
|
+
if ((this._sourceView || this._views[0]).viewport.matchesSizeClass(args.forSizeClass)) {
|
|
750
|
+
this._updateConfiguration();
|
|
751
|
+
}
|
|
752
|
+
},
|
|
753
|
+
|
|
754
|
+
/**
|
|
755
|
+
* Removes this constraint's priority variation for the given size class.
|
|
756
|
+
* If this constraint doesn't have a priority variation for this size class, this method does nothing.
|
|
757
|
+
* @param sizeClass <BMLayoutSizeClass> The layout size class.
|
|
758
|
+
*/
|
|
759
|
+
removePriorityVariationForSizeClass(sizeClass) {
|
|
760
|
+
if (this._variations[sizeClass._hashString]) {
|
|
761
|
+
// Delete the constant variation
|
|
762
|
+
delete this._variations[sizeClass._hashString].priority;
|
|
763
|
+
|
|
764
|
+
// Remove the variations object for this size class if there are no other variations left
|
|
765
|
+
if (Object.keys(this._variations[sizeClass._hashString]).length == 1) {
|
|
766
|
+
delete this._variations[sizeClass._hashString];
|
|
767
|
+
if (this.isConstraintCollection) {
|
|
768
|
+
this._views[0].rootView._invalidatedSizeClasses = YES;
|
|
769
|
+
}
|
|
770
|
+
else {
|
|
771
|
+
this._sourceView.rootView._invalidatedSizeClasses = YES;
|
|
772
|
+
}
|
|
773
|
+
}
|
|
774
|
+
|
|
775
|
+
// Update the configuration if this change affects the current size classes
|
|
776
|
+
if ((this._sourceView || this._views[0]).viewport.matchesSizeClass(sizeClass)) {
|
|
777
|
+
this._updateConfiguration();
|
|
778
|
+
}
|
|
779
|
+
}
|
|
780
|
+
},
|
|
781
|
+
|
|
782
|
+
/**
|
|
783
|
+
* Used to verify if this layout constraint has a priority variation for the given size class.
|
|
784
|
+
* @param sizeClass <BMLayoutSizeClass> The size class.
|
|
785
|
+
* @return <Boolean> `YES` if this constraint has a priority variation for the size class, `NO` otherwise.
|
|
786
|
+
*/
|
|
787
|
+
hasPriorityVariationForSizeClass(sizeClass) {
|
|
788
|
+
if (this._variations[sizeClass._hashString]) {
|
|
789
|
+
return 'priority' in this._variations[sizeClass._hashString];
|
|
790
|
+
}
|
|
791
|
+
return NO;
|
|
792
|
+
},
|
|
793
|
+
|
|
794
|
+
/**
|
|
795
|
+
* @deprecated - Unused
|
|
796
|
+
* Returns this constraint's priority for the currently active size class.
|
|
797
|
+
*/
|
|
798
|
+
get activePriority() { // <Number>
|
|
799
|
+
// TODO:
|
|
800
|
+
return this._configuration.priority;
|
|
801
|
+
let sizeClassHash = this._sourceView.sizeClass._hashString;
|
|
802
|
+
|
|
803
|
+
if ('priority' in this._variations[sizeClassHash]) {
|
|
804
|
+
return this._variations[sizeClassHash].priority;
|
|
805
|
+
}
|
|
806
|
+
|
|
807
|
+
return this._priority;
|
|
808
|
+
},
|
|
809
|
+
|
|
810
|
+
/**
|
|
811
|
+
* The equation sign.
|
|
812
|
+
*/
|
|
813
|
+
_relation: BMLayoutConstraintRelation.Equals, // <BMLayoutConstraintRelation>
|
|
814
|
+
|
|
815
|
+
/**
|
|
816
|
+
* The kind of layout constraint.
|
|
817
|
+
*/
|
|
818
|
+
_kind: undefined, // <BMLayoutConstraintKind>
|
|
819
|
+
|
|
820
|
+
/**
|
|
821
|
+
* Returns a string representing this constraint's category, for debugging purposes.
|
|
822
|
+
*/
|
|
823
|
+
get categoryKind() { // <String>
|
|
824
|
+
if (this._kind == BMLayoutConstraintKind.Vertical) {
|
|
825
|
+
if (this._sourceViewAttribute == BMLayoutAttribute.Height) {
|
|
826
|
+
return 'Height';
|
|
827
|
+
}
|
|
828
|
+
else {
|
|
829
|
+
return 'Vertical Position';
|
|
830
|
+
}
|
|
831
|
+
}
|
|
832
|
+
else {
|
|
833
|
+
if (this._sourceViewAttribute == BMLayoutAttribute.Width) {
|
|
834
|
+
return 'Width';
|
|
835
|
+
}
|
|
836
|
+
else {
|
|
837
|
+
return 'Horizontal Position';
|
|
838
|
+
}
|
|
839
|
+
}
|
|
840
|
+
},
|
|
841
|
+
|
|
842
|
+
/**
|
|
843
|
+
* Defaults to NO. Should be set to YES to cause this constraint to become active and affect the layout.
|
|
844
|
+
*
|
|
845
|
+
* For newly created constraints, it is up to the developer to mark the constraint as active, however in most cases
|
|
846
|
+
* where constraints are created automatically, the view that manages the layout hierarchy will typically
|
|
847
|
+
* manage the active state of constraints it owns, based on the current set of size traits.
|
|
848
|
+
*
|
|
849
|
+
* This operation will throw an exception if the views to which the constraint is related are not part of the same view hierarchy.
|
|
850
|
+
*/
|
|
851
|
+
_isActive: NO, // <Boolean>
|
|
852
|
+
get isActive() {
|
|
853
|
+
return this._isActive;
|
|
854
|
+
},
|
|
855
|
+
set isActive(active) {
|
|
856
|
+
if (active != this._isActive) {
|
|
857
|
+
this._isActive = active;
|
|
858
|
+
return this._updateConfiguration();
|
|
859
|
+
this._sourceView._checkConstraints();
|
|
860
|
+
this._sourceView.needsLayout = YES;
|
|
861
|
+
this._sourceView.rootView._invalidatedConstraints = YES;
|
|
862
|
+
|
|
863
|
+
if (this._targetView) {
|
|
864
|
+
if (this._targetView.rootView != this._sourceView.rootView) {
|
|
865
|
+
throw new Error('[BMCoreUI] Incorrectly attempting to activate a layout constraint that affects two views that do not share a common ancestor.');
|
|
866
|
+
}
|
|
867
|
+
|
|
868
|
+
this._targetView._checkConstraints();
|
|
869
|
+
this._targetView.needsLayout = YES;
|
|
870
|
+
}
|
|
871
|
+
}
|
|
872
|
+
},
|
|
873
|
+
|
|
874
|
+
/**
|
|
875
|
+
* Sets this constraint's active state for the given size class.
|
|
876
|
+
* @param isActive <Number> The active state.
|
|
877
|
+
* {
|
|
878
|
+
* @param forSizeClass <BMLayoutSizeClass> The layout size class to which the active state should apply.
|
|
879
|
+
* }
|
|
880
|
+
*/
|
|
881
|
+
setIsActive(isActive, args) {
|
|
882
|
+
if (!this._variations[args.forSizeClass._hashString]) {
|
|
883
|
+
this._variations[args.forSizeClass._hashString] = {sizeClass: args.forSizeClass};
|
|
884
|
+
if (this.isConstraintCollection) {
|
|
885
|
+
this._views[0].rootView._invalidatedSizeClasses = YES;
|
|
886
|
+
}
|
|
887
|
+
else {
|
|
888
|
+
this._sourceView.rootView._invalidatedSizeClasses = YES;
|
|
889
|
+
}
|
|
890
|
+
}
|
|
891
|
+
|
|
892
|
+
this._variations[args.forSizeClass._hashString].isActive = isActive;
|
|
893
|
+
|
|
894
|
+
// Update the configuration if this change affects the current size classes
|
|
895
|
+
if ((this._sourceView || this._views[0]).viewport.matchesSizeClass(args.forSizeClass)) {
|
|
896
|
+
this._updateConfiguration();
|
|
897
|
+
}
|
|
898
|
+
},
|
|
899
|
+
|
|
900
|
+
/**
|
|
901
|
+
* Removes this constraint's active variation for the given size class.
|
|
902
|
+
* If this constraint doesn't have a active variation for this size class, this method does nothing.
|
|
903
|
+
* @param sizeClass <BMLayoutSizeClass> The layout size class.
|
|
904
|
+
*/
|
|
905
|
+
removeIsActiveVariationForSizeClass(sizeClass) {
|
|
906
|
+
if (this._variations[sizeClass._hashString]) {
|
|
907
|
+
// Delete the constant variation
|
|
908
|
+
delete this._variations[sizeClass._hashString].isActive;
|
|
909
|
+
|
|
910
|
+
// Remove the variations object for this size class if there are no other variations left
|
|
911
|
+
if (Object.keys(this._variations[sizeClass._hashString]).length == 1) {
|
|
912
|
+
delete this._variations[sizeClass._hashString];
|
|
913
|
+
if (this.isConstraintCollection) {
|
|
914
|
+
this._views[0].rootView._invalidatedSizeClasses = YES;
|
|
915
|
+
}
|
|
916
|
+
else {
|
|
917
|
+
this._sourceView.rootView._invalidatedSizeClasses = YES;
|
|
918
|
+
}
|
|
919
|
+
}
|
|
920
|
+
|
|
921
|
+
// Update the configuration if this change affects the current size classes
|
|
922
|
+
if ((this._sourceView || this._views[0]).viewport.matchesSizeClass(sizeClass)) {
|
|
923
|
+
this._updateConfiguration();
|
|
924
|
+
}
|
|
925
|
+
}
|
|
926
|
+
},
|
|
927
|
+
|
|
928
|
+
/**
|
|
929
|
+
* Used to verify if this layout constraint has an isActive variation for the given size class.
|
|
930
|
+
* @param sizeClass <BMLayoutSizeClass> The size class.
|
|
931
|
+
* @return <Boolean> `YES` if this constraint has an isActive variation for the size class, `NO` otherwise.
|
|
932
|
+
*/
|
|
933
|
+
hasIsActiveVariationForSizeClass(sizeClass) {
|
|
934
|
+
if (this._variations[sizeClass._hashString]) {
|
|
935
|
+
return 'isActive' in this._variations[sizeClass._hashString];
|
|
936
|
+
}
|
|
937
|
+
return NO;
|
|
938
|
+
},
|
|
939
|
+
|
|
940
|
+
/**
|
|
941
|
+
* Returns `YES` if this constraint can affect the layout depending on the view hierarchy's current size class.
|
|
942
|
+
*/
|
|
943
|
+
get affectsLayout() { // <Boolean>
|
|
944
|
+
return this._configuration.isActive;
|
|
945
|
+
let sizeClassHash = this._sourceView.sizeClass._hashString;
|
|
946
|
+
|
|
947
|
+
if ('isActive' in this._variations[sizeClassHash]) {
|
|
948
|
+
return this._variations[sizeClassHash].isActive;
|
|
949
|
+
}
|
|
950
|
+
|
|
951
|
+
return this._isActive;
|
|
952
|
+
},
|
|
953
|
+
|
|
954
|
+
/**
|
|
955
|
+
* Invoked internally to install this constraint onto the views it affects.
|
|
956
|
+
*/
|
|
957
|
+
_install() {
|
|
958
|
+
this._sourceView._addConstraint(this);
|
|
959
|
+
|
|
960
|
+
if (this._targetView) {
|
|
961
|
+
this._targetView._addConstraint(this);
|
|
962
|
+
}
|
|
963
|
+
|
|
964
|
+
this._sourceView.rootView._invalidatedConstraints = YES;
|
|
965
|
+
},
|
|
966
|
+
|
|
967
|
+
/**
|
|
968
|
+
* Should be invoked when this constraint is no longer needed and should be removed from the views it affects.
|
|
969
|
+
* This constraint cannot be marked active after invoking this method.
|
|
970
|
+
*/
|
|
971
|
+
remove() {
|
|
972
|
+
if (this._isActive) {
|
|
973
|
+
this._sourceView.needsLayout = YES;
|
|
974
|
+
}
|
|
975
|
+
|
|
976
|
+
this._isActive = NO;
|
|
977
|
+
this._sourceView._removeConstraint(this);
|
|
978
|
+
this._sourceView.rootView._invalidatedConstraints = YES;
|
|
979
|
+
if (this._targetView) {
|
|
980
|
+
this._targetView.needsLayout = YES;
|
|
981
|
+
this._targetView._removeConstraint(this);
|
|
982
|
+
this._sourceView.rootView._invalidatedConstraints = YES;
|
|
983
|
+
}
|
|
984
|
+
|
|
985
|
+
this._sourceView = undefined;
|
|
986
|
+
this._targetView = undefined;
|
|
987
|
+
},
|
|
988
|
+
|
|
989
|
+
/**
|
|
990
|
+
* Invoked internally by CoreUI to retrieve the Cassowary expression that will be
|
|
991
|
+
* generated by this layout constraint. This expression will be used as the basis of
|
|
992
|
+
* the Cassowary constraint that will finally be used in the layout calculations.
|
|
993
|
+
*/
|
|
994
|
+
get _cassowaryExpression() { // <[kiwi.Expression]>
|
|
995
|
+
// Resolve the constant if it is a layout variable
|
|
996
|
+
let constant = this._configuration.constantValue || 0;
|
|
997
|
+
//if (typeof constant === 'string') constant = this._sourceView._layoutVariables[constant] || 0;
|
|
998
|
+
|
|
999
|
+
if (!this._targetView) {
|
|
1000
|
+
if (this._sourceViewAttribute == BMLayoutAttribute.AspectRatio) {
|
|
1001
|
+
// The aspect ratio is treated differently
|
|
1002
|
+
// It expressed as Ratio * Height - Width = 0
|
|
1003
|
+
return new kiwi.Expression(
|
|
1004
|
+
[constant, this._sourceView._variables[BMLayoutAttribute.Height]],
|
|
1005
|
+
[-1, this._sourceView._variables[BMLayoutAttribute.Width]]
|
|
1006
|
+
);
|
|
1007
|
+
}
|
|
1008
|
+
else {
|
|
1009
|
+
// All other attributes use expression provided by the view itself
|
|
1010
|
+
return constant ?
|
|
1011
|
+
this._sourceView._cassowaryExpressionForLayoutAttribute(this._sourceViewAttribute).plus(-constant) :
|
|
1012
|
+
this._sourceView._cassowaryExpressionForLayoutAttribute(this._sourceViewAttribute);
|
|
1013
|
+
}
|
|
1014
|
+
}
|
|
1015
|
+
else {
|
|
1016
|
+
if (this._sourceViewAttribute == BMLayoutAttribute.AspectRatio) {
|
|
1017
|
+
if (this._targetViewAttribute != BMLayoutAttribute.AspectRatio) {
|
|
1018
|
+
throw new Error('[BMCoreUI] Aspect ratio constraints must affect both views\' aspect ratio.');
|
|
1019
|
+
}
|
|
1020
|
+
|
|
1021
|
+
throw new Error('[BMCoreUI] Non-constant aspect ratio constraint are currently not supported.');
|
|
1022
|
+
}
|
|
1023
|
+
|
|
1024
|
+
// All two-view constraints are treated as the following epxression
|
|
1025
|
+
// View1.Attribute - Multiplier * View2.Attribute - Constant = 0
|
|
1026
|
+
var baseExpression = new kiwi.Expression(
|
|
1027
|
+
this._sourceView._cassowaryExpressionForLayoutAttribute(this._sourceViewAttribute)
|
|
1028
|
+
).minus(
|
|
1029
|
+
this._targetView._cassowaryExpressionForLayoutAttribute(this._targetViewAttribute, {withMultiplier: this._multiplier})
|
|
1030
|
+
);
|
|
1031
|
+
|
|
1032
|
+
if (constant) {
|
|
1033
|
+
if (!this._sourceView.LTRLayout && this._kind == BMLayoutConstraintKind.Horizontal && this._sourceViewAttribute != BMLayoutAttribute.Width) {
|
|
1034
|
+
// Horizontal position RTL layouts need to have the constant's sign swapped
|
|
1035
|
+
baseExpression = baseExpression.plus(constant);
|
|
1036
|
+
}
|
|
1037
|
+
else {
|
|
1038
|
+
baseExpression = baseExpression.minus(constant);
|
|
1039
|
+
}
|
|
1040
|
+
}
|
|
1041
|
+
|
|
1042
|
+
return baseExpression;
|
|
1043
|
+
}
|
|
1044
|
+
},
|
|
1045
|
+
|
|
1046
|
+
/**
|
|
1047
|
+
* Invoked internally by CoreUI to retrieve the Cassowary constraint that will be
|
|
1048
|
+
* generated by this layout constraint.
|
|
1049
|
+
*/
|
|
1050
|
+
get _cassowaryConstraint() {
|
|
1051
|
+
if (this._constraint) return this._constraint;
|
|
1052
|
+
|
|
1053
|
+
var expression = this._cassowaryExpression;
|
|
1054
|
+
|
|
1055
|
+
// CoreUI priorities go up to 1000 (Required)
|
|
1056
|
+
// which is mapped to the cassowary required strength value
|
|
1057
|
+
var priority = (this._configuration.priority == BMLayoutConstraintPriorityRequired ?
|
|
1058
|
+
kiwi.Strength.required :
|
|
1059
|
+
this._configuration.priority / 1000 * kiwi.Strength.required);
|
|
1060
|
+
|
|
1061
|
+
// Horizontal position RTL layouts need to have the inequality sign swapped
|
|
1062
|
+
let relation = this._relation;
|
|
1063
|
+
if (!this._sourceView.LTRLayout && this._kind == BMLayoutConstraintKind.Horizontal && this._sourceViewAttribute != BMLayoutAttribute.Width) {
|
|
1064
|
+
if (this._relation == BMLayoutConstraintRelation.GreaterThanOrEquals) {
|
|
1065
|
+
relation = BMLayoutConstraintRelation.LessThanOrEquals;
|
|
1066
|
+
}
|
|
1067
|
+
else if (this._relation == BMLayoutConstraintRelation.LessThanOrEquals) {
|
|
1068
|
+
relation = BMLayoutConstraintRelation.GreaterThanOrEquals;
|
|
1069
|
+
}
|
|
1070
|
+
}
|
|
1071
|
+
|
|
1072
|
+
// CoreUI expressions always use 0 on the right-hand side
|
|
1073
|
+
this._constraint = new kiwi.Constraint(expression, relation, undefined, priority);
|
|
1074
|
+
return this._constraint;
|
|
1075
|
+
},
|
|
1076
|
+
|
|
1077
|
+
/**
|
|
1078
|
+
* An object that specifies the variations supported by this layout constraint across
|
|
1079
|
+
* the size classes supported by its view hierarchy.
|
|
1080
|
+
*/
|
|
1081
|
+
_variations: undefined, // <Dictionary<BMLayoutConstraintVariation>>
|
|
1082
|
+
|
|
1083
|
+
/**
|
|
1084
|
+
* Returns a variations object that can be serialized.
|
|
1085
|
+
*/
|
|
1086
|
+
get _serializedVariations() {
|
|
1087
|
+
let variations = {};
|
|
1088
|
+
|
|
1089
|
+
if (this._variations) {
|
|
1090
|
+
Object.keys(this._variations).forEach(key => {
|
|
1091
|
+
variations[key] = {};
|
|
1092
|
+
Object.keys(this._variations[key]).forEach(key2 => {
|
|
1093
|
+
if (key2 == 'sizeClass') return;
|
|
1094
|
+
variations[key][key2] = this._variations[key][key2];
|
|
1095
|
+
})
|
|
1096
|
+
});
|
|
1097
|
+
}
|
|
1098
|
+
|
|
1099
|
+
return variations;
|
|
1100
|
+
},
|
|
1101
|
+
|
|
1102
|
+
/**
|
|
1103
|
+
* Returns a string representation of this constraint. This is
|
|
1104
|
+
* often used when generating layout-related debug messages.
|
|
1105
|
+
* The contents of the string depend on the currently active size classes.
|
|
1106
|
+
* @return <String> A string.
|
|
1107
|
+
*/
|
|
1108
|
+
toString() {
|
|
1109
|
+
let operatorMap = {
|
|
1110
|
+
[BMLayoutConstraintRelation.Equals]: '=',
|
|
1111
|
+
[BMLayoutConstraintRelation.GreaterThanOrEquals]: '\u2265',
|
|
1112
|
+
[BMLayoutConstraintRelation.LessThanOrEquals]: '\u2264'
|
|
1113
|
+
}
|
|
1114
|
+
|
|
1115
|
+
if (this._targetView) {
|
|
1116
|
+
|
|
1117
|
+
let constant = this._configuration.constant ? `${this._configuration.constant < 0 ? '-' : '+'} ${this._configuration.constant < 0 ? -this._configuration.constant : this._configuration.constant}` : '';
|
|
1118
|
+
|
|
1119
|
+
return `${this._sourceView.debuggingName || this._sourceView.node.id}.${this._sourceViewAttribute} ${operatorMap[this._relation]} \
|
|
1120
|
+
${(this._multiplier != 1 ? this._multiplier + '* ' : '')}${this._targetView.debuggingName || this._targetView.node.id}.${this._targetViewAttribute} \
|
|
1121
|
+
${constant}`;
|
|
1122
|
+
}
|
|
1123
|
+
return `${this._sourceView.debuggingName || this._sourceView.node.id}.${this._sourceViewAttribute} ${operatorMap[this._relation]} ${this._configuration.constant} (${this._configuration.priority})`;
|
|
1124
|
+
},
|
|
1125
|
+
|
|
1126
|
+
/**
|
|
1127
|
+
* Returns a string representation of this constraint. This is
|
|
1128
|
+
* often used when generating layout-related debug messages.
|
|
1129
|
+
* The contents of the string depend on the currently active size classes.
|
|
1130
|
+
* @return <String> A string.
|
|
1131
|
+
*/
|
|
1132
|
+
toCompactString() {
|
|
1133
|
+
let operatorMap = {
|
|
1134
|
+
[BMLayoutConstraintRelation.Equals]: '=',
|
|
1135
|
+
[BMLayoutConstraintRelation.GreaterThanOrEquals]: '\u2265',
|
|
1136
|
+
[BMLayoutConstraintRelation.LessThanOrEquals]: '\u2264'
|
|
1137
|
+
}
|
|
1138
|
+
|
|
1139
|
+
let sourceAttribute = this._sourceViewAttribute.charAt(0);
|
|
1140
|
+
if (this._sourceViewAttribute == BMLayoutAttribute.Left) sourceAttribute = 'Lf';
|
|
1141
|
+
|
|
1142
|
+
if (this._targetView) {
|
|
1143
|
+
let targetAttribute = this._targetViewAttribute.charAt(0);
|
|
1144
|
+
if (this._targetViewAttribute == BMLayoutAttribute.Left) targetAttribute = 'Lf';
|
|
1145
|
+
|
|
1146
|
+
let constant = this._configuration.constant ? `${this._configuration.constant < 0 ? '-' : '+'} ${this._configuration.constant < 0 ? -this._configuration.constant : this._configuration.constant}` : '';
|
|
1147
|
+
|
|
1148
|
+
return `${this._sourceView.debuggingName || this._sourceView.node.id}.${sourceAttribute} ${operatorMap[this._relation]} \
|
|
1149
|
+
${(this._multiplier != 1 ? this._multiplier + '* ' : '')}${this._targetView.debuggingName || this._targetView.node.id}.${targetAttribute} \
|
|
1150
|
+
${constant}`;
|
|
1151
|
+
}
|
|
1152
|
+
return `${this._sourceView.debuggingName || this._sourceView.node.id}.${sourceAttribute} ${operatorMap[this._relation]} ${this._configuration.constant}`;
|
|
1153
|
+
},
|
|
1154
|
+
|
|
1155
|
+
/**
|
|
1156
|
+
* Returns a string representation of this constraint that is relative to the given view. This is
|
|
1157
|
+
* often used when generating layout-related debug messages.
|
|
1158
|
+
* The contents of the string depend on the currently active size classes.
|
|
1159
|
+
* @param view <BMView> The view for which to return the description.
|
|
1160
|
+
* @return <String> A string.
|
|
1161
|
+
*/
|
|
1162
|
+
descriptionRelativeToView(view) {
|
|
1163
|
+
let operatorMap = {
|
|
1164
|
+
[BMLayoutConstraintRelation.Equals]: '=',
|
|
1165
|
+
[BMLayoutConstraintRelation.GreaterThanOrEquals]: '\u2265',
|
|
1166
|
+
[BMLayoutConstraintRelation.LessThanOrEquals]: '\u2264'
|
|
1167
|
+
}
|
|
1168
|
+
|
|
1169
|
+
if (this._sourceView !== view && this._targetView!== view) return this.toString();
|
|
1170
|
+
|
|
1171
|
+
if (this._targetView) {
|
|
1172
|
+
const constant = this._configuration.constant ? `${this._configuration.constant < 0 ? '-' : '+'} ${this._configuration.constant < 0 ? -this._configuration.constant : this._configuration.constant}` : '';
|
|
1173
|
+
|
|
1174
|
+
if (this._sourceView === view) {
|
|
1175
|
+
const constant = this._configuration.constant ? `${this._configuration.constant < 0 ? '-' : '+'} ${this._configuration.constant < 0 ? -this._configuration.constant : this._configuration.constant}` : '';
|
|
1176
|
+
return `${this._sourceViewAttribute} ${operatorMap[this._relation]} \
|
|
1177
|
+
${(this._multiplier != 1 ? this._multiplier + '* ' : '')}${this._targetView.debuggingName || this._targetView.node.id}.${this._targetViewAttribute} \
|
|
1178
|
+
${constant}`;
|
|
1179
|
+
}
|
|
1180
|
+
else {
|
|
1181
|
+
const constant = this._configuration.constant ? `${this._configuration.constant > 0 ? '-' : '+'} ${this._configuration.constant < 0 ? -this._configuration.constant : this._configuration.constant}` : '';
|
|
1182
|
+
const operatorMap = {
|
|
1183
|
+
[BMLayoutConstraintRelation.Equals]: '=',
|
|
1184
|
+
[BMLayoutConstraintRelation.GreaterThanOrEquals]: '\u2264',
|
|
1185
|
+
[BMLayoutConstraintRelation.LessThanOrEquals]: '\u2265'
|
|
1186
|
+
}
|
|
1187
|
+
|
|
1188
|
+
return `${this._targetViewAttribute} ${operatorMap[this._relation]} \
|
|
1189
|
+
${(this._multiplier != 1 ? '(' : '')}${this._sourceView.debuggingName || this._sourceView.node.id}.${this._sourceViewAttribute} \
|
|
1190
|
+
${constant}${(this._multiplier != 1 ? ') / ' + this._multiplier : '')}`
|
|
1191
|
+
|
|
1192
|
+
return `${this._sourceView.debuggingName || this._sourceView.node.id}.${this._sourceViewAttribute} ${operatorMap[this._relation]} \
|
|
1193
|
+
${(this._multiplier != 1 ? this._multiplier + '* ' : '')}${this._targetView.debuggingName || this._targetView.node.id}.${this._targetViewAttribute} \
|
|
1194
|
+
${constant}`;
|
|
1195
|
+
}
|
|
1196
|
+
|
|
1197
|
+
return `${this._sourceView.debuggingName || this._sourceView.node.id}.${this._sourceViewAttribute} ${operatorMap[this._relation]} \
|
|
1198
|
+
${(this._multiplier != 1 ? this._multiplier + '* ' : '')}${this._targetView.debuggingName || this._targetView.node.id}.${this._targetViewAttribute} \
|
|
1199
|
+
${constant}`;
|
|
1200
|
+
}
|
|
1201
|
+
|
|
1202
|
+
return `${this._sourceViewAttribute} ${operatorMap[this._relation]} ${this._configuration.constant}`;
|
|
1203
|
+
},
|
|
1204
|
+
|
|
1205
|
+
/**
|
|
1206
|
+
* Returns an object representing this constraint that may be serialized to a string.
|
|
1207
|
+
* @param block <String ^(BMView)> A block that will be invoked for each view that this constraint affects.
|
|
1208
|
+
* The block is given the view instance and should return a string from which
|
|
1209
|
+
* a view reference may be obtained when this serialized representation is converted
|
|
1210
|
+
* back into a constraint.
|
|
1211
|
+
* @return <AnyObject> A serializable representation of this constraint.
|
|
1212
|
+
*/
|
|
1213
|
+
serializedConstraintWithViewIDs(block) {
|
|
1214
|
+
return {
|
|
1215
|
+
_class: 'BMLayoutConstraint',
|
|
1216
|
+
_sourceViewAttribute: this._sourceViewAttribute,
|
|
1217
|
+
_relation: this._relation,
|
|
1218
|
+
_targetViewAttribute: this._targetViewAttribute,
|
|
1219
|
+
_constant: this._constant,
|
|
1220
|
+
_multiplier: this._multiplier,
|
|
1221
|
+
_priority: this._priority,
|
|
1222
|
+
_sourceView: block(this._sourceView),
|
|
1223
|
+
_targetView: this._targetView ? block(this._targetView) : undefined,
|
|
1224
|
+
_kind: this._kind,
|
|
1225
|
+
_identifier: this._identifier,
|
|
1226
|
+
_variations: this._serializedVariations,
|
|
1227
|
+
_isActive: this._isActive
|
|
1228
|
+
};
|
|
1229
|
+
}
|
|
1230
|
+
|
|
1231
|
+
};
|
|
1232
|
+
|
|
1233
|
+
// @endtype
|
|
1234
|
+
|
|
1235
|
+
// @type BMEqualAttributeLayoutConstraint extends BMLayoutConstraint
|
|
1236
|
+
|
|
1237
|
+
/**
|
|
1238
|
+
* An equal attribute layout constraint is a constraint collection that makes a given attribute
|
|
1239
|
+
* of a set of views have the same value.
|
|
1240
|
+
*/
|
|
1241
|
+
export function BMEqualAttributeLayoutConstraint() {} // <constructor>
|
|
1242
|
+
|
|
1243
|
+
/**
|
|
1244
|
+
* Constructs and returns a constraint that makes all of the views given to it have the same value
|
|
1245
|
+
* for a given attribute.
|
|
1246
|
+
* @param attribute <BMLayoutAttribute> The attribute.
|
|
1247
|
+
* {
|
|
1248
|
+
* @param forViews <[BMView]> An array of views that this constraint affects. This array should contain at least
|
|
1249
|
+
* two views.
|
|
1250
|
+
* @param priority <Number, nullable> Defaults to <code>BMLayoutConstraintPriorityRequired</code>. The constraint's priority.
|
|
1251
|
+
* }
|
|
1252
|
+
* @return <BMEqualAttributeLayoutConstraint> A constraint.
|
|
1253
|
+
*/
|
|
1254
|
+
BMEqualAttributeLayoutConstraint.constraintWithAttribute = function (attribute, args) {
|
|
1255
|
+
let constraint = new BMEqualAttributeLayoutConstraint();
|
|
1256
|
+
|
|
1257
|
+
constraint._identifier = BMUUIDMake();
|
|
1258
|
+
|
|
1259
|
+
constraint._views = args.forViews.slice();
|
|
1260
|
+
constraint._attribute = attribute;
|
|
1261
|
+
constraint._priority = args.priority || BMLayoutConstraintPriorityRequired;
|
|
1262
|
+
|
|
1263
|
+
if (attribute === BMLayoutAttribute.Top || attribute == BMLayoutAttribute.Bottom || attribute === BMLayoutAttribute.Height || attribute === BMLayoutAttribute.CenterY) {
|
|
1264
|
+
constraint._kind = BMLayoutConstraintKind.Vertical;
|
|
1265
|
+
}
|
|
1266
|
+
else {
|
|
1267
|
+
constraint._kind = BMLayoutConstraintKind.Horizontal;
|
|
1268
|
+
}
|
|
1269
|
+
|
|
1270
|
+
constraint._variations = {};
|
|
1271
|
+
constraint._configuration = {constant: constraint._constant, priority: constraint._priority, isActive: constraint._isActive};
|
|
1272
|
+
|
|
1273
|
+
if (!args._internal) {
|
|
1274
|
+
constraint._install();
|
|
1275
|
+
}
|
|
1276
|
+
else {
|
|
1277
|
+
constraint._internal = YES;
|
|
1278
|
+
}
|
|
1279
|
+
|
|
1280
|
+
return constraint;
|
|
1281
|
+
}
|
|
1282
|
+
|
|
1283
|
+
BMEqualAttributeLayoutConstraint.prototype = BMExtend({}, BMLayoutConstraint.prototype, {
|
|
1284
|
+
|
|
1285
|
+
// @override - BMLayoutConstraint
|
|
1286
|
+
initWithSerializedConstraint(constraint, args) {
|
|
1287
|
+
this._views = constraint._views.map(viewID => args.viewIDs(viewID));
|
|
1288
|
+
for (var i = 0; i < this._views.length; i++) {
|
|
1289
|
+
if (!this._views[i]) return undefined;
|
|
1290
|
+
}
|
|
1291
|
+
this._attribute = constraint._attribute;
|
|
1292
|
+
this._kind = constraint._kind;
|
|
1293
|
+
this._priority = constraint._priority;
|
|
1294
|
+
this._identifier = constraint._identifier || BMUUIDMake();
|
|
1295
|
+
this._isActive = (constraint._isActive === undefined) ? YES : constraint._isActive;
|
|
1296
|
+
|
|
1297
|
+
// For variations, it is required to re-create the size class object references from their hash strings
|
|
1298
|
+
this._variations = constraint._variations || {};
|
|
1299
|
+
for (let key in this._variations) {
|
|
1300
|
+
this._variations[key].sizeClass = BMLayoutSizeClass._layoutSizeClassForHashString(key);
|
|
1301
|
+
}
|
|
1302
|
+
|
|
1303
|
+
// Create the configuration
|
|
1304
|
+
this._updateConfiguration();
|
|
1305
|
+
|
|
1306
|
+
this._install();
|
|
1307
|
+
|
|
1308
|
+
return this;
|
|
1309
|
+
},
|
|
1310
|
+
|
|
1311
|
+
/**
|
|
1312
|
+
* The views that this constraint affects.
|
|
1313
|
+
*/
|
|
1314
|
+
_views: undefined, // <[BMView]>
|
|
1315
|
+
|
|
1316
|
+
/**
|
|
1317
|
+
* The attribute affected by this constraint.
|
|
1318
|
+
*/
|
|
1319
|
+
_attribute: undefined, // <BMLayoutAttribute>
|
|
1320
|
+
|
|
1321
|
+
// @override - BMLayoutConstraint
|
|
1322
|
+
affectedAttributesForView(view) {
|
|
1323
|
+
let attributes = [];
|
|
1324
|
+
|
|
1325
|
+
if (this._views.indexOf(view) != -1) return [this._attribute];
|
|
1326
|
+
|
|
1327
|
+
return attributes;
|
|
1328
|
+
},
|
|
1329
|
+
|
|
1330
|
+
|
|
1331
|
+
// @override - BMLayoutConstraint
|
|
1332
|
+
get isConstraintCollection() {
|
|
1333
|
+
return YES;
|
|
1334
|
+
},
|
|
1335
|
+
|
|
1336
|
+
|
|
1337
|
+
_constituentConstraints: undefined, // <[BMLayoutConstraints]>
|
|
1338
|
+
|
|
1339
|
+
// @override - BMLayoutConstraint
|
|
1340
|
+
get constituentConstraints() {
|
|
1341
|
+
if (this._constituentConstraints) return this._constituentConstraints;
|
|
1342
|
+
|
|
1343
|
+
let constraints = [];
|
|
1344
|
+
let constituentConstraint;
|
|
1345
|
+
|
|
1346
|
+
for (let i = 1; i < this._views.length; i++) {
|
|
1347
|
+
constraints.push(constituentConstraint = BMLayoutConstraint.internalConstraintWithView(this._views[i - 1], {
|
|
1348
|
+
attribute: this._attribute,
|
|
1349
|
+
relatedBy: BMLayoutConstraintRelation.Equals,
|
|
1350
|
+
toView: this._views[i],
|
|
1351
|
+
secondAttribute: this._attribute,
|
|
1352
|
+
constant: 0,
|
|
1353
|
+
multiplier: 1,
|
|
1354
|
+
priority: this._priority
|
|
1355
|
+
}));
|
|
1356
|
+
constituentConstraint._variations = this._variations;
|
|
1357
|
+
constituentConstraint._isActive = this._isActive;
|
|
1358
|
+
constituentConstraint._updateConfigurationSilently(YES);
|
|
1359
|
+
}
|
|
1360
|
+
|
|
1361
|
+
this._constituentConstraints = constraints;
|
|
1362
|
+
return constraints;
|
|
1363
|
+
},
|
|
1364
|
+
|
|
1365
|
+
// @override - BMLayoutConstraint
|
|
1366
|
+
get constant() {
|
|
1367
|
+
return this._constant;
|
|
1368
|
+
},
|
|
1369
|
+
set constant(constant) {
|
|
1370
|
+
if (constant == this._constant) return;
|
|
1371
|
+
this._constant = constant;
|
|
1372
|
+
return this._updateConfiguration();
|
|
1373
|
+
|
|
1374
|
+
this.constituentConstraints.forEach(constraint => constraint.constant = constant);
|
|
1375
|
+
},
|
|
1376
|
+
|
|
1377
|
+
|
|
1378
|
+
// @override - BMLayoutConstraint
|
|
1379
|
+
get _hasEditableConstant() {
|
|
1380
|
+
return NO;
|
|
1381
|
+
},
|
|
1382
|
+
|
|
1383
|
+
// @override - BMLayoutConstraint
|
|
1384
|
+
get categoryKind() { // <String>
|
|
1385
|
+
if (this._kind == BMLayoutConstraintKind.Vertical) {
|
|
1386
|
+
if (this._attribute == BMLayoutAttribute.Height) {
|
|
1387
|
+
return 'Height';
|
|
1388
|
+
}
|
|
1389
|
+
else {
|
|
1390
|
+
return 'Vertical Position';
|
|
1391
|
+
}
|
|
1392
|
+
}
|
|
1393
|
+
else {
|
|
1394
|
+
if (this._attribute == BMLayoutAttribute.Width) {
|
|
1395
|
+
return 'Width';
|
|
1396
|
+
}
|
|
1397
|
+
else {
|
|
1398
|
+
return 'Horizontal Position';
|
|
1399
|
+
}
|
|
1400
|
+
}
|
|
1401
|
+
},
|
|
1402
|
+
|
|
1403
|
+
|
|
1404
|
+
// @override - BMLayoutConstraint
|
|
1405
|
+
_isActive: NO,
|
|
1406
|
+
|
|
1407
|
+
get isActive() {
|
|
1408
|
+
return this._isActive;
|
|
1409
|
+
},
|
|
1410
|
+
set isActive(active) {
|
|
1411
|
+
if (active != this._isActive) {
|
|
1412
|
+
this._isActive = active;
|
|
1413
|
+
return this._updateConfiguration();
|
|
1414
|
+
this._views[0].rootView._invalidatedConstraints = YES;
|
|
1415
|
+
|
|
1416
|
+
this._views.forEach(view => {
|
|
1417
|
+
view._checkConstraints();
|
|
1418
|
+
view.needsLayout = YES;
|
|
1419
|
+
});
|
|
1420
|
+
}
|
|
1421
|
+
},
|
|
1422
|
+
|
|
1423
|
+
// @override - BMLayoutConstraint
|
|
1424
|
+
_install() {
|
|
1425
|
+
this._views.forEach(view => view._addConstraint(this));
|
|
1426
|
+
this._views[0].rootView._invalidatedConstraints = YES;
|
|
1427
|
+
},
|
|
1428
|
+
|
|
1429
|
+
|
|
1430
|
+
// @override - BMLayoutConstraint
|
|
1431
|
+
remove() {
|
|
1432
|
+
if (this._isActive) {
|
|
1433
|
+
this._isActive = NO;
|
|
1434
|
+
}
|
|
1435
|
+
|
|
1436
|
+
this._views.forEach(view => {
|
|
1437
|
+
view._removeConstraint(this);
|
|
1438
|
+
view._checkConstraints();
|
|
1439
|
+
view.needsLayout = YES;
|
|
1440
|
+
});
|
|
1441
|
+
this._views[0].rootView._invalidatedConstraints = YES;
|
|
1442
|
+
|
|
1443
|
+
this._views = undefined;
|
|
1444
|
+
},
|
|
1445
|
+
|
|
1446
|
+
|
|
1447
|
+
// @override - BMLayoutConstraint
|
|
1448
|
+
toString() {
|
|
1449
|
+
return 'Equal ' + this._attribute;
|
|
1450
|
+
},
|
|
1451
|
+
|
|
1452
|
+
|
|
1453
|
+
// @override - BMLayoutConstraint
|
|
1454
|
+
toCompactString() {
|
|
1455
|
+
return 'Equal ' + this._attribute;
|
|
1456
|
+
},
|
|
1457
|
+
|
|
1458
|
+
// @override - BMLayoutConstraint
|
|
1459
|
+
serializedConstraintWithViewIDs(block) {
|
|
1460
|
+
return {
|
|
1461
|
+
_class: 'BMEqualAttributeLayoutConstraint',
|
|
1462
|
+
_attribute: this._attribute,
|
|
1463
|
+
_priority: this._priority,
|
|
1464
|
+
_views: this._views.map(view => block(view)),
|
|
1465
|
+
_kind: this._kind,
|
|
1466
|
+
_identifier: this._identifier,
|
|
1467
|
+
_variations: this._serializedVariations,
|
|
1468
|
+
_isActive: this._isActive
|
|
1469
|
+
};
|
|
1470
|
+
}
|
|
1471
|
+
});
|
|
1472
|
+
|
|
1473
|
+
// @endtype
|
|
1474
|
+
|
|
1475
|
+
// @type BMEqualSpacingLayoutConstraint extends BMLayoutConstraint
|
|
1476
|
+
|
|
1477
|
+
|
|
1478
|
+
/**
|
|
1479
|
+
* An equal attribute layout constraint is a constraint collection that makes a set of views
|
|
1480
|
+
* have the same spacing between them, and optionally between the first and last view and the superview.
|
|
1481
|
+
*/
|
|
1482
|
+
export function BMEqualSpacingLayoutConstraint () {} // <constructor>
|
|
1483
|
+
|
|
1484
|
+
|
|
1485
|
+
/**
|
|
1486
|
+
* Constructs and returns a constraint that makes all of the views given to it have the same value
|
|
1487
|
+
* for a given attribute.
|
|
1488
|
+
* @param kind <BMLayoutConstraintKind> The kind of spacing. Should be .Horizontal or .Vertical
|
|
1489
|
+
* {
|
|
1490
|
+
* @param forViews <[BMView]> An array of views that this constraint affects. This array should contain at least
|
|
1491
|
+
* two views. If <code>withSuperview</code> is set to <code>YES</code>, this views in this
|
|
1492
|
+
* array must be siblings.
|
|
1493
|
+
* @param withSuperview <Boolean, nullable> Defaults to <code>NO</code>. If set to <code>YES</code>, the first and last views in
|
|
1494
|
+
* the array will have leading and trailing constraints bound to their superview. This method will raise an exception
|
|
1495
|
+
* if this parameter is set to `YES` and the views do not have the same superview.
|
|
1496
|
+
* @param constant <Number or String, nullable> Defaults to <code>0</code>. The spacing to apply between the views.
|
|
1497
|
+
* @param priority <Number, nullable> Defaults to <code>BMLayoutConstraintPriorityRequired</code>. The constraint's priority.
|
|
1498
|
+
* }
|
|
1499
|
+
* @return <BMEqualAttributeLayoutConstraint> A constraint.
|
|
1500
|
+
*/
|
|
1501
|
+
BMEqualSpacingLayoutConstraint.constraintOfKind = function (kind, args) {
|
|
1502
|
+
let constraint = new BMEqualSpacingLayoutConstraint();
|
|
1503
|
+
|
|
1504
|
+
constraint._views = args.forViews.slice();
|
|
1505
|
+
constraint._kind = kind;
|
|
1506
|
+
constraint._priority = args.priority || BMLayoutConstraintPriorityRequired;
|
|
1507
|
+
constraint._constant = args.constant || 0;
|
|
1508
|
+
|
|
1509
|
+
constraint._identifier = BMUUIDMake();
|
|
1510
|
+
|
|
1511
|
+
if (args.withSuperview) {
|
|
1512
|
+
// Ensure that if the superview is specified the views are siblings
|
|
1513
|
+
constraint._withSuperview = args.withSuperview;
|
|
1514
|
+
let parent = args.forViews[0].superview;
|
|
1515
|
+
args.forViews.forEach(view => {
|
|
1516
|
+
if (view.superview != parent) throw new Error("The views must have the same superview.");
|
|
1517
|
+
});
|
|
1518
|
+
|
|
1519
|
+
constraint._superview = parent;
|
|
1520
|
+
}
|
|
1521
|
+
|
|
1522
|
+
if (kind == BMLayoutConstraintKind.Horizontal) {
|
|
1523
|
+
constraint._firstAttribute = BMLayoutAttribute.Leading;
|
|
1524
|
+
constraint._secondAttribute = BMLayoutAttribute.Trailing;
|
|
1525
|
+
}
|
|
1526
|
+
else {
|
|
1527
|
+
constraint._firstAttribute = BMLayoutAttribute.Top;
|
|
1528
|
+
constraint._secondAttribute = BMLayoutAttribute.Bottom;
|
|
1529
|
+
}
|
|
1530
|
+
|
|
1531
|
+
constraint._variations = {};
|
|
1532
|
+
constraint._configuration = {constant: constraint._constant, priority: constraint._priority, isActive: constraint._isActive};
|
|
1533
|
+
if (typeof constraint._constant == 'string') {
|
|
1534
|
+
constraint._configuration.constantValue = args.forViews[0].rootView.valueForLayoutVariable(constraint._constant);
|
|
1535
|
+
}
|
|
1536
|
+
else {
|
|
1537
|
+
constraint._configuration.constantValue = constraint._constant;
|
|
1538
|
+
}
|
|
1539
|
+
|
|
1540
|
+
if (!args._internal) {
|
|
1541
|
+
constraint._install();
|
|
1542
|
+
}
|
|
1543
|
+
else {
|
|
1544
|
+
constraint._internal = YES;
|
|
1545
|
+
}
|
|
1546
|
+
|
|
1547
|
+
return constraint;
|
|
1548
|
+
}
|
|
1549
|
+
|
|
1550
|
+
|
|
1551
|
+
BMEqualSpacingLayoutConstraint.prototype = BMExtend({}, BMLayoutConstraint.prototype, {
|
|
1552
|
+
|
|
1553
|
+
// @override - BMLayoutConstraint
|
|
1554
|
+
initWithSerializedConstraint(constraint, args) {
|
|
1555
|
+
this._views = constraint._views.map(viewID => args.viewIDs(viewID));
|
|
1556
|
+
for (var i = 0; i < this._views.length; i++) {
|
|
1557
|
+
if (!this._views[i]) return undefined;
|
|
1558
|
+
}
|
|
1559
|
+
if (constraint._superview) {
|
|
1560
|
+
this._superview = args.viewIDs(constraint._superview);
|
|
1561
|
+
if (!this._superview) return undefined;
|
|
1562
|
+
}
|
|
1563
|
+
this._firstAttribute = constraint._firstAttribute;
|
|
1564
|
+
this._secondAttribute = constraint._secondAttribute;
|
|
1565
|
+
this._constant = constraint._constant;
|
|
1566
|
+
this._kind = constraint._kind;
|
|
1567
|
+
this._priority = constraint._priority;
|
|
1568
|
+
this._identifier = constraint._identifier || BMUUIDMake();
|
|
1569
|
+
this._isActive = (constraint._isActive === undefined) ? YES : constraint._isActive;
|
|
1570
|
+
|
|
1571
|
+
// For variations, it is required to re-create the size class object references from their hash strings
|
|
1572
|
+
this._variations = constraint._variations || {};
|
|
1573
|
+
for (let key in this._variations) {
|
|
1574
|
+
this._variations[key].sizeClass = BMLayoutSizeClass._layoutSizeClassForHashString(key);
|
|
1575
|
+
}
|
|
1576
|
+
|
|
1577
|
+
// Create the configuration
|
|
1578
|
+
this._updateConfiguration();
|
|
1579
|
+
|
|
1580
|
+
this._install();
|
|
1581
|
+
|
|
1582
|
+
return this;
|
|
1583
|
+
},
|
|
1584
|
+
|
|
1585
|
+
/**
|
|
1586
|
+
* The views that this constraint affects.
|
|
1587
|
+
*/
|
|
1588
|
+
_views: undefined, // <[BMView]>
|
|
1589
|
+
|
|
1590
|
+
/**
|
|
1591
|
+
* The superview affected by this constraint, if any.
|
|
1592
|
+
*/
|
|
1593
|
+
_superview: undefined, // <BMView, nullable>
|
|
1594
|
+
|
|
1595
|
+
/**
|
|
1596
|
+
* The first attribute for this constraint. This is <code>.Leading</code> for horizontal spacing
|
|
1597
|
+
* and <code>.Top</code> for vertical spacing.
|
|
1598
|
+
*/
|
|
1599
|
+
_firstAttribute: undefined, // <BMLayoutAttribute>
|
|
1600
|
+
|
|
1601
|
+
/**
|
|
1602
|
+
* The first attribute for this constraint. This is <code>.Leading</code> for horizontal spacing
|
|
1603
|
+
* and <code>.Top</code> for vertical spacing.
|
|
1604
|
+
*/
|
|
1605
|
+
_secondAttribute: undefined, // <BMLayoutAttribute>
|
|
1606
|
+
|
|
1607
|
+
//
|
|
1608
|
+
// The type of spacing to apply.
|
|
1609
|
+
//
|
|
1610
|
+
_kind: undefined, // <BMLayoutConstraintKind>
|
|
1611
|
+
|
|
1612
|
+
// @override - BMLayoutConstraint
|
|
1613
|
+
affectedAttributesForView(view) {
|
|
1614
|
+
let attributes = [];
|
|
1615
|
+
let index = 0;
|
|
1616
|
+
|
|
1617
|
+
if (view == this._superview) return [this._firstAttribute, this._secondAttribute];
|
|
1618
|
+
|
|
1619
|
+
if ((index = this._views.indexOf(view)) != -1) {
|
|
1620
|
+
if (this._superview) {
|
|
1621
|
+
if (index == 0) return [this._secondAttribute];
|
|
1622
|
+
if (index == this._views.length - 1) return [this._firstAttribute];
|
|
1623
|
+
return [this._firstAttribute, this._secondAttribute];
|
|
1624
|
+
}
|
|
1625
|
+
else {
|
|
1626
|
+
return [this._firstAttribute, this._secondAttribute];
|
|
1627
|
+
}
|
|
1628
|
+
}
|
|
1629
|
+
|
|
1630
|
+
return attributes;
|
|
1631
|
+
},
|
|
1632
|
+
|
|
1633
|
+
|
|
1634
|
+
// @override - BMLayoutConstraint
|
|
1635
|
+
get isConstraintCollection() {
|
|
1636
|
+
return YES;
|
|
1637
|
+
},
|
|
1638
|
+
|
|
1639
|
+
_constituentConstraints: undefined, // <[BMLayoutConstraint]>
|
|
1640
|
+
|
|
1641
|
+
// @override - BMLayoutConstraint
|
|
1642
|
+
get constituentConstraints() {
|
|
1643
|
+
if (this._constituentConstraints) return this._constituentConstraints;
|
|
1644
|
+
|
|
1645
|
+
let constraints = [];
|
|
1646
|
+
|
|
1647
|
+
let constituentConstraint;
|
|
1648
|
+
|
|
1649
|
+
for (let i = 1; i < this._views.length; i++) {
|
|
1650
|
+
constraints.push(constituentConstraint = BMLayoutConstraint.internalConstraintWithView(this._views[i - 1], {
|
|
1651
|
+
attribute: this._secondAttribute,
|
|
1652
|
+
relatedBy: BMLayoutConstraintRelation.Equals,
|
|
1653
|
+
toView: this._views[i],
|
|
1654
|
+
secondAttribute: this._firstAttribute,
|
|
1655
|
+
constant: this._constant,
|
|
1656
|
+
multiplier: 1,
|
|
1657
|
+
priority: this._priority
|
|
1658
|
+
}));
|
|
1659
|
+
|
|
1660
|
+
constituentConstraint._reversesConstant = YES;
|
|
1661
|
+
constituentConstraint._variations = this._variations;
|
|
1662
|
+
constituentConstraint._isActive = this._isActive;
|
|
1663
|
+
constituentConstraint._updateConfigurationSilently(YES);
|
|
1664
|
+
}
|
|
1665
|
+
|
|
1666
|
+
if (this._superview) {
|
|
1667
|
+
constraints.push(constituentConstraint = BMLayoutConstraint.internalConstraintWithView(this._views[0], {
|
|
1668
|
+
attribute: this._firstAttribute,
|
|
1669
|
+
relatedBy: BMLayoutConstraintRelation.Equals,
|
|
1670
|
+
toView: this._superview,
|
|
1671
|
+
secondAttribute: this._firstAttribute,
|
|
1672
|
+
constant: this._constant,
|
|
1673
|
+
multiplier: 1,
|
|
1674
|
+
priority: this._priority
|
|
1675
|
+
}));
|
|
1676
|
+
constituentConstraint._variations = this._variations;
|
|
1677
|
+
constituentConstraint._isActive = this._isActive;
|
|
1678
|
+
constituentConstraint._updateConfigurationSilently(YES);
|
|
1679
|
+
|
|
1680
|
+
constraints.push(constituentConstraint = BMLayoutConstraint.internalConstraintWithView(this._views[this._views.length - 1], {
|
|
1681
|
+
attribute: this._secondAttribute,
|
|
1682
|
+
relatedBy: BMLayoutConstraintRelation.Equals,
|
|
1683
|
+
toView: this._superview,
|
|
1684
|
+
secondAttribute: this._secondAttribute,
|
|
1685
|
+
constant: this._constant,
|
|
1686
|
+
multiplier: 1,
|
|
1687
|
+
priority: this._priority
|
|
1688
|
+
}));
|
|
1689
|
+
constituentConstraint._reversesConstant = YES;
|
|
1690
|
+
constituentConstraint._variations = this._variations;
|
|
1691
|
+
constituentConstraint._isActive = this._isActive;
|
|
1692
|
+
constituentConstraint._updateConfigurationSilently(YES);
|
|
1693
|
+
}
|
|
1694
|
+
|
|
1695
|
+
this._constituentConstraints = constraints;
|
|
1696
|
+
return constraints;
|
|
1697
|
+
},
|
|
1698
|
+
|
|
1699
|
+
// @override - BMLayoutConstraint
|
|
1700
|
+
get constant() {
|
|
1701
|
+
return this._constant;
|
|
1702
|
+
},
|
|
1703
|
+
set constant(constant) {
|
|
1704
|
+
if (constant == this._constant) return;
|
|
1705
|
+
this._constant = constant;
|
|
1706
|
+
return this._updateConfiguration();
|
|
1707
|
+
|
|
1708
|
+
this.constituentConstraints.forEach(constraint => constraint.constant = constant);
|
|
1709
|
+
},
|
|
1710
|
+
|
|
1711
|
+
|
|
1712
|
+
// @override - BMLayoutConstraint
|
|
1713
|
+
get _hasEditableConstant() {
|
|
1714
|
+
return YES;
|
|
1715
|
+
},
|
|
1716
|
+
|
|
1717
|
+
// @override - BMLayoutConstraint
|
|
1718
|
+
get categoryKind() { // <String>
|
|
1719
|
+
if (this._kind == BMLayoutConstraintKind.Vertical) {
|
|
1720
|
+
return 'Vertical Position';
|
|
1721
|
+
}
|
|
1722
|
+
else {
|
|
1723
|
+
return 'Horizontal Position';
|
|
1724
|
+
}
|
|
1725
|
+
},
|
|
1726
|
+
|
|
1727
|
+
|
|
1728
|
+
// @override - BMLayoutConstraint
|
|
1729
|
+
_isActive: NO,
|
|
1730
|
+
|
|
1731
|
+
get isActive() {
|
|
1732
|
+
return this._isActive;
|
|
1733
|
+
},
|
|
1734
|
+
set isActive(active) {
|
|
1735
|
+
if (active != this._isActive) {
|
|
1736
|
+
this._isActive = active;
|
|
1737
|
+
return this._updateConfiguration();
|
|
1738
|
+
this._views[0].rootView._invalidatedConstraints = YES;
|
|
1739
|
+
|
|
1740
|
+
this._views.forEach(view => {
|
|
1741
|
+
view._checkConstraints();
|
|
1742
|
+
view.needsLayout = YES;
|
|
1743
|
+
});
|
|
1744
|
+
|
|
1745
|
+
if (this._superview) {
|
|
1746
|
+
this._superview._checkConstraints();
|
|
1747
|
+
this._superview.needsLayout = YES;
|
|
1748
|
+
}
|
|
1749
|
+
}
|
|
1750
|
+
},
|
|
1751
|
+
|
|
1752
|
+
// @override - BMLayoutConstraint
|
|
1753
|
+
_install() {
|
|
1754
|
+
this._views.forEach(view => view._addConstraint(this));
|
|
1755
|
+
this._views[0].rootView._invalidatedConstraints = YES;
|
|
1756
|
+
|
|
1757
|
+
if (this._superview) this._superview._addConstraint(this);
|
|
1758
|
+
},
|
|
1759
|
+
|
|
1760
|
+
|
|
1761
|
+
// @override - BMLayoutConstraint
|
|
1762
|
+
remove() {
|
|
1763
|
+
if (this._isActive) {
|
|
1764
|
+
this._isActive = NO;
|
|
1765
|
+
}
|
|
1766
|
+
|
|
1767
|
+
this._views.forEach(view => {
|
|
1768
|
+
view._removeConstraint(this);
|
|
1769
|
+
view._checkConstraints();
|
|
1770
|
+
view.needsLayout = YES;
|
|
1771
|
+
});
|
|
1772
|
+
this._views[0].rootView._invalidatedConstraints = YES;
|
|
1773
|
+
|
|
1774
|
+
if (this._superview) {
|
|
1775
|
+
this._superview._removeConstraint(this);
|
|
1776
|
+
this._superview._checkConstraints();
|
|
1777
|
+
this._superview.needsLayout = YES;
|
|
1778
|
+
}
|
|
1779
|
+
|
|
1780
|
+
this._views = undefined;
|
|
1781
|
+
},
|
|
1782
|
+
|
|
1783
|
+
|
|
1784
|
+
// @override - BMLayoutConstraint
|
|
1785
|
+
toString() {
|
|
1786
|
+
return 'Equal Spacing';
|
|
1787
|
+
},
|
|
1788
|
+
|
|
1789
|
+
|
|
1790
|
+
// @override - BMLayoutConstraint
|
|
1791
|
+
toCompactString() {
|
|
1792
|
+
return 'Equal Spacing';
|
|
1793
|
+
},
|
|
1794
|
+
|
|
1795
|
+
// @override - BMLayoutConstraint
|
|
1796
|
+
serializedConstraintWithViewIDs(block) {
|
|
1797
|
+
return {
|
|
1798
|
+
_class: 'BMEqualSpacingLayoutConstraint',
|
|
1799
|
+
_priority: this._priority,
|
|
1800
|
+
_views: this._views.map(view => block(view)),
|
|
1801
|
+
_superview: this._superview ? block(this._superview) : undefined,
|
|
1802
|
+
_constant: this._constant,
|
|
1803
|
+
_firstAttribute: this._firstAttribute,
|
|
1804
|
+
_secondAttribute: this._secondAttribute,
|
|
1805
|
+
_kind: this._kind,
|
|
1806
|
+
_identifier: this._identifier,
|
|
1807
|
+
_variations: this._serializedVariations,
|
|
1808
|
+
_isActive: this._isActive
|
|
1809
|
+
};
|
|
1810
|
+
}
|
|
1811
|
+
});
|
|
1812
|
+
|
|
1813
|
+
// @endtype
|