Archived
1
This repository has been archived on 2022-08-08. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
mathpad/MathPad/MPLayout.m
2014-10-13 23:53:04 +02:00

200 lines
4.9 KiB
Objective-C

//
// MPLayout.m
// MathPad
//
// Created by Kim Wittenburg on 11.08.14.
// Copyright (c) 2014 Kim Wittenburg. All rights reserved.
//
#import "MPLayout.h"
#import "MPRangePath.h"
#import "NSIndexPath+MPAdditions.h"
@interface MPLayout ()
// Querying and Storing Caches
- (BOOL)hasCacheForElementAtIndex:(NSUInteger)index;
- (void)ensureCacheSizeForIndex:(NSUInteger)index;
@end
@implementation MPLayout {
NSMutableArray *_cache;
NSRect _cachedBounds;
}
#pragma mark Creation Methods
- (id)init
{
self = [super init];
if (self) {
_cache = [[NSMutableArray alloc] init];
_cachedBounds = NSZeroRect;
}
return self;
}
- (instancetype)initWithParent:(MPLayout *)parent
{
self = [self init];
if (self) {
_parent = parent;
}
return self;
}
#pragma mark Properties
- (NSFont *)font
{
return self.usesSmallSize ? self.smallFont : self.normalFont;
}
- (CGFloat)fontSize
{
return self.usesSmallSize ? self.smallFontSize : self.normalFontSize;
}
- (NSFont *)normalFont
{
return [NSFont fontWithName:@"CMU Serif"
size:self.fontSize];
}
- (CGFloat)normalFontSize
{
return 18.0;
}
- (NSFont *)smallFont
{
return [NSFont fontWithName:@"CMU Serif"
size:self.smallFontSize];
}
- (CGFloat)smallFontSize
{
return 12.0;
}
#pragma mark Cache Tree
// Querying and Storing 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 ensureCacheSizeForIndex:index];
_cache[index] = object;
return object;
}
- (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
{
_cachedBounds = NSZeroRect;
[self.parent invalidate];
}
- (MPLayout *)childLayoutAtIndexPath:(NSIndexPath *)indexPath
{
if (indexPath.length == 0) {
return self;
}
MPLayout *child = [self childLayoutAtIndex:indexPath.firstIndex];
return [child childLayoutAtIndexPath:[indexPath indexPathByRemovingFirstIndex]];
}
#pragma mark Calculation and Drawing Methods
- (CTLineRef)createLineForString:(NSString *)aString
{
return [self createLineForString:aString
usingFont:self.font];
}
- (CTLineRef)createLineForString:(NSString *)aString
usingFont:(NSFont *)font
{
NSAttributedString *text = [[NSAttributedString alloc] initWithString:aString
attributes:@{NSFontAttributeName: font}];
CFAttributedStringRef attributedString = CFBridgingRetain(text);
CTLineRef line = CTLineCreateWithAttributedString(attributedString);
CFRelease(attributedString); // TODO: Is this release appropriate?
return line;
}
- (NSRect)bounds
{
if (NSEqualRects(_cachedBounds, NSZeroRect)) {
_cachedBounds = [self generateBounds];
}
return _cachedBounds;
}
- (NSRect)boundingRectForRangePath:(MPRangePath *)rangePath
{
if (rangePath.location.length == 1) {
return [self boundingRectForRange:rangePath.rangeAtLastIndex];
}
NSUInteger nextIndex = [rangePath.location indexAtPosition:0];
NSIndexPath *newLocation = [rangePath.location indexPathByRemovingFirstIndex];
MPRangePath *newRangePath = [[MPRangePath alloc] initWithLocation:newLocation length:rangePath.length];
NSRect bounds = [[self childLayoutAtIndex:nextIndex] boundingRectForRangePath:newRangePath];
NSPoint offset = [self offsetOfChildLayoutAtIndex:nextIndex];
bounds.origin = NSMakePoint(bounds.origin.x + offset.x, bounds.origin.y + offset.y);
return bounds;
}
- (BOOL)drawsChildrenManually
{
return NO;
}
- (void)drawAtPoint:(NSPoint)point
{
NSAffineTransform *transform = [NSAffineTransform transform];
[transform translateXBy:point.x
yBy:point.y];
[transform concat];
[self draw];
if (!self.drawsChildrenManually) {
for (NSUInteger index = 0; index < [self numberOfChildren]; index++) {
MPLayout *childLayout = [self childLayoutAtIndex:index];
NSPoint offset = [self offsetOfChildLayoutAtIndex:index];
[childLayout drawAtPoint:offset];
}
}
[transform invert];
[transform concat];
}
@end