mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-09-10 22:45:16 +00:00
* Initial commit for adding a size constraint to ASLayoutable's * Some more commits * Fix sample projects in extra/ * Remove preferredFrameSize test of ASEditableTextNode * Remove preferredFrameSize from examples_extra * Add deprecation warning to -[ASDisplayNode preferredFrameSize] * Add deprecation warning to -[ASDisplayNode measureWithSizeRange:] * Commit * Commit * Remove ASRelativeSizeRange * Make ASRelativeSize private * Adjust examples * Improve setting of -[ASLayoutable size] with points or fractions * Add ASWrapperLayoutSpec * Improve creation of ASRelativeDimension * Add `preferredFrameSize` back and add deprecated logging * Add `layoutSpecBlock` setter and getter and add locking for it * Add better documentation and fix macros to create ASRelativeDimension * Create new ASSizeRangeMake with just a CGSize as parameter * Update Kitten and Social App Layout example * Add layoutThatFits: and deprecate measure: * Rename ASRelativeDimension to ASDimension * Fix examples for ASDimension renaming * Remove fancy height and width setter * Fix ASDimension helper * Rename -[ASLayout layoutableObject] to -[ASLayout layoutable] * Update layout related methods and more clearer documentation around how to use it * Deprecate old ASLayout class constructors * Don't unnecessary recalculate layout if constrained or parent size did not change * Use shared pointer for ASDisplayNodeLayout * Fix rebase conflicts * Add documentation and move implementation in mm file of ASDisplayNodeLayout * Fix test errors * Rename ASSize to ASLayoutableSize * Address comments * Rename setSizeFromCGSize to setSizeWithCGSize * Improve inline functions in ASDimension * Fix rebase conflicts
218 lines
6.9 KiB
Plaintext
218 lines
6.9 KiB
Plaintext
//
|
|
// ASDimension.mm
|
|
// AsyncDisplayKit
|
|
//
|
|
// Copyright (c) 2014-present, Facebook, Inc. All rights reserved.
|
|
// This source code is licensed under the BSD-style license found in the
|
|
// LICENSE file in the root directory of this source tree. An additional grant
|
|
// of patent rights can be found in the PATENTS file in the same directory.
|
|
//
|
|
|
|
#import "ASDimension.h"
|
|
#import "ASAssert.h"
|
|
|
|
#pragma mark - ASDimension
|
|
|
|
ASDimension const ASDimensionAuto = {ASDimensionUnitAuto, 0};
|
|
|
|
ASOVERLOADABLE ASDimension ASDimensionMake(NSString *dimension)
|
|
{
|
|
// Handle empty string
|
|
if (dimension.length == 0) {
|
|
return ASDimensionMake(ASDimensionUnitPoints, 0.0);
|
|
}
|
|
|
|
// Handle points
|
|
NSUInteger pointsStringLocation = [dimension rangeOfString:@"pt"].location;
|
|
if (pointsStringLocation != NSNotFound) {
|
|
// Check if points is at the end and remove it
|
|
if (pointsStringLocation == (dimension.length-2)) {
|
|
dimension = [dimension substringToIndex:(dimension.length-2)];
|
|
return ASDimensionMake(ASDimensionUnitPoints, dimension.floatValue);
|
|
}
|
|
}
|
|
|
|
// Handle fraction
|
|
NSUInteger percentStringLocation = [dimension rangeOfString:@"%"].location;
|
|
if (percentStringLocation != NSNotFound) {
|
|
// Check if percent is at the end and remove it
|
|
if (percentStringLocation == (dimension.length-1)) {
|
|
dimension = [dimension substringToIndex:(dimension.length-1)];
|
|
return ASDimensionMake(ASDimensionUnitFraction, dimension.floatValue);
|
|
}
|
|
}
|
|
|
|
// Assert as parsing went wrong
|
|
ASDisplayNodeCAssert(NO, @"Parsing dimension failed for: %@", dimension);
|
|
return ASDimensionAuto;
|
|
}
|
|
|
|
NSString *NSStringFromASDimension(ASDimension dimension)
|
|
{
|
|
switch (dimension.unit) {
|
|
case ASDimensionUnitPoints:
|
|
return [NSString stringWithFormat:@"%.0fpt", dimension.value];
|
|
case ASDimensionUnitFraction:
|
|
return [NSString stringWithFormat:@"%.0f%%", dimension.value * 100.0];
|
|
case ASDimensionUnitAuto:
|
|
return @"Auto";
|
|
}
|
|
}
|
|
|
|
|
|
#pragma mark - NSNumber+ASDimension
|
|
|
|
@implementation NSNumber (ASDimension)
|
|
|
|
- (ASDimension)as_pointDimension
|
|
{
|
|
return ASDimensionMake(ASDimensionUnitPoints, self.floatValue);
|
|
}
|
|
|
|
- (ASDimension)as_fractionDimension
|
|
{
|
|
return ASDimensionMake(ASDimensionUnitFraction, self.floatValue);
|
|
}
|
|
|
|
@end
|
|
|
|
|
|
#pragma mark - ASRelativeSize
|
|
|
|
/**
|
|
* Expresses a size with relative dimensions. Only used for calculations internally in ASDimension.h
|
|
*/
|
|
typedef struct {
|
|
ASDimension width;
|
|
ASDimension height;
|
|
} ASRelativeSize;
|
|
|
|
ASDISPLAYNODE_INLINE ASRelativeSize ASRelativeSizeMake(ASDimension width, ASDimension height)
|
|
{
|
|
ASRelativeSize size;
|
|
size.width = width;
|
|
size.height = height;
|
|
return size;
|
|
}
|
|
|
|
// ** Resolve this relative size relative to a parent size. */
|
|
ASDISPLAYNODE_INLINE CGSize ASRelativeSizeResolveSize(ASRelativeSize relativeSize, CGSize parentSize, CGSize autoSize)
|
|
{
|
|
return CGSizeMake(ASDimensionResolve(relativeSize.width, parentSize.width, autoSize.width),
|
|
ASDimensionResolve(relativeSize.height, parentSize.height, autoSize.height));
|
|
}
|
|
|
|
// ** Returns a string formatted to contain the data from an ASRelativeSize. */
|
|
ASDISPLAYNODE_INLINE NSString *NSStringFromASRelativeSize(ASRelativeSize size)
|
|
{
|
|
return [NSString stringWithFormat:@"{%@, %@}",
|
|
NSStringFromASDimension(size.width),
|
|
NSStringFromASDimension(size.height)];
|
|
}
|
|
|
|
|
|
#pragma mark - ASLayoutableSize
|
|
|
|
NSString *NSStringFromASLayoutableSize(ASLayoutableSize size)
|
|
{
|
|
return [NSString stringWithFormat:
|
|
@"<ASLayoutableSize: exact=%@, min=%@, max=%@>",
|
|
NSStringFromASRelativeSize(ASRelativeSizeMake(size.width, size.height)),
|
|
NSStringFromASRelativeSize(ASRelativeSizeMake(size.minWidth, size.minHeight)),
|
|
NSStringFromASRelativeSize(ASRelativeSizeMake(size.maxWidth, size.maxHeight))];
|
|
}
|
|
|
|
ASDISPLAYNODE_INLINE void ASLayoutableSizeConstrain(CGFloat minVal, CGFloat exactVal, CGFloat maxVal, CGFloat *outMin, CGFloat *outMax)
|
|
{
|
|
NSCAssert(!isnan(minVal), @"minVal must not be NaN");
|
|
NSCAssert(!isnan(maxVal), @"maxVal must not be NaN");
|
|
// Avoid use of min/max primitives since they're harder to reason
|
|
// about in the presence of NaN (in exactVal)
|
|
// Follow CSS: min overrides max overrides exact.
|
|
|
|
// Begin with the min/max range
|
|
*outMin = minVal;
|
|
*outMax = maxVal;
|
|
if (maxVal <= minVal) {
|
|
// min overrides max and exactVal is irrelevant
|
|
*outMax = minVal;
|
|
return;
|
|
}
|
|
if (isnan(exactVal)) {
|
|
// no exact value, so leave as a min/max range
|
|
return;
|
|
}
|
|
if (exactVal > maxVal) {
|
|
// clip to max value
|
|
*outMin = maxVal;
|
|
} else if (exactVal < minVal) {
|
|
// clip to min value
|
|
*outMax = minVal;
|
|
} else {
|
|
// use exact value
|
|
*outMin = *outMax = exactVal;
|
|
}
|
|
}
|
|
|
|
ASSizeRange ASLayoutableSizeResolveAutoSize(ASLayoutableSize size, const CGSize parentSize, ASSizeRange autoASSizeRange)
|
|
{
|
|
CGSize resolvedExact = ASRelativeSizeResolveSize(ASRelativeSizeMake(size.width, size.height), parentSize, {NAN, NAN});
|
|
CGSize resolvedMin = ASRelativeSizeResolveSize(ASRelativeSizeMake(size.minWidth, size.minHeight), parentSize, autoASSizeRange.min);
|
|
CGSize resolvedMax = ASRelativeSizeResolveSize(ASRelativeSizeMake(size.maxWidth, size.maxHeight), parentSize, autoASSizeRange.max);
|
|
|
|
CGSize rangeMin, rangeMax;
|
|
ASLayoutableSizeConstrain(resolvedMin.width, resolvedExact.width, resolvedMax.width, &rangeMin.width, &rangeMax.width);
|
|
ASLayoutableSizeConstrain(resolvedMin.height, resolvedExact.height, resolvedMax.height, &rangeMin.height, &rangeMax.height);
|
|
return {rangeMin, rangeMax};
|
|
}
|
|
|
|
|
|
#pragma mark - ASSizeRange
|
|
|
|
struct _Range {
|
|
CGFloat min;
|
|
CGFloat max;
|
|
|
|
/**
|
|
Intersects another dimension range. If the other range does not overlap, this size range "wins" by returning a
|
|
single point within its own range that is closest to the non-overlapping range.
|
|
*/
|
|
_Range intersect(const _Range &other) const
|
|
{
|
|
CGFloat newMin = MAX(min, other.min);
|
|
CGFloat newMax = MIN(max, other.max);
|
|
if (newMin <= newMax) {
|
|
return {newMin, newMax};
|
|
} else {
|
|
// No intersection. If we're before the other range, return our max; otherwise our min.
|
|
if (min < other.min) {
|
|
return {max, max};
|
|
} else {
|
|
return {min, min};
|
|
}
|
|
}
|
|
}
|
|
};
|
|
|
|
ASSizeRange ASSizeRangeIntersect(ASSizeRange sizeRange, ASSizeRange otherSizeRange)
|
|
{
|
|
auto w = _Range({sizeRange.min.width, sizeRange.max.width}).intersect({otherSizeRange.min.width, otherSizeRange.max.width});
|
|
auto h = _Range({sizeRange.min.height, sizeRange.max.height}).intersect({otherSizeRange.min.height, otherSizeRange.max.height});
|
|
return {{w.min, h.min}, {w.max, h.max}};
|
|
}
|
|
|
|
NSString *NSStringFromASSizeRange(ASSizeRange sizeRange)
|
|
{
|
|
return [NSString stringWithFormat:@"<ASSizeRange: min=%@, max=%@>",
|
|
NSStringFromCGSize(sizeRange.min),
|
|
NSStringFromCGSize(sizeRange.max)];
|
|
}
|
|
|
|
|
|
#pragma mark - Deprecated
|
|
|
|
ASSizeRange ASSizeRangeMakeExactSize(CGSize size)
|
|
{
|
|
return ASSizeRangeMake(size);
|
|
}
|