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:
Michael Schneider
2016-03-30 22:02:17 -07:00
parent 65b4961802
commit 4e757f0969
13 changed files with 281 additions and 309 deletions

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -32,9 +32,9 @@ ASEnvironmentHierarchyState ASEnvironmentHierarchyStateCreate()
};
}
ASEnvironmentCollection ASEnvironmentCollectionCreate()
ASEnvironmentState ASEnvironmentStateCreate()
{
return (ASEnvironmentCollection) {
return (ASEnvironmentState) {
.hierarchyState = ASEnvironmentHierarchyStateCreate(),
.layoutOptionsState = ASEnvironmentLayoutOptionsStateCreate()
};

View File

@@ -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.
*

View File

@@ -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

View File

@@ -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

View File

@@ -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);\
}\

View File

@@ -200,9 +200,9 @@
@implementation ASStackLayoutSpec (ASEnvironment)
- (BOOL)supportsMultipleChildren
- (BOOL)supportsUpwardPropagation
{
return YES;
return NO;
}
@end

View File

@@ -87,9 +87,9 @@
@implementation ASStaticLayoutSpec (ASEnvironment)
- (BOOL)supportsMultipleChildren
- (BOOL)supportsUpwardPropagation
{
return YES;
return NO;
}
@end

View File

@@ -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;

View File

@@ -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);
}
}

View File

@@ -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;
}