mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2026-01-04 04:05:00 +00:00
General improvements
- Refactor naming of ASEnvironmentCollection to ASEnvironmentState - Remove struct pointers - Move ASEnvironmentStatePropagation to a enum class - Move merge functions to pure functions - Move ASLayoutOptionsForwarding and ASLayoutableExtensibility into ASLayoutSpec and ASDisplayNode - Remove ASLayoutableSetValuesForLayoutable and move into explicit classes (ASDisplayNode, ASTextNode)
This commit is contained in:
@@ -253,8 +253,7 @@ static ASDisplayNodeMethodOverrides GetASDisplayNodeMethodOverrides(Class c)
|
||||
_displaySentinel = [[ASSentinel alloc] init];
|
||||
_preferredFrameSize = CGSizeZero;
|
||||
|
||||
_environmentCollection = ASEnvironmentCollectionCreate();
|
||||
ASLayoutableSetValuesForLayoutable(self);
|
||||
_environmentState = ASEnvironmentStateCreate();
|
||||
}
|
||||
|
||||
- (id)init
|
||||
@@ -1703,6 +1702,10 @@ static NSInteger incrementIfFound(NSInteger i) {
|
||||
[self exitHierarchyState:stateToEnterOrExit];
|
||||
}
|
||||
}
|
||||
|
||||
if ([newSupernode supportsUpwardPropagation]) {
|
||||
ASEnvironmentStatePropagateUp(newSupernode, self.environmentState.layoutOptionsState);
|
||||
}
|
||||
}
|
||||
|
||||
// Track that a node will be displayed as part of the current node hierarchy.
|
||||
@@ -1857,8 +1860,8 @@ void recursivelyTriggerDisplayForLayer(CALayer *layer, BOOL shouldBlock)
|
||||
ASDN::MutexLocker l(_propertyLock);
|
||||
if (_methodOverrides & ASDisplayNodeMethodOverrideLayoutSpecThatFits) {
|
||||
ASLayoutSpec *layoutSpec = [self layoutSpecThatFits:constrainedSize];
|
||||
layoutSpec.isMutable = NO;
|
||||
layoutSpec.parent = self;
|
||||
layoutSpec.isMutable = NO;
|
||||
ASLayout *layout = [layoutSpec measureWithSizeRange:constrainedSize];
|
||||
// Make sure layoutableObject of the root layout is `self`, so that the flattened layout will be structurally correct.
|
||||
if (layout.layoutableObject != self) {
|
||||
@@ -1922,6 +1925,7 @@ void recursivelyTriggerDisplayForLayer(CALayer *layer, BOOL shouldBlock)
|
||||
ASDN::MutexLocker l(_propertyLock);
|
||||
if (! CGSizeEqualToSize(_preferredFrameSize, preferredFrameSize)) {
|
||||
_preferredFrameSize = preferredFrameSize;
|
||||
self.sizeRange = ASRelativeSizeRangeMake(ASRelativeSizeMakeWithCGSize(_preferredFrameSize), ASRelativeSizeMakeWithCGSize(_preferredFrameSize));
|
||||
[self invalidateCalculatedLayout];
|
||||
}
|
||||
}
|
||||
@@ -2672,9 +2676,14 @@ static const char *ASDisplayNodeDrawingPriorityKey = "ASDrawingPriority";
|
||||
|
||||
#pragma mark - ASEnvironment
|
||||
|
||||
- (ASEnvironmentCollection *)environmentCollection
|
||||
- (ASEnvironmentState)environmentState
|
||||
{
|
||||
return &_environmentCollection;
|
||||
return _environmentState;
|
||||
}
|
||||
|
||||
- (void)setEnvironmentState:(ASEnvironmentState)environmentState
|
||||
{
|
||||
_environmentState = environmentState;
|
||||
}
|
||||
|
||||
- (ASDisplayNode *)parent
|
||||
@@ -2682,53 +2691,18 @@ static const char *ASDisplayNodeDrawingPriorityKey = "ASDrawingPriority";
|
||||
return self.supernode;
|
||||
}
|
||||
|
||||
- (void)setParent:(ASDisplayNode *)parent
|
||||
{
|
||||
[self __setSupernode:parent];
|
||||
}
|
||||
|
||||
- (NSArray<ASDisplayNode *> *)children
|
||||
{
|
||||
return self.subnodes;
|
||||
}
|
||||
|
||||
- (BOOL)supportsMultipleChildren
|
||||
- (BOOL)supportsUpwardPropagation
|
||||
{
|
||||
return NO;
|
||||
return YES;
|
||||
}
|
||||
|
||||
|
||||
#pragma mark - ASLayoutableExtensibility
|
||||
|
||||
- (void)setLayoutOptionExtensionBool:(BOOL)value atIndex:(int)idx
|
||||
{
|
||||
_ASEnvironmentLayoutOptionsExtensionSetBoolAtIndex(self, idx, value);
|
||||
}
|
||||
|
||||
- (BOOL)layoutOptionExtensionBoolAtIndex:(int)idx
|
||||
{
|
||||
return _ASEnvironmentLayoutOptionsExtensionGetBoolAtIndex(self, idx);
|
||||
}
|
||||
|
||||
- (void)setLayoutOptionExtensionInteger:(NSInteger)value atIndex:(int)idx
|
||||
{
|
||||
_ASEnvironmentLayoutOptionsExtensionSetIntegerAtIndex(self, idx, value);
|
||||
}
|
||||
|
||||
- (NSInteger)layoutOptionExtensionIntegerAtIndex:(int)idx
|
||||
{
|
||||
return _ASEnvironmentLayoutOptionsExtensionGetIntegerAtIndex(self, idx);
|
||||
}
|
||||
|
||||
- (void)setLayoutOptionExtensionEdgeInsets:(UIEdgeInsets)value atIndex:(int)idx
|
||||
{
|
||||
_ASEnvironmentLayoutOptionsExtensionSetEdgeInsetsAtIndex(self, idx, value);
|
||||
}
|
||||
|
||||
- (UIEdgeInsets)layoutOptionExtensionEdgeInsetsAtIndex:(int)idx
|
||||
{
|
||||
return _ASEnvironmentLayoutOptionsExtensionGetEdgeInsetsAtIndex(self, idx);
|
||||
}
|
||||
ASEnvironmentLayoutOptionsForwarding
|
||||
ASEnvironmentLayoutExtensibilityForwarding
|
||||
|
||||
|
||||
#if TARGET_OS_TV
|
||||
|
||||
@@ -364,6 +364,12 @@ static NSArray *DefaultLinkAttributeNames = @[ NSLinkAttributeName ];
|
||||
}
|
||||
|
||||
_attributedString = ASCleanseAttributedStringOfCoreTextAttributes(attributedString);
|
||||
|
||||
if (_attributedString.length > 0) {
|
||||
CGFloat screenScale = ASScreenScale();
|
||||
self.ascender = round([[_attributedString attribute:NSFontAttributeName atIndex:0 effectiveRange:NULL] ascender] * screenScale)/screenScale;
|
||||
self.descender = round([[_attributedString attribute:NSFontAttributeName atIndex:_attributedString.length - 1 effectiveRange:NULL] descender] * screenScale)/screenScale;
|
||||
}
|
||||
|
||||
// Sync the truncation string with attributes from the updated _attributedString
|
||||
// Without this, the size calculation of the text with truncation applied will
|
||||
|
||||
@@ -62,13 +62,13 @@ typedef struct ASEnvironmentHierarchyState {
|
||||
extern ASEnvironmentHierarchyState ASEnvironmentHierarchyStateCreate();
|
||||
|
||||
|
||||
#pragma mark - ASEnvironmentCollection
|
||||
#pragma mark - ASEnvironmentState
|
||||
|
||||
typedef struct ASEnvironmentCollection {
|
||||
typedef struct ASEnvironmentState {
|
||||
struct ASEnvironmentHierarchyState hierarchyState;
|
||||
struct ASEnvironmentLayoutOptionsState layoutOptionsState;
|
||||
} ASEnvironmentCollection;
|
||||
extern ASEnvironmentCollection ASEnvironmentCollectionCreate();
|
||||
} ASEnvironmentState;
|
||||
extern ASEnvironmentState ASEnvironmentStateCreate();
|
||||
|
||||
ASDISPLAYNODE_EXTERN_C_END
|
||||
|
||||
@@ -77,26 +77,22 @@ ASDISPLAYNODE_EXTERN_C_END
|
||||
|
||||
/**
|
||||
* ASEnvironment allows objects that conform to the ASEnvironment protocol to be able to propagate specific States
|
||||
* defined in an ASEnvironmentCollection up and down the ASEnvironment tree. To be able to define how merges of
|
||||
* defined in an ASEnvironmentState up and down the ASEnvironment tree. To be able to define how merges of
|
||||
* States should happen, specific merge functions can be provided
|
||||
*/
|
||||
@protocol ASEnvironment <NSObject>
|
||||
|
||||
/// The environment collection of an object which class conforms to the ASEnvironment protocol
|
||||
- (ASEnvironmentCollection *)environmentCollection;
|
||||
- (ASEnvironmentState)environmentState;
|
||||
- (void)setEnvironmentState:(ASEnvironmentState)environmentState;
|
||||
|
||||
/// Returns the parent of an object which class conforms to the ASEnvironment protocol
|
||||
- (id<ASEnvironment>)parent;
|
||||
|
||||
/// Set the parent of an object which class conforms to the ASEnvironment protocol
|
||||
- (void)setParent:(id<ASEnvironment>)parent;
|
||||
- (id<ASEnvironment> _Nullable)parent;
|
||||
|
||||
/// Returns all children of an object which class conforms to the ASEnvironment protocol
|
||||
- (NSArray<id<ASEnvironment>> *)children;
|
||||
|
||||
// TODO: ASEnvironment: Find a better name. As in ASDisplayNode this returns NO which in theory is wrong as as
|
||||
// it supports multiple subnodes
|
||||
- (BOOL)supportsMultipleChildren;
|
||||
- (BOOL)supportsUpwardPropagation;
|
||||
|
||||
@end
|
||||
|
||||
|
||||
@@ -32,9 +32,9 @@ ASEnvironmentHierarchyState ASEnvironmentHierarchyStateCreate()
|
||||
};
|
||||
}
|
||||
|
||||
ASEnvironmentCollection ASEnvironmentCollectionCreate()
|
||||
ASEnvironmentState ASEnvironmentStateCreate()
|
||||
{
|
||||
return (ASEnvironmentCollection) {
|
||||
return (ASEnvironmentState) {
|
||||
.hierarchyState = ASEnvironmentHierarchyStateCreate(),
|
||||
.layoutOptionsState = ASEnvironmentLayoutOptionsStateCreate()
|
||||
};
|
||||
|
||||
@@ -25,6 +25,8 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
- (instancetype)init;
|
||||
|
||||
@property (nullable, nonatomic, weak) id<ASLayoutable> parent;
|
||||
|
||||
/**
|
||||
* Adds a child to this layout spec using a default identifier.
|
||||
*
|
||||
|
||||
@@ -25,9 +25,9 @@ static NSString * const kDefaultChildKey = @"kDefaultChildKey";
|
||||
static NSString * const kDefaultChildrenKey = @"kDefaultChildrenKey";
|
||||
|
||||
@interface ASLayoutSpec() {
|
||||
ASEnvironmentCollection _environmentCollection;
|
||||
ASEnvironmentState _environmentState;
|
||||
ASDN::RecursiveMutex _propertyLock;
|
||||
}
|
||||
@property (nonatomic, weak) id<ASLayoutable> parent;
|
||||
@property (nonatomic, strong) NSMutableDictionary *layoutChildren;
|
||||
@end
|
||||
|
||||
@@ -44,8 +44,7 @@ static NSString * const kDefaultChildrenKey = @"kDefaultChildrenKey";
|
||||
return nil;
|
||||
}
|
||||
_isMutable = YES;
|
||||
_environmentCollection = ASEnvironmentCollectionCreate();
|
||||
ASLayoutableSetValuesForLayoutable(self);
|
||||
_environmentState = ASEnvironmentStateCreate();
|
||||
|
||||
return self;
|
||||
}
|
||||
@@ -83,7 +82,9 @@ static NSString * const kDefaultChildrenKey = @"kDefaultChildrenKey";
|
||||
id<ASLayoutable> finalLayoutable = [child finalLayoutable];
|
||||
if (finalLayoutable != child) {
|
||||
// Copy layout options
|
||||
finalLayoutable.environmentCollection->layoutOptionsState = child.environmentCollection->layoutOptionsState;
|
||||
ASEnvironmentState environmentState = finalLayoutable.environmentState;
|
||||
environmentState.layoutOptionsState = child.environmentState.layoutOptionsState;
|
||||
finalLayoutable.environmentState = environmentState;
|
||||
return finalLayoutable;
|
||||
}
|
||||
}
|
||||
@@ -102,8 +103,8 @@ static NSString * const kDefaultChildrenKey = @"kDefaultChildrenKey";
|
||||
{
|
||||
_parent = parent;
|
||||
|
||||
if (![parent supportsMultipleChildren]) {
|
||||
ASEnvironmentStatePropagateUp(parent, self.environmentCollection->layoutOptionsState);
|
||||
if ([parent supportsUpwardPropagation]) {
|
||||
ASEnvironmentStatePropagateUp(parent, _environmentState.layoutOptionsState);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -148,48 +149,23 @@ static NSString * const kDefaultChildrenKey = @"kDefaultChildrenKey";
|
||||
|
||||
#pragma mark - ASEnvironment
|
||||
|
||||
- (ASEnvironmentCollection *)environmentCollection
|
||||
- (ASEnvironmentState)environmentState
|
||||
{
|
||||
return &_environmentCollection;
|
||||
return _environmentState;
|
||||
}
|
||||
|
||||
- (BOOL)supportsMultipleChildren
|
||||
- (void)setEnvironmentState:(ASEnvironmentState)environmentState
|
||||
{
|
||||
return NO;
|
||||
_environmentState = environmentState;
|
||||
}
|
||||
|
||||
|
||||
#pragma mark - ASLayoutableExtensibility
|
||||
|
||||
- (void)setLayoutOptionExtensionBool:(BOOL)value atIndex:(int)idx
|
||||
- (BOOL)supportsUpwardPropagation
|
||||
{
|
||||
_ASEnvironmentLayoutOptionsExtensionSetBoolAtIndex(self, idx, value);
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (BOOL)layoutOptionExtensionBoolAtIndex:(int)idx
|
||||
{
|
||||
return _ASEnvironmentLayoutOptionsExtensionGetBoolAtIndex(self, idx);
|
||||
}
|
||||
|
||||
- (void)setLayoutOptionExtensionInteger:(NSInteger)value atIndex:(int)idx
|
||||
{
|
||||
_ASEnvironmentLayoutOptionsExtensionSetIntegerAtIndex(self, idx, value);
|
||||
}
|
||||
|
||||
- (NSInteger)layoutOptionExtensionIntegerAtIndex:(int)idx
|
||||
{
|
||||
return _ASEnvironmentLayoutOptionsExtensionGetIntegerAtIndex(self, idx);
|
||||
}
|
||||
|
||||
- (void)setLayoutOptionExtensionEdgeInsets:(UIEdgeInsets)value atIndex:(int)idx
|
||||
{
|
||||
_ASEnvironmentLayoutOptionsExtensionSetEdgeInsetsAtIndex(self, idx, value);
|
||||
}
|
||||
|
||||
- (UIEdgeInsets)layoutOptionExtensionEdgeInsetsAtIndex:(int)idx
|
||||
{
|
||||
return _ASEnvironmentLayoutOptionsExtensionGetEdgeInsetsAtIndex(self, idx);
|
||||
}
|
||||
ASEnvironmentLayoutOptionsForwarding
|
||||
ASEnvironmentLayoutExtensibilityForwarding
|
||||
|
||||
@end
|
||||
|
||||
|
||||
@@ -81,183 +81,3 @@ void ASLayoutableClearCurrentContext()
|
||||
ASDN::StaticMutexLocker l(_layoutableContextLock);
|
||||
layoutableContextMap.erase(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Given an id<ASLayoutable>, set up layout options that are intrinsically defined by the layoutable.
|
||||
*
|
||||
* While this could be done in the layoutable object itself, moving the logic into this helper function
|
||||
* allows a custom spec to set up defaults without needing to alter the layoutable itself. For example,
|
||||
* image you were creating a custom baseline spec that needed ascender/descender. To assign values automatically
|
||||
* when a text node's attribute string is set, you would need to subclass ASTextNode and assign the values in the
|
||||
* override of setAttributeString. However, assigning the defaults via this function allows you to create a
|
||||
* custom spec without the need to create a subclass of ASTextNode.
|
||||
*
|
||||
* @param layoutable The layoutable object to inspect for default intrinsic layout option values
|
||||
*/
|
||||
void ASLayoutableSetValuesForLayoutable(id<ASLayoutable> layoutable)
|
||||
{
|
||||
//ASDN::MutexLocker l(_propertyLock);
|
||||
if ([layoutable isKindOfClass:[ASDisplayNode class]]) {
|
||||
ASDisplayNode *displayNode = (ASDisplayNode *)layoutable;
|
||||
displayNode.sizeRange = ASRelativeSizeRangeMake(ASRelativeSizeMakeWithCGSize(displayNode.preferredFrameSize), ASRelativeSizeMakeWithCGSize(displayNode.preferredFrameSize));
|
||||
|
||||
if ([layoutable isKindOfClass:[ASTextNode class]]) {
|
||||
ASTextNode *textNode = (ASTextNode *)layoutable;
|
||||
NSAttributedString *attributedString = textNode.attributedString;
|
||||
if (attributedString.length > 0) {
|
||||
CGFloat screenScale = ASScreenScale();
|
||||
textNode.ascender = round([[attributedString attribute:NSFontAttributeName atIndex:0 effectiveRange:NULL] ascender] * screenScale)/screenScale;
|
||||
textNode.descender = round([[attributedString attribute:NSFontAttributeName atIndex:attributedString.length - 1 effectiveRange:NULL] descender] * screenScale)/screenScale;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#pragma mark - ASLayoutOptionsForwarding
|
||||
|
||||
/**
|
||||
* Both an ASDisplayNode and an ASLayoutSpec conform to ASLayoutable. There are several properties
|
||||
* in ASLayoutable that are used when a node or spec is used in a layout spec.
|
||||
* These properties are provided for convenience, as they are forwards to the node or spec's
|
||||
* properties. Instead of duplicating the property forwarding in both classes, we
|
||||
* create a define that allows us to easily implement the forwards in one place.
|
||||
*
|
||||
* If you create a custom layout spec, we recommend this stragety if you decide to extend
|
||||
* ASDisplayNode and ASLayoutSpec to provide convenience properties for any options that your
|
||||
* layoutSpec may require.
|
||||
*/
|
||||
|
||||
#define ASEnvironmentLayoutOptionsForwarding \
|
||||
- (ASEnvironmentLayoutOptionsState *)layoutOptionsState\
|
||||
{\
|
||||
return &(self.environmentCollection->layoutOptionsState);\
|
||||
}\
|
||||
- (void)propagateUpLayoutOptionsState\
|
||||
{\
|
||||
id<ASEnvironment> parent = [self parent];\
|
||||
if (![parent supportsMultipleChildren]) {\
|
||||
ASEnvironmentStatePropagateUp(parent, self.environmentCollection->layoutOptionsState);\
|
||||
}\
|
||||
}\
|
||||
\
|
||||
- (CGFloat)spacingAfter\
|
||||
{\
|
||||
return self.layoutOptionsState->spacingAfter;\
|
||||
}\
|
||||
\
|
||||
- (void)setSpacingAfter:(CGFloat)spacingAfter\
|
||||
{\
|
||||
self.layoutOptionsState->spacingAfter = spacingAfter;\
|
||||
[self propagateUpLayoutOptionsState];\
|
||||
}\
|
||||
\
|
||||
- (CGFloat)spacingBefore\
|
||||
{\
|
||||
return self.layoutOptionsState->spacingBefore;\
|
||||
}\
|
||||
\
|
||||
- (void)setSpacingBefore:(CGFloat)spacingBefore\
|
||||
{\
|
||||
self.layoutOptionsState->spacingBefore = spacingBefore;\
|
||||
[self propagateUpLayoutOptionsState];\
|
||||
}\
|
||||
\
|
||||
- (BOOL)flexGrow\
|
||||
{\
|
||||
return self.layoutOptionsState->flexGrow;\
|
||||
}\
|
||||
\
|
||||
- (void)setFlexGrow:(BOOL)flexGrow\
|
||||
{\
|
||||
self.layoutOptionsState->flexGrow = flexGrow;\
|
||||
[self propagateUpLayoutOptionsState];\
|
||||
}\
|
||||
\
|
||||
- (BOOL)flexShrink\
|
||||
{\
|
||||
return self.layoutOptionsState->flexShrink;\
|
||||
}\
|
||||
\
|
||||
- (void)setFlexShrink:(BOOL)flexShrink\
|
||||
{\
|
||||
self.layoutOptionsState->flexShrink = flexShrink;\
|
||||
[self propagateUpLayoutOptionsState];\
|
||||
}\
|
||||
\
|
||||
- (ASRelativeDimension)flexBasis\
|
||||
{\
|
||||
return self.layoutOptionsState->flexBasis;\
|
||||
}\
|
||||
\
|
||||
- (void)setFlexBasis:(ASRelativeDimension)flexBasis\
|
||||
{\
|
||||
self.layoutOptionsState->flexBasis = flexBasis;\
|
||||
[self propagateUpLayoutOptionsState];\
|
||||
}\
|
||||
\
|
||||
- (ASStackLayoutAlignSelf)alignSelf\
|
||||
{\
|
||||
return self.layoutOptionsState->alignSelf;\
|
||||
}\
|
||||
\
|
||||
- (void)setAlignSelf:(ASStackLayoutAlignSelf)alignSelf\
|
||||
{\
|
||||
self.layoutOptionsState->alignSelf = alignSelf;\
|
||||
[self propagateUpLayoutOptionsState];\
|
||||
}\
|
||||
\
|
||||
- (CGFloat)ascender\
|
||||
{\
|
||||
return self.layoutOptionsState->ascender;\
|
||||
}\
|
||||
\
|
||||
- (void)setAscender:(CGFloat)ascender\
|
||||
{\
|
||||
self.layoutOptionsState->ascender = ascender;\
|
||||
[self propagateUpLayoutOptionsState];\
|
||||
}\
|
||||
\
|
||||
- (CGFloat)descender\
|
||||
{\
|
||||
return self.layoutOptionsState->descender;\
|
||||
}\
|
||||
\
|
||||
- (void)setDescender:(CGFloat)descender\
|
||||
{\
|
||||
self.layoutOptionsState->descender = descender;\
|
||||
[self propagateUpLayoutOptionsState];\
|
||||
}\
|
||||
\
|
||||
- (ASRelativeSizeRange)sizeRange\
|
||||
{\
|
||||
return self.layoutOptionsState->sizeRange;\
|
||||
}\
|
||||
\
|
||||
- (void)setSizeRange:(ASRelativeSizeRange)sizeRange\
|
||||
{\
|
||||
self.layoutOptionsState->sizeRange = sizeRange;\
|
||||
[self propagateUpLayoutOptionsState];\
|
||||
}\
|
||||
\
|
||||
- (CGPoint)layoutPosition\
|
||||
{\
|
||||
return self.layoutOptionsState->layoutPosition;\
|
||||
}\
|
||||
\
|
||||
- (void)setLayoutPosition:(CGPoint)layoutPosition\
|
||||
{\
|
||||
self.layoutOptionsState->layoutPosition = layoutPosition;\
|
||||
[self propagateUpLayoutOptionsState];\
|
||||
}\
|
||||
|
||||
|
||||
@implementation ASDisplayNode(ASLayoutOptionsForwarding)
|
||||
ASEnvironmentLayoutOptionsForwarding
|
||||
@end
|
||||
|
||||
@implementation ASLayoutSpec(ASLayoutOptionsForwarding)
|
||||
ASEnvironmentLayoutOptionsForwarding
|
||||
@end
|
||||
|
||||
|
||||
@@ -34,8 +34,6 @@ extern struct ASLayoutableContext ASLayoutableGetCurrentContext();
|
||||
|
||||
extern void ASLayoutableClearCurrentContext();
|
||||
|
||||
extern void ASLayoutableSetValuesForLayoutable(id<ASLayoutable> layoutable);
|
||||
|
||||
/**
|
||||
* The base protocol for ASLayoutable. Generally the methods/properties in this class do not need to be
|
||||
* called by the end user and are only called internally. However, there may be a case where the methods are useful.
|
||||
@@ -62,3 +60,201 @@ extern void ASLayoutableSetValuesForLayoutable(id<ASLayoutable> layoutable);
|
||||
@property (nonatomic, assign) BOOL isFinalLayoutable;
|
||||
|
||||
@end
|
||||
|
||||
|
||||
#pragma mark - ASLayoutOptionsForwarding
|
||||
|
||||
/**
|
||||
* Both an ASDisplayNode and an ASLayoutSpec conform to ASLayoutable. There are several properties
|
||||
* in ASLayoutable that are used when a node or spec is used in a layout spec.
|
||||
* These properties are provided for convenience, as they are forwards to the node or spec's
|
||||
* properties. Instead of duplicating the property forwarding in both classes, we
|
||||
* create a define that allows us to easily implement the forwards in one place.
|
||||
*
|
||||
* If you create a custom layout spec, we recommend this stragety if you decide to extend
|
||||
* ASDisplayNode and ASLayoutSpec to provide convenience properties for any options that your
|
||||
* layoutSpec may require.
|
||||
*/
|
||||
|
||||
#define ASEnvironmentLayoutOptionsForwarding \
|
||||
- (void)propagateUpLayoutOptionsState\
|
||||
{\
|
||||
id<ASEnvironment> parent = [self parent];\
|
||||
if ([parent supportsUpwardPropagation]) {\
|
||||
ASEnvironmentStatePropagateUp(parent, _environmentState.layoutOptionsState);\
|
||||
}\
|
||||
}\
|
||||
\
|
||||
- (CGFloat)spacingAfter\
|
||||
{\
|
||||
ASDN::MutexLocker l(_propertyLock);\
|
||||
return _environmentState.layoutOptionsState.spacingAfter;\
|
||||
}\
|
||||
\
|
||||
- (void)setSpacingAfter:(CGFloat)spacingAfter\
|
||||
{\
|
||||
_propertyLock.lock();\
|
||||
_environmentState.layoutOptionsState.spacingAfter = spacingAfter;\
|
||||
[self propagateUpLayoutOptionsState];\
|
||||
_propertyLock.unlock();\
|
||||
}\
|
||||
\
|
||||
- (CGFloat)spacingBefore\
|
||||
{\
|
||||
ASDN::MutexLocker l(_propertyLock);\
|
||||
return _environmentState.layoutOptionsState.spacingBefore;\
|
||||
}\
|
||||
\
|
||||
- (void)setSpacingBefore:(CGFloat)spacingBefore\
|
||||
{\
|
||||
_propertyLock.lock();\
|
||||
_environmentState.layoutOptionsState.spacingBefore = spacingBefore;\
|
||||
[self propagateUpLayoutOptionsState];\
|
||||
_propertyLock.unlock();\
|
||||
}\
|
||||
\
|
||||
- (BOOL)flexGrow\
|
||||
{\
|
||||
ASDN::MutexLocker l(_propertyLock);\
|
||||
return _environmentState.layoutOptionsState.flexGrow;\
|
||||
}\
|
||||
\
|
||||
- (void)setFlexGrow:(BOOL)flexGrow\
|
||||
{\
|
||||
_propertyLock.lock();\
|
||||
_environmentState.layoutOptionsState.flexGrow = flexGrow;\
|
||||
[self propagateUpLayoutOptionsState];\
|
||||
_propertyLock.unlock();\
|
||||
}\
|
||||
\
|
||||
- (BOOL)flexShrink\
|
||||
{\
|
||||
ASDN::MutexLocker l(_propertyLock);\
|
||||
return _environmentState.layoutOptionsState.flexShrink;\
|
||||
}\
|
||||
\
|
||||
- (void)setFlexShrink:(BOOL)flexShrink\
|
||||
{\
|
||||
_propertyLock.lock();\
|
||||
_environmentState.layoutOptionsState.flexShrink = flexShrink;\
|
||||
[self propagateUpLayoutOptionsState];\
|
||||
_propertyLock.unlock();\
|
||||
}\
|
||||
\
|
||||
- (ASRelativeDimension)flexBasis\
|
||||
{\
|
||||
ASDN::MutexLocker l(_propertyLock);\
|
||||
return _environmentState.layoutOptionsState.flexBasis;\
|
||||
}\
|
||||
\
|
||||
- (void)setFlexBasis:(ASRelativeDimension)flexBasis\
|
||||
{\
|
||||
_propertyLock.lock();\
|
||||
_environmentState.layoutOptionsState.flexBasis = flexBasis;\
|
||||
[self propagateUpLayoutOptionsState];\
|
||||
_propertyLock.unlock();\
|
||||
}\
|
||||
\
|
||||
- (ASStackLayoutAlignSelf)alignSelf\
|
||||
{\
|
||||
ASDN::MutexLocker l(_propertyLock);\
|
||||
return _environmentState.layoutOptionsState.alignSelf;\
|
||||
}\
|
||||
\
|
||||
- (void)setAlignSelf:(ASStackLayoutAlignSelf)alignSelf\
|
||||
{\
|
||||
_propertyLock.lock();\
|
||||
_environmentState.layoutOptionsState.alignSelf = alignSelf;\
|
||||
[self propagateUpLayoutOptionsState];\
|
||||
_propertyLock.unlock();\
|
||||
}\
|
||||
\
|
||||
- (CGFloat)ascender\
|
||||
{\
|
||||
ASDN::MutexLocker l(_propertyLock);\
|
||||
return _environmentState.layoutOptionsState.ascender;\
|
||||
}\
|
||||
\
|
||||
- (void)setAscender:(CGFloat)ascender\
|
||||
{\
|
||||
_propertyLock.lock();\
|
||||
_environmentState.layoutOptionsState.ascender = ascender;\
|
||||
[self propagateUpLayoutOptionsState];\
|
||||
_propertyLock.unlock();\
|
||||
}\
|
||||
\
|
||||
- (CGFloat)descender\
|
||||
{\
|
||||
ASDN::MutexLocker l(_propertyLock);\
|
||||
return _environmentState.layoutOptionsState.descender;\
|
||||
}\
|
||||
\
|
||||
- (void)setDescender:(CGFloat)descender\
|
||||
{\
|
||||
_propertyLock.lock();\
|
||||
_environmentState.layoutOptionsState.descender = descender;\
|
||||
[self propagateUpLayoutOptionsState];\
|
||||
_propertyLock.unlock();\
|
||||
}\
|
||||
\
|
||||
- (ASRelativeSizeRange)sizeRange\
|
||||
{\
|
||||
ASDN::MutexLocker l(_propertyLock);\
|
||||
return _environmentState.layoutOptionsState.sizeRange;\
|
||||
}\
|
||||
\
|
||||
- (void)setSizeRange:(ASRelativeSizeRange)sizeRange\
|
||||
{\
|
||||
_propertyLock.lock();\
|
||||
_environmentState.layoutOptionsState.sizeRange = sizeRange;\
|
||||
[self propagateUpLayoutOptionsState];\
|
||||
_propertyLock.unlock();\
|
||||
}\
|
||||
\
|
||||
- (CGPoint)layoutPosition\
|
||||
{\
|
||||
ASDN::MutexLocker l(_propertyLock);\
|
||||
return _environmentState.layoutOptionsState.layoutPosition;\
|
||||
}\
|
||||
\
|
||||
- (void)setLayoutPosition:(CGPoint)layoutPosition\
|
||||
{\
|
||||
_propertyLock.lock();\
|
||||
_environmentState.layoutOptionsState.layoutPosition = layoutPosition;\
|
||||
[self propagateUpLayoutOptionsState];\
|
||||
_propertyLock.unlock();\
|
||||
}\
|
||||
|
||||
|
||||
#pragma mark - ASLayoutableExtensibility
|
||||
|
||||
#define ASEnvironmentLayoutExtensibilityForwarding \
|
||||
- (void)setLayoutOptionExtensionBool:(BOOL)value atIndex:(int)idx\
|
||||
{\
|
||||
_ASEnvironmentLayoutOptionsExtensionSetBoolAtIndex(self, idx, value);\
|
||||
}\
|
||||
\
|
||||
- (BOOL)layoutOptionExtensionBoolAtIndex:(int)idx\
|
||||
{\
|
||||
return _ASEnvironmentLayoutOptionsExtensionGetBoolAtIndex(self, idx);\
|
||||
}\
|
||||
\
|
||||
- (void)setLayoutOptionExtensionInteger:(NSInteger)value atIndex:(int)idx\
|
||||
{\
|
||||
_ASEnvironmentLayoutOptionsExtensionSetIntegerAtIndex(self, idx, value);\
|
||||
}\
|
||||
\
|
||||
- (NSInteger)layoutOptionExtensionIntegerAtIndex:(int)idx\
|
||||
{\
|
||||
return _ASEnvironmentLayoutOptionsExtensionGetIntegerAtIndex(self, idx);\
|
||||
}\
|
||||
\
|
||||
- (void)setLayoutOptionExtensionEdgeInsets:(UIEdgeInsets)value atIndex:(int)idx\
|
||||
{\
|
||||
_ASEnvironmentLayoutOptionsExtensionSetEdgeInsetsAtIndex(self, idx, value);\
|
||||
}\
|
||||
\
|
||||
- (UIEdgeInsets)layoutOptionExtensionEdgeInsetsAtIndex:(int)idx\
|
||||
{\
|
||||
return _ASEnvironmentLayoutOptionsExtensionGetEdgeInsetsAtIndex(self, idx);\
|
||||
}\
|
||||
|
||||
@@ -200,9 +200,9 @@
|
||||
|
||||
@implementation ASStackLayoutSpec (ASEnvironment)
|
||||
|
||||
- (BOOL)supportsMultipleChildren
|
||||
- (BOOL)supportsUpwardPropagation
|
||||
{
|
||||
return YES;
|
||||
return NO;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -87,9 +87,9 @@
|
||||
|
||||
@implementation ASStaticLayoutSpec (ASEnvironment)
|
||||
|
||||
- (BOOL)supportsMultipleChildren
|
||||
- (BOOL)supportsUpwardPropagation
|
||||
{
|
||||
return YES;
|
||||
return NO;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -97,7 +97,7 @@ FOUNDATION_EXPORT NSString * const ASRenderingEngineDidDisplayNodesScheduledBefo
|
||||
// This is the desired contentsScale, not the scale at which the layer's contents should be displayed
|
||||
CGFloat _contentsScaleForDisplay;
|
||||
|
||||
ASEnvironmentCollection _environmentCollection;
|
||||
ASEnvironmentState _environmentState;
|
||||
ASLayout *_layout;
|
||||
|
||||
ASSizeRange _constrainedSize;
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
enum ASEnvironmentStatePropagation { DOWN, UP };
|
||||
enum class ASEnvironmentStatePropagation { DOWN, UP };
|
||||
|
||||
|
||||
#pragma mark - Set and get extensible values for layout options
|
||||
@@ -36,34 +36,34 @@ void ASEnvironmentPerformBlockOnObjectAndParents(id<ASEnvironment> object, void(
|
||||
#pragma mark - Merging
|
||||
|
||||
static const struct ASEnvironmentLayoutOptionsState ASEnvironmentDefaultLayoutOptionsState = {};
|
||||
void ASEnvironmentMergeObjectAndState(id<ASEnvironment> object, ASEnvironmentLayoutOptionsState& state, ASEnvironmentStatePropagation propagation);
|
||||
ASEnvironmentState ASEnvironmentMergeObjectAndState(ASEnvironmentState environmentState, ASEnvironmentLayoutOptionsState state, ASEnvironmentStatePropagation propagation);
|
||||
|
||||
|
||||
static const struct ASEnvironmentHierarchyState ASEnvironmentDefaultHierarchyState = {};
|
||||
void ASEnvironmentMergeObjectAndState(id<ASEnvironment> object, ASEnvironmentHierarchyState& state, ASEnvironmentStatePropagation propagation);
|
||||
ASEnvironmentState ASEnvironmentMergeObjectAndState(ASEnvironmentState environmentState, ASEnvironmentHierarchyState state, ASEnvironmentStatePropagation propagation);
|
||||
|
||||
|
||||
#pragma mark - Propagation
|
||||
|
||||
template <typename ASEnvironmentStateType>
|
||||
void ASEnvironmentStatePropagateDown(id<ASEnvironment> object, ASEnvironmentStateType& state) {
|
||||
void ASEnvironmentStatePropagateDown(id<ASEnvironment> object, ASEnvironmentStateType state) {
|
||||
ASEnvironmentPerformBlockOnObjectAndChildren(object, ^(id<ASEnvironment> node) {
|
||||
ASEnvironmentMergeObjectAndState(object, state, DOWN);
|
||||
object.environmentState = ASEnvironmentMergeObjectAndState(object.environmentState, state, ASEnvironmentStatePropagation::DOWN);
|
||||
});
|
||||
}
|
||||
|
||||
template <typename ASEnvironmentStateType>
|
||||
void ASEnvironmentStatePropagateUp(id<ASEnvironment> object, ASEnvironmentStateType& state) {
|
||||
void ASEnvironmentStatePropagateUp(id<ASEnvironment> object, ASEnvironmentStateType state) {
|
||||
ASEnvironmentPerformBlockOnObjectAndParents(object, ^(id<ASEnvironment> node) {
|
||||
ASEnvironmentMergeObjectAndState(object, state, UP);
|
||||
object.environmentState = ASEnvironmentMergeObjectAndState(object.environmentState, state, ASEnvironmentStatePropagation::UP);
|
||||
});
|
||||
}
|
||||
|
||||
template <typename ASEnvironmentStateType>
|
||||
void ASEnvironmentStateApply(id<ASEnvironment> object, ASEnvironmentStateType& state, ASEnvironmentStatePropagation propagate) {
|
||||
if (propagate == DOWN) {
|
||||
if (propagate == ASEnvironmentStatePropagation::DOWN) {
|
||||
ASEnvironmentStatePropagateUp(object, state);
|
||||
} else if (propagate == UP) {
|
||||
} else if (propagate == ASEnvironmentStatePropagation::UP) {
|
||||
ASEnvironmentStatePropagateDown(object, state);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -52,65 +52,66 @@ void _ASEnvironmentLayoutOptionsExtensionSetBoolAtIndex(id<ASEnvironment> object
|
||||
{
|
||||
NSCAssert(idx < kMaxEnvironmentStateBoolExtensions, @"Setting index outside of max bool extensions space");
|
||||
|
||||
ASEnvironmentStateExtensions extension = object.environmentCollection->layoutOptionsState._extensions;
|
||||
ASEnvironmentStateExtensions extension = object.environmentState.layoutOptionsState._extensions;
|
||||
extension.boolExtensions[idx] = value;
|
||||
object.environmentCollection->layoutOptionsState._extensions = extension;
|
||||
object.environmentState.layoutOptionsState._extensions = extension;
|
||||
}
|
||||
|
||||
BOOL _ASEnvironmentLayoutOptionsExtensionGetBoolAtIndex(id<ASEnvironment> object, int idx)
|
||||
{
|
||||
NSCAssert(idx < kMaxEnvironmentStateBoolExtensions, @"Accessing index outside of max bool extensions space");
|
||||
return object.environmentCollection->layoutOptionsState._extensions.boolExtensions[idx];
|
||||
return object.environmentState.layoutOptionsState._extensions.boolExtensions[idx];
|
||||
}
|
||||
|
||||
void _ASEnvironmentLayoutOptionsExtensionSetIntegerAtIndex(id<ASEnvironment> object, int idx, NSInteger value)
|
||||
{
|
||||
NSCAssert(idx < kMaxEnvironmentStateIntegerExtensions, @"Setting index outside of max integer extensions space");
|
||||
|
||||
ASEnvironmentStateExtensions extension = object.environmentCollection->layoutOptionsState._extensions;
|
||||
ASEnvironmentStateExtensions extension = object.environmentState.layoutOptionsState._extensions;
|
||||
extension.integerExtensions[idx] = value;
|
||||
object.environmentCollection->layoutOptionsState._extensions = extension;
|
||||
object.environmentState.layoutOptionsState._extensions = extension;
|
||||
}
|
||||
|
||||
NSInteger _ASEnvironmentLayoutOptionsExtensionGetIntegerAtIndex(id<ASEnvironment> object, int idx)
|
||||
{
|
||||
NSCAssert(idx < kMaxEnvironmentStateIntegerExtensions, @"Accessing index outside of max integer extensions space");
|
||||
return object.environmentCollection->layoutOptionsState._extensions.integerExtensions[idx];
|
||||
return object.environmentState.layoutOptionsState._extensions.integerExtensions[idx];
|
||||
}
|
||||
|
||||
void _ASEnvironmentLayoutOptionsExtensionSetEdgeInsetsAtIndex(id<ASEnvironment> object, int idx, UIEdgeInsets value)
|
||||
{
|
||||
NSCAssert(idx < kMaxEnvironmentStateEdgeInsetExtensions, @"Setting index outside of max edge insets extensions space");
|
||||
|
||||
ASEnvironmentStateExtensions extension = object.environmentCollection->layoutOptionsState._extensions;
|
||||
ASEnvironmentStateExtensions extension = object.environmentState.layoutOptionsState._extensions;
|
||||
extension.edgeInsetsExtensions[idx] = value;
|
||||
object.environmentCollection->layoutOptionsState._extensions = extension;
|
||||
object.environmentState.layoutOptionsState._extensions = extension;
|
||||
}
|
||||
|
||||
UIEdgeInsets _ASEnvironmentLayoutOptionsExtensionGetEdgeInsetsAtIndex(id<ASEnvironment> object, int idx)
|
||||
{
|
||||
NSCAssert(idx < kMaxEnvironmentStateEdgeInsetExtensions, @"Accessing index outside of max edge insets extensions space");
|
||||
return object.environmentCollection->layoutOptionsState._extensions.edgeInsetsExtensions[idx];
|
||||
return object.environmentState.layoutOptionsState._extensions.edgeInsetsExtensions[idx];
|
||||
}
|
||||
|
||||
|
||||
#pragma mark - Merging functions for states
|
||||
|
||||
void ASEnvironmentMergeObjectAndState(id<ASEnvironment> object, ASEnvironmentHierarchyState& state, ASEnvironmentStatePropagation propagation) {
|
||||
ASEnvironmentState ASEnvironmentMergeObjectAndState(ASEnvironmentState environmentState, ASEnvironmentHierarchyState state, ASEnvironmentStatePropagation propagation) {
|
||||
// Merge object and hierarchy state
|
||||
LOG(@"Merge object and state: %@ - ASEnvironmentHierarchyState", object);
|
||||
return environmentState;
|
||||
}
|
||||
|
||||
void ASEnvironmentMergeObjectAndState(id<ASEnvironment> object, ASEnvironmentLayoutOptionsState& state, ASEnvironmentStatePropagation propagation) {
|
||||
ASEnvironmentState ASEnvironmentMergeObjectAndState(ASEnvironmentState environmentState, ASEnvironmentLayoutOptionsState state, ASEnvironmentStatePropagation propagation) {
|
||||
// Merge object and layout options state
|
||||
LOG(@"Merge object and state: %@ - ASEnvironmentLayoutOptionsState", object);
|
||||
|
||||
// Support propagate up
|
||||
if (propagation == UP) {
|
||||
if (propagation == ASEnvironmentStatePropagation::UP) {
|
||||
|
||||
// Object is the parent and the state is the state of the child
|
||||
const ASEnvironmentLayoutOptionsState defaultState = ASEnvironmentDefaultLayoutOptionsState;
|
||||
ASEnvironmentLayoutOptionsState parentState = object.environmentCollection->layoutOptionsState;
|
||||
ASEnvironmentLayoutOptionsState parentState = environmentState.layoutOptionsState;
|
||||
|
||||
// For every field check if the parent value is equal to the default than propegate up the child value to
|
||||
// the parent
|
||||
@@ -143,7 +144,8 @@ void ASEnvironmentMergeObjectAndState(id<ASEnvironment> object, ASEnvironmentLay
|
||||
parentState.layoutPosition = defaultState.layoutPosition;
|
||||
}
|
||||
|
||||
object.environmentCollection->layoutOptionsState = parentState;
|
||||
environmentState.layoutOptionsState = parentState;
|
||||
}
|
||||
|
||||
return environmentState;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user