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/MPSumFunctionLayout.m
Kim Wittenburg 4a3ea0cede Improved Model
Added Keyboard Selection Support
Added Mouse Selection Support
Added Keyboard Editing Support
Corrected Some Bugs
Abstracted the Layout System further
Added Functions Button (test)
2014-08-31 15:41:17 +02:00

157 lines
6.5 KiB
Objective-C

//
// 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;
}
- (CTLineRef)line
{
CTLineRef line = [self lineForPrivateCacheIndex:0 generator:^CTLineRef{
NSAttributedString *text =
[[NSAttributedString alloc] initWithString:@""
attributes:@{NSFontAttributeName: self.font}];
CFAttributedStringRef attributedString = CFBridgingRetain(text);
CTLineRef line = CTLineCreateWithAttributedString(attributedString);
CFRelease(attributedString); // TODO: Is this release appropriate
return line;
}];
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