Fundamental Redesign of the View and Controller
This commit is contained in:
@@ -61,7 +61,6 @@
|
||||
#pragma mark Actions
|
||||
- (IBAction)changeExpression:(id)sender {
|
||||
[self.resultExpressionView.expressionStorage insertElement:@"abc" atLocation:6];
|
||||
self.resultExpressionView.needsDisplay = YES;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -14,6 +14,6 @@
|
||||
|
||||
- (instancetype)initRootLayoutWithExpressionStorage:(MPExpressionStorage *)expressionStorage;
|
||||
|
||||
@property (readonly, nonatomic, weak) MPExpression *expression; // Convenience
|
||||
@property (readonly, nonatomic, weak) MPExpression *expression;
|
||||
|
||||
@end
|
||||
|
||||
@@ -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];
|
||||
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);
|
||||
}];
|
||||
} else {
|
||||
MPLayout *layout = [self childLayoutAtIndex:index];
|
||||
return layout.bezierPath;
|
||||
}
|
||||
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 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
|
||||
|
||||
@@ -8,10 +8,14 @@
|
||||
|
||||
#import "MPExpression.h"
|
||||
|
||||
@class MPExpressionStorage, MPExpressionLayout;
|
||||
@class MPExpressionStorage, MPExpressionView, MPExpressionLayout;
|
||||
|
||||
@interface MPExpressionStorage : MPExpression
|
||||
|
||||
- (instancetype)initWithExpressionView:(MPExpressionView *)expressionView
|
||||
elements:(NSArray *)elements;
|
||||
|
||||
@property (readonly, nonatomic, weak) MPExpressionView *expressionView;
|
||||
@property (nonatomic, strong) MPExpressionLayout *rootLayout;
|
||||
|
||||
- (NSLayoutManager *)layoutManager;
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
//
|
||||
|
||||
#import "MPExpressionStorage.h"
|
||||
#import "MPExpressionView.h"
|
||||
#import "MPExpressionLayout.h"
|
||||
#import "MPFunctionLayout.h"
|
||||
#import "MPRangePath.h"
|
||||
@@ -19,6 +20,15 @@
|
||||
|
||||
@implementation MPExpressionStorage
|
||||
|
||||
- (instancetype)initWithExpressionView:(MPExpressionView *)expressionView elements:(NSArray *)elements
|
||||
{
|
||||
self = [self initWithElements:elements];
|
||||
if (self) {
|
||||
_expressionView = expressionView;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (instancetype)initWithElements:(NSArray *)elements
|
||||
{
|
||||
self = [super initWithElements:elements];
|
||||
@@ -69,7 +79,9 @@
|
||||
for (NSUInteger index = 1; index < rangePath.location.length-1; index++) {
|
||||
current = [current childLayoutAtIndex:index];
|
||||
}
|
||||
[current clearCacheInRange:rangePath.rangeAtLastIndex replacementLength:replacementLength];
|
||||
[current clearCacheInRange:rangePath.rangeAtLastIndex
|
||||
replacementLength:replacementLength];
|
||||
self.expressionView.needsDisplay = YES;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
|
||||
@class MPExpressionView, MPExpressionStorage, MPExpressionLayout, MPRangePath;
|
||||
|
||||
@interface MPExpressionView : NSView <NSUserInterfaceValidations>
|
||||
@interface MPExpressionView : NSView
|
||||
|
||||
#pragma mark Creation Methods
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
@property (readonly, nonatomic, strong) MPExpressionStorage *expressionStorage;
|
||||
|
||||
@property (nonatomic, getter = isEditable) BOOL editable;
|
||||
@property (nonatomic, strong) MPRangePath *selection;
|
||||
//@property (nonatomic, strong) MPRangePath *selection;
|
||||
@property (nonatomic, strong) NSIndexPath *caretLocation;
|
||||
|
||||
@end
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
#import "MPSumFunction.h"
|
||||
|
||||
@interface MPExpressionView (MPCursor)
|
||||
@property (nonatomic, strong) NSTimer *cursorTimer;
|
||||
|
||||
@end
|
||||
|
||||
@implementation MPExpressionView
|
||||
@@ -49,8 +49,9 @@
|
||||
|
||||
- (void)initializeObjects
|
||||
{
|
||||
MPExpressionStorage *expressionStorage = [[MPExpressionStorage alloc] initWithElements:@[@"12345", [[MPSumFunction alloc] init], [[MPSumFunction alloc] init]]];
|
||||
MPExpressionStorage *expressionStorage = [[MPExpressionStorage alloc] initWithExpressionView:self elements:@[@"12345", [[MPSumFunction alloc] init], [[MPSumFunction alloc] init]]];
|
||||
_expressionStorage = expressionStorage;
|
||||
_caretLocation = [[NSIndexPath alloc] initWithIndex:0];
|
||||
}
|
||||
|
||||
#pragma mark Properties
|
||||
@@ -60,9 +61,25 @@
|
||||
return NO;
|
||||
}
|
||||
|
||||
- (void)setExpressionStorage:(MPExpressionStorage *)expressionStorage
|
||||
- (BOOL)acceptsFirstResponder
|
||||
{
|
||||
_expressionStorage = expressionStorage;
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (BOOL)canBecomeKeyView
|
||||
{
|
||||
return YES;
|
||||
}
|
||||
|
||||
#pragma mark Event Handling
|
||||
- (void)keyDown:(NSEvent *)theEvent
|
||||
{
|
||||
[self interpretKeyEvents:@[theEvent]];
|
||||
}
|
||||
|
||||
- (void)moveRight:(id)sender
|
||||
{
|
||||
[self.expressionStorage deleteElementsInRange:NSMakeRange(0, 1)];
|
||||
}
|
||||
|
||||
#pragma mark Drawing Methods
|
||||
|
||||
@@ -14,18 +14,24 @@
|
||||
+ (MPFunctionLayout *)functionLayoutForFunctionAtIndexPath:(NSIndexPath *)path
|
||||
parent:(MPExpressionLayout *)parent;
|
||||
|
||||
@property (readonly, nonatomic, weak) MPFunction *function; // Convenience
|
||||
@property (readonly, nonatomic, weak) MPFunction *function;
|
||||
|
||||
@end
|
||||
|
||||
@interface MPFunctionLayout (MPSubclassOverride)
|
||||
|
||||
#pragma mark Cache Methods
|
||||
- (CTLineRef)lineForPrivateCacheIndex:(NSUInteger)index
|
||||
generator:(CTLineRef (^)())generator;
|
||||
|
||||
// Should also implement accessor method for special function type:
|
||||
// - (MPCustomFunction *)customFunction
|
||||
// {
|
||||
// return (MPCustomFunction *)self.function;
|
||||
// }
|
||||
|
||||
- (NSBezierPath *)generateBezierPath;
|
||||
#pragma mark Size and Drawing Methods
|
||||
- (NSSize)generateSize; // To be implemented
|
||||
- (void)drawAtPoint:(NSPoint)point; // To be implemented
|
||||
|
||||
@end
|
||||
@@ -27,32 +27,63 @@
|
||||
return [[self alloc] initWithPath:path parent:parent];
|
||||
}
|
||||
|
||||
#pragma mark Properties
|
||||
- (MPFunction *)function
|
||||
- (instancetype)initWithPath:(NSIndexPath *)path
|
||||
parent:(MPLayout *)parent
|
||||
{
|
||||
return [self.expressionStorage elementAtIndexPath:self.path];
|
||||
self = [super initWithPath:path
|
||||
parent:parent];
|
||||
if (self) {
|
||||
_function = [parent.expressionStorage elementAtIndexPath:path];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
#pragma mark Properties
|
||||
//- (MPFunction *)function
|
||||
//{
|
||||
// return [self.expressionStorage elementAtIndexPath:self.path];
|
||||
//}
|
||||
|
||||
#pragma mark Cache Methods
|
||||
- (CTLineRef)lineForPrivateCacheIndex:(NSUInteger)index
|
||||
generator:(CTLineRef (^)())generator
|
||||
{
|
||||
NSUInteger actualIndex = self.function.numberOfChildren + index;
|
||||
id (^actualGenerator)() = ^{
|
||||
CTLineRef line = generator();
|
||||
return CFBridgingRelease(line);
|
||||
};
|
||||
id lineObject = [self cachableObjectForIndex:actualIndex
|
||||
generator:actualGenerator];
|
||||
return (__bridge CTLineRef)(lineObject);
|
||||
}
|
||||
|
||||
- (MPLayout *)childLayoutAtIndex:(NSUInteger)index
|
||||
{
|
||||
return [self cachableObjectForIndex:index generator:^id{
|
||||
NSIndexPath *childPath = [self.path indexPathByAddingIndex:index];
|
||||
NSIndexPath *childPath = [self.function.indexPath indexPathByAddingIndex:index];
|
||||
MPExpressionLayout *layout = [[MPExpressionLayout alloc] initWithPath:childPath
|
||||
parent:self];
|
||||
return layout;
|
||||
}];
|
||||
}
|
||||
|
||||
#pragma mark Size and Drawing Methods
|
||||
|
||||
- (NSSize)sizeForChildAtIndex:(NSUInteger)index
|
||||
{
|
||||
MPLayout *childLayout = [self childLayoutAtIndex:index];
|
||||
return [childLayout size];
|
||||
}
|
||||
|
||||
- (NSBezierPath *)generateBezierPath
|
||||
- (NSSize)generateSize
|
||||
{
|
||||
return [NSBezierPath bezierPath];
|
||||
return NSZeroSize;
|
||||
}
|
||||
|
||||
- (void)drawAtPoint:(NSPoint)point
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -20,13 +20,9 @@
|
||||
|
||||
#pragma mark Text System Objects
|
||||
@property (readonly, nonatomic, weak) MPExpressionStorage *expressionStorage;
|
||||
@property (readonly, nonatomic, weak) NSLayoutManager *layoutManager;
|
||||
@property (readonly, nonatomic, weak) NSTextContainer *textContainer;
|
||||
@property (readonly, nonatomic, weak) NSTextStorage *textStorage;
|
||||
|
||||
#pragma mark Cache Tree
|
||||
@property (readonly, nonatomic, weak) MPLayout *parent;
|
||||
@property (readonly, nonatomic, strong) NSIndexPath *path;
|
||||
|
||||
#pragma mark Cache Methods
|
||||
// Querying Caches
|
||||
@@ -39,18 +35,14 @@
|
||||
- (void)invalidate;
|
||||
|
||||
#pragma mark Calculation and Drawing Methods
|
||||
// TODO: Implement Small Size
|
||||
// @property (nonatomic) BOOL usesSmallSize;
|
||||
- (NSSize)size;
|
||||
|
||||
- (NSBezierPath *)bezierPath;
|
||||
- (NSBezierPath *)bezierPathAtOrigin:(NSPoint)point;
|
||||
|
||||
- (void)drawAtPoint:(NSPoint)point;
|
||||
|
||||
@end
|
||||
|
||||
@interface MPLayout (MPSubclassImplement)
|
||||
- (MPLayout *)childLayoutAtIndex:(NSUInteger)index; // To be implemented
|
||||
- (NSSize)sizeForChildAtIndex:(NSUInteger)index; // To be implemented
|
||||
- (NSBezierPath *)generateBezierPath; // To be implemented
|
||||
- (NSSize)generateSize; // To be implemented
|
||||
@end
|
||||
@@ -10,19 +10,15 @@
|
||||
|
||||
@interface MPLayout ()
|
||||
|
||||
// Querying Caches
|
||||
// Querying and Storing Caches
|
||||
- (BOOL)hasCacheForElementAtIndex:(NSUInteger)index;
|
||||
|
||||
// Storing Caches
|
||||
- (void)cacheObject:(id)anObject
|
||||
forElementAtIndex:(NSUInteger)index;
|
||||
- (void)ensureCacheSizeForIndex:(NSUInteger)index;
|
||||
|
||||
@end
|
||||
|
||||
@implementation MPLayout {
|
||||
NSMutableArray *_cache;
|
||||
NSBezierPath *_cachedPath;
|
||||
NSSize _cachedSize;
|
||||
}
|
||||
|
||||
#pragma mark Creation Methods
|
||||
@@ -31,8 +27,7 @@
|
||||
self = [super init];
|
||||
if (self) {
|
||||
_cache = [[NSMutableArray alloc] init];
|
||||
_cachedPath = nil;
|
||||
_path = [[NSIndexPath alloc] init];
|
||||
_cachedSize = NSZeroSize;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
@@ -42,7 +37,6 @@
|
||||
{
|
||||
self = [self init];
|
||||
if (self) {
|
||||
_path = path;
|
||||
_parent = parent;
|
||||
}
|
||||
return self;
|
||||
@@ -54,23 +48,8 @@
|
||||
return self.parent.expressionStorage;
|
||||
}
|
||||
|
||||
- (NSLayoutManager *)layoutManager
|
||||
{
|
||||
return self.expressionStorage.layoutManager;
|
||||
}
|
||||
|
||||
- (NSTextContainer *)textContainer
|
||||
{
|
||||
return self.expressionStorage.textContainer;
|
||||
}
|
||||
|
||||
- (NSTextStorage *)textStorage
|
||||
{
|
||||
return self.expressionStorage.textStorage;
|
||||
}
|
||||
|
||||
#pragma mark Cache Tree
|
||||
// Querying Caches
|
||||
// Querying and Storing Caches
|
||||
- (BOOL)hasCacheForElementAtIndex:(NSUInteger)index
|
||||
{
|
||||
if (index >= _cache.count) {
|
||||
@@ -86,17 +65,9 @@
|
||||
return _cache[index];
|
||||
}
|
||||
id object = generator();
|
||||
[self cacheObject:object
|
||||
forElementAtIndex:index];
|
||||
return object;
|
||||
}
|
||||
|
||||
// Storing Caches
|
||||
- (void)cacheObject:(id)anObject
|
||||
forElementAtIndex:(NSUInteger)index
|
||||
{
|
||||
[self ensureCacheSizeForIndex:index];
|
||||
_cache[index] = anObject;
|
||||
_cache[index] = object;
|
||||
return object;
|
||||
}
|
||||
|
||||
- (void)ensureCacheSizeForIndex:(NSUInteger)index
|
||||
@@ -121,39 +92,41 @@
|
||||
|
||||
- (void)invalidate
|
||||
{
|
||||
_cachedPath = nil;
|
||||
_cachedSize = NSZeroSize;
|
||||
[self.parent invalidate];
|
||||
}
|
||||
|
||||
#pragma mark Calculation Methods
|
||||
#pragma mark Calculation and Drawing Methods
|
||||
- (NSSize)size
|
||||
{
|
||||
return self.bezierPath.bounds.size;
|
||||
if (NSEqualSizes(_cachedSize, NSZeroSize)) {
|
||||
_cachedSize = [self generateSize];
|
||||
}
|
||||
|
||||
- (NSBezierPath *)bezierPath
|
||||
{
|
||||
if (!_cachedPath) {
|
||||
_cachedPath = [self generateBezierPath];
|
||||
}
|
||||
return _cachedPath;
|
||||
}
|
||||
|
||||
- (NSBezierPath *)bezierPathAtOrigin:(NSPoint)point
|
||||
{
|
||||
NSAffineTransform *transform = [NSAffineTransform transform];
|
||||
[transform translateXBy:point.x
|
||||
yBy:point.y];
|
||||
NSBezierPath *path = [NSBezierPath bezierPath];
|
||||
[path appendBezierPath:self.bezierPath];
|
||||
[path transformUsingAffineTransform:transform];
|
||||
return path;
|
||||
return _cachedSize;
|
||||
}
|
||||
|
||||
- (void)drawAtPoint:(NSPoint)point
|
||||
{
|
||||
NSBezierPath *path = [self bezierPathAtOrigin:point];
|
||||
[path fill];
|
||||
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation MPLayout (MPSubclassImplement)
|
||||
|
||||
- (MPLayout *)childLayoutAtIndex:(NSUInteger)index
|
||||
{
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (NSSize)sizeForChildAtIndex:(NSUInteger)index
|
||||
{
|
||||
return NSZeroSize;
|
||||
}
|
||||
|
||||
- (NSSize)generateSize
|
||||
{
|
||||
return NSZeroSize;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -16,21 +16,46 @@
|
||||
return (MPSumFunction *)self.function;
|
||||
}
|
||||
|
||||
- (NSBezierPath *)generateBezierPath
|
||||
- (CTLineRef)line
|
||||
{
|
||||
NSAttributedString *text = [[NSAttributedString alloc] initWithString:@"∑"
|
||||
CTLineRef line = [self lineForPrivateCacheIndex:0 generator:^CTLineRef{
|
||||
NSAttributedString *text =
|
||||
[[NSAttributedString alloc] initWithString:@"∑"
|
||||
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 actualGylphCount = [self.layoutManager getGlyphs:glyphs
|
||||
range:glyphRange];
|
||||
NSBezierPath *path = [NSBezierPath bezierPath];
|
||||
[path moveToPoint:NSZeroPoint];
|
||||
[path appendBezierPathWithGlyphs:glyphs
|
||||
count:actualGylphCount
|
||||
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;
|
||||
}];
|
||||
return line;
|
||||
}
|
||||
|
||||
- (NSSize)generateSize
|
||||
{
|
||||
CTLineRef line = [self line];
|
||||
CFRetain(line);
|
||||
CGSize size = CTLineGetBoundsWithOptions(line, /*kCTLineBoundsUseOpticalBounds*/0).size;
|
||||
CFRelease(line);
|
||||
return size;
|
||||
}
|
||||
|
||||
- (void)drawAtPoint:(NSPoint)point
|
||||
{
|
||||
// Get the current context
|
||||
CGContextRef context = (CGContextRef)[[NSGraphicsContext currentContext] graphicsPort];
|
||||
|
||||
// Set the text matrix
|
||||
CGContextSetTextMatrix(context, CGAffineTransformIdentity);
|
||||
|
||||
// Get the line of text
|
||||
CTLineRef line = [self line];
|
||||
CFRetain(line);
|
||||
|
||||
// Draw the line
|
||||
CGContextSetTextPosition(context, point.x, point.y);
|
||||
CTLineDraw(line, context);
|
||||
|
||||
CFRelease(line);
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
Reference in New Issue
Block a user