// // MPSumFunctionLayout.m // MathPad // // Created by Kim Wittenburg on 23.04.14. // Copyright (c) 2014 Kim Wittenburg. All rights reserved. // #import "MPSumFunctionLayout.h" #import "MPSumFunction.h" #import "NSIndexPath+MPAdditions.h" #define kSumFunctionStartExpressionOffset 3 #define kSumFunctionTargetExpressionOffset 0 #define kSumFunctionSumExpressionOffset 3 #define kSumFunctionTrailingOffset 5 @implementation MPSumFunctionLayout - (MPSumFunction *)sumFunction { return (MPSumFunction *)self.function; } - (NSUInteger)indexOfLeadingChild { return 2; } - (NSUInteger)indexOfTrailingChild { return 2; } - (CTLineRef)line { CTLineRef line = [self lineForPrivateCacheIndex:0 generator:^CTLineRef{ return [self createLineForString:@"∑"]; }]; return line; } - (NSRect)localLineBounds { NSRect lineBounds = CTLineGetBoundsWithOptions(self.line, 0); CGFloat width = MAX(MAX([self childLayoutAtIndex:0].bounds.size.width, [self childLayoutAtIndex:1].bounds.size.width), lineBounds.size.width); CGFloat xPosition = (width - lineBounds.size.width) / 2; return NSMakeRect(xPosition, lineBounds.origin.y, lineBounds.size.width, lineBounds.size.height); } - (NSPoint)offsetOfChildLayoutAtIndex:(NSUInteger)index { NSRect childBounds = [self childLayoutAtIndex:index].bounds; NSRect localLineBounds = [self localLineBounds]; NSPoint offset; if (index == 0) { // Start Expression offset.x = localLineBounds.origin.x + localLineBounds.size.width / 2 - childBounds.size.width / 2; offset.y = -kSumFunctionStartExpressionOffset - childBounds.size.height; } else if (index == 1) { // Target Expression offset.x = localLineBounds.origin.x + localLineBounds.size.width / 2 - childBounds.size.width / 2; offset.y = localLineBounds.size.height + kSumFunctionTargetExpressionOffset; } else { // Sum Expression MPLayout *startExpressionLayout = [self childLayoutAtIndex:0]; MPLayout *targetExpressionLayout = [self childLayoutAtIndex:1]; CGFloat sumWidth = MAX(MAX(localLineBounds.origin.x + localLineBounds.size.width, startExpressionLayout.bounds.size.width), targetExpressionLayout.bounds.size.width); offset.x = sumWidth + kSumFunctionSumExpressionOffset; offset.y = 0; } return offset; } - (NSIndexPath *)indexPathForMousePoint:(NSPoint)point { // A single index is used to communicate back wether the // selection should be before or after the function. // A 0 means before, a 1 means after. for (NSUInteger index = 0; index < self.function.numberOfChildren; index++) { MPLayout *childLayout = [self childLayoutAtIndex:index]; NSRect childBounds = childLayout.bounds; NSPoint childOffset = [self offsetOfChildLayoutAtIndex:index]; childBounds.origin.x += childOffset.x; childBounds.origin.y += childOffset.y; if (NSMouseInRect(point, childBounds, self.flipped)) { NSPoint pointInChild = NSMakePoint(point.x - childOffset.x, point.y - childOffset.y); NSIndexPath *subPath = [childLayout indexPathForMousePoint:pointInChild]; return [subPath indexPathByPreceedingIndex:index]; } } if (point.x < CTLineGetBoundsWithOptions(self.line, 0).size.width / 2) { return [NSIndexPath indexPathWithIndex:0]; } else { return [NSIndexPath indexPathWithIndex:1]; } } - (NSRect)generateBounds { NSRect lineBounds = CTLineGetBoundsWithOptions(self.line, 0); NSRect startExpressionBounds = [self childLayoutAtIndex:0].bounds; NSRect targetExpressionBounds = [self childLayoutAtIndex:1].bounds; NSRect sumExpressionBounds = [self childLayoutAtIndex:2].bounds; NSRect bounds = lineBounds; bounds.size.width = MAX(lineBounds.size.width, startExpressionBounds.size.width); bounds.size.height += startExpressionBounds.size.height + kSumFunctionStartExpressionOffset; bounds.size.width = MAX(bounds.size.width, targetExpressionBounds.size.width); bounds.size.height += targetExpressionBounds.size.height + kSumFunctionTargetExpressionOffset; bounds.size.width += kSumFunctionSumExpressionOffset + sumExpressionBounds.size.width; bounds.size.height = MAX(bounds.size.height, sumExpressionBounds.size.height); bounds.origin.y -= targetExpressionBounds.size.height + kSumFunctionStartExpressionOffset; bounds.size.width += kSumFunctionTrailingOffset; return bounds; } - (void)draw { // Get the current context CGContextRef context = (CGContextRef)[[NSGraphicsContext currentContext] graphicsPort]; // Set the text matrix CGContextSetTextMatrix(context, CGAffineTransformIdentity); // Draw the sum symbol CTLineRef line = [self line]; CFRetain(line); NSRect localLineBounds = [self localLineBounds]; CGContextSetTextPosition(context, localLineBounds.origin.x, 0); CTLineDraw(line, context); // Draw the start function MPLayout *startExpressionLayout = [self childLayoutAtIndex:0]; NSPoint startExpressionLocation = NSMakePoint(localLineBounds.origin.x + localLineBounds.size.width / 2, 0); startExpressionLocation.x -= startExpressionLayout.bounds.size.width / 2; startExpressionLocation.y -= startExpressionLayout.bounds.size.height + kSumFunctionStartExpressionOffset; [startExpressionLayout drawAtPoint:startExpressionLocation]; // Draw the target function MPLayout *targetExpressionLayout = [self childLayoutAtIndex:1]; NSPoint targetExpressionLocation = NSMakePoint(localLineBounds.origin.x + localLineBounds.size.width / 2, localLineBounds.size.height); targetExpressionLocation.x -= targetExpressionLayout.bounds.size.width / 2; targetExpressionLocation.y += kSumFunctionTargetExpressionOffset; [targetExpressionLayout drawAtPoint:targetExpressionLocation]; // Draw the sum function MPLayout *sumExpressionLayout = [self childLayoutAtIndex:2]; CGFloat sumWidth = MAX(MAX(localLineBounds.origin.x + localLineBounds.size.width, startExpressionLayout.bounds.size.width), targetExpressionLayout.bounds.size.width); sumWidth += kSumFunctionSumExpressionOffset; [sumExpressionLayout drawAtPoint:NSMakePoint(sumWidth, 0)]; CFRelease(line); } @end