Archived
1

Fundamental Redesign of the View and Controller

This commit is contained in:
Kim Wittenburg
2014-08-22 00:54:13 +02:00
parent a37d587e1f
commit c024886241
12 changed files with 255 additions and 150 deletions

View File

@@ -9,45 +9,38 @@
#import "MPExpressionLayout.h"
#import "MPFunctionLayout.h"
@interface MPExpressionLayout (MPPathGeneration)
- (NSBezierPath *)bezierPathForChildAtIndex:(NSUInteger)index;
- (NSBezierPath *)generateBezierPathForString:(NSString *)aString;
@interface MPExpressionLayout (MPLineGeneration)
- (CTLineRef)lineForElementAtIndex:(NSUInteger)index;
- (CTLineRef)createLineForString:(NSString *)aString;
@end
@implementation MPExpressionLayout (MPPathGeneration)
@implementation MPExpressionLayout (MPLineGeneration)
- (NSBezierPath *)bezierPathForChildAtIndex:(NSUInteger)index
- (CTLineRef)lineForElementAtIndex:(NSUInteger)index
{
id symbol = [self.expression elementAtIndex:index];
if ([symbol isString]) {
return [self cachableObjectForIndex:index
generator:^id{
return [self generateBezierPathForString:symbol];
}];
} else {
MPLayout *layout = [self childLayoutAtIndex:index];
return layout.bezierPath;
id element = [self.expression elementAtIndex:index];
if (![element isString]) {
return NULL;
}
NSString *string = element;
id lineObject = [self cachableObjectForIndex:index generator:^id{
CTLineRef line = [self createLineForString:string];
return CFBridgingRelease(line);
}];
return (__bridge CTLineRef)lineObject;
}
- (NSBezierPath *)generateBezierPathForString:(NSString *)aString
- (CTLineRef)createLineForString:(NSString *)aString
{
NSAttributedString *text = [[NSAttributedString alloc] initWithString:aString
attributes:@{NSFontAttributeName: [NSFont fontWithName:@"Lucida Grande" size:18.0]}];
self.textStorage.attributedString = text;
NSRange glyphRange = [self.layoutManager glyphRangeForTextContainer:self.textContainer];
NSGlyph glyphs[glyphRange.length+1];
NSUInteger actualGlyphCount = [self.layoutManager getGlyphs:glyphs
range:glyphRange];
NSBezierPath *path = [NSBezierPath bezierPath];
[path moveToPoint:NSZeroPoint];
[path appendBezierPathWithGlyphs:glyphs
count:actualGlyphCount
inFont:[NSFont fontWithName:@"Lucida Grande" size:18.0]];
return path;
CFAttributedStringRef attributedString = CFBridgingRetain(text);
CTLineRef line = CTLineCreateWithAttributedString(attributedString);
CFRelease(attributedString); // TODO: Is this release appropriate?
return line;
}
@end
@@ -60,6 +53,18 @@
self = [super init];
if (self) {
_expressionStorage = expressionStorage;
_expression = expressionStorage;
}
return self;
}
- (instancetype)initWithPath:(NSIndexPath *)path
parent:(MPLayout *)parent
{
self = [super initWithPath:path
parent:parent];
if (self) {
_expression = [parent.expressionStorage elementAtIndexPath:path];
}
return self;
}
@@ -74,52 +79,92 @@
return self.parent.expressionStorage;
}
- (MPExpression *)expression
{
return [self.expressionStorage elementAtIndexPath:self.path];
}
//- (MPExpression *)expression
//{
// return [self.expressionStorage elementAtIndexPath:self.path];
//}
#pragma mark Cache Methods
- (MPLayout *)childLayoutAtIndex:(NSUInteger)index
{
id cachedObject = [self cachableObjectForIndex:index generator:^id{
NSIndexPath *indexPath = [self.path indexPathByAddingIndex:index];
NSIndexPath *indexPath = [self.expression.indexPath indexPathByAddingIndex:index];
MPFunctionLayout *layout = [MPFunctionLayout functionLayoutForFunctionAtIndexPath:indexPath
parent:self];
return layout;
}];
if ([cachedObject isKindOfClass:[NSBezierPath class]]) {
return nil;
if ([cachedObject isKindOfClass:[MPLayout class]]) {
return cachedObject;
}
return cachedObject;
return nil;
}
- (NSSize)sizeForChildAtIndex:(NSUInteger)index
- (NSSize)sizeForElementAtIndex:(NSUInteger)index
{
id symbol = [self.expression elementAtIndex:index];
if ([symbol isString]) {
return [self bezierPathForChildAtIndex:index].bounds.size;
CTLineRef line = [self lineForElementAtIndex:index];
CFRetain(line);
CGRect bounds = CTLineGetBoundsWithOptions(line, /*kCTLineBoundsUseOpticalBounds*/ 0);
CFRelease(line);
return bounds.size;
} else {
return [self childLayoutAtIndex:index].size;
}
}
#pragma mark Drawing Methods
- (NSBezierPath *)generateBezierPath
- (NSSize)generateSize
{
NSBezierPath *fullPath = [NSBezierPath bezierPath];
[fullPath moveToPoint:NSZeroPoint];
NSUInteger x = 0;
for (NSInteger index = 0; index < self.expression.numberOfElements; ++index) {
NSAffineTransform *transform = [NSAffineTransform transform];
// TODO: Translate by the right amount
[transform translateXBy:x yBy:0];
NSBezierPath *path = [self bezierPathForChildAtIndex:index].copy;
[path transformUsingAffineTransform:transform];
[fullPath appendBezierPath:path];
x += path.bounds.size.width;
CGFloat width = 0, height = 0;
for (NSUInteger index = 0; index < self.expression.numberOfElements; index++) {
NSSize elementSize = [self sizeForElementAtIndex:index];
width += elementSize.width;
height = MAX(height, elementSize.height);
}
return fullPath;
return NSMakeSize(width, height);
}
- (void)drawAtPoint:(NSPoint)point
{
// Get the current context
CGContextRef context =
(CGContextRef)[[NSGraphicsContext currentContext] graphicsPort];
CGContextSaveGState(context);
// Set the text matrix
CGContextSetTextMatrix(context, CGAffineTransformIdentity);
// Track the x position
CGFloat x = point.x;
for (NSUInteger index = 0; index < self.expression.numberOfElements; index++) {
// The current element
id element = [self.expression elementAtIndex:index];
NSSize elementSize = [self sizeForElementAtIndex:index];
CGFloat dy = (self.size.height - elementSize.height) / 2;
CGFloat y = point.y + dy;
if ([element isString]) {
// Get the line to draw
CTLineRef line = [self lineForElementAtIndex:index];
CFRetain(line);
// Move to the appropriate position
CGContextSetTextPosition(context, x, y);
// Perform the drawing
CTLineDraw(line, context);
CFRelease(line);
} else {
// Let the child layout draw itself
MPLayout *layout = [self childLayoutAtIndex:index];
[layout drawAtPoint:NSMakePoint(x, y)];
}
x += elementSize.width;
}
CGContextRestoreGState(context);
}
@end