// // MPLayout.m // MathPad // // Created by Kim Wittenburg on 11.08.14. // Copyright (c) 2014 Kim Wittenburg. All rights reserved. // #import "MPLayout.h" @interface MPLayout () // Querying Caches - (BOOL)hasCacheForElementAtIndex:(NSUInteger)index; // Storing Caches - (void)cacheObject:(id)anObject forElementAtIndex:(NSUInteger)index; - (void)ensureCacheSizeForIndex:(NSUInteger)index; @end @implementation MPLayout { NSMutableArray *_cache; NSBezierPath *_cachedPath; } #pragma mark Creation Methods - (id)init { self = [super init]; if (self) { _cache = [[NSMutableArray alloc] init]; _cachedPath = nil; _path = [[NSIndexPath alloc] init]; } return self; } - (id)initWithPath:(NSIndexPath *)path parent:(MPLayout *)parent { self = [self init]; if (self) { _path = path; _parent = parent; } return self; } #pragma Text System Objects - (MPExpressionStorage *)expressionStorage { return self.parent.expressionStorage; } - (NSLayoutManager *)layoutManager { return self.expressionStorage.layoutManager; } - (NSTextContainer *)textContainer { return self.expressionStorage.textContainer; } - (NSTextStorage *)textStorage { return self.expressionStorage.textStorage; } #pragma mark Cache Tree // Querying Caches - (BOOL)hasCacheForElementAtIndex:(NSUInteger)index { if (index >= _cache.count) { return NO; } return _cache[index] != MPNull; } - (id)cachableObjectForIndex:(NSUInteger)index generator:(id (^)())generator { if ([self hasCacheForElementAtIndex:index]) { return _cache[index]; } id object = generator(); [self cacheObject:object forElementAtIndex:index]; return object; } // Storing Caches - (void)cacheObject:(id)anObject forElementAtIndex:(NSUInteger)index { [self ensureCacheSizeForIndex:index]; _cache[index] = anObject; } - (void)ensureCacheSizeForIndex:(NSUInteger)index { while (index >= _cache.count) { [_cache addObject:MPNull]; } } // Clearing Caches - (void)clearCacheInRange:(NSRange)range replacementLength:(NSUInteger)replacementLength { NSMutableArray *placeholders = [[NSMutableArray alloc] initWithCapacity:replacementLength]; while (placeholders.count < replacementLength) { [placeholders addObject:MPNull]; } [_cache replaceObjectsInRange:range withObjectsFromArray:placeholders]; [self invalidate]; } - (void)invalidate { _cachedPath = nil; [self.parent invalidate]; } #pragma mark Calculation Methods - (NSSize)size { return self.bezierPath.bounds.size; } - (NSBezierPath *)bezierPath { if (!_cachedPath) { _cachedPath = [self generateBezierPath]; } return _cachedPath; } - (NSBezierPath *)bezierPathAtOrigin:(NSPoint)point { NSAffineTransform *transform = [NSAffineTransform transform]; [transform translateXBy:point.x yBy:point.y]; NSBezierPath *path = [NSBezierPath bezierPath]; [path appendBezierPath:self.bezierPath]; [path transformUsingAffineTransform:transform]; return path; } - (void)drawAtPoint:(NSPoint)point { NSBezierPath *path = [self bezierPathAtOrigin:point]; [path fill]; } @end