Fundamental Redesign of the View and Controller
This commit is contained in:
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user