Added Function Chooser as a Popover
Improved Evaluation Added Parenthesis Function
This commit is contained in:
@@ -13,6 +13,12 @@
|
||||
#import "NSIndexPath+MPAdditions.h"
|
||||
|
||||
#define kMPEmptyBoxWidth (self.usesSmallSize ? 2.0 : 3.0)
|
||||
#define kMPEmptyBoxHeight (CTFontGetDescent((CTFontRef)self.font) + CTFontGetAscent((CTFontRef)self.font) + CTFontGetLeading((CTFontRef)self.font))
|
||||
#define kMPEmptyBoxYOrigin (-(CTFontGetDescent((CTFontRef)self.font) + CTFontGetLeading((CTFontRef)self.font)))
|
||||
|
||||
#define kMPEmptyBoxDrawingWidth kMPEmptyBoxWidth
|
||||
#define kMPEmptyBoxDrawingHeight (CTFontGetDescent((CTFontRef)self.font) + CTFontGetAscent((CTFontRef)self.font))
|
||||
#define kMPEmptyBoxDrawingYOrigin (-(CTFontGetDescent((CTFontRef)self.font) + CTFontGetLeading((CTFontRef)self.font)/2))
|
||||
|
||||
@interface MPExpressionLayout (MPLineGeneration)
|
||||
|
||||
@@ -86,7 +92,7 @@
|
||||
- (NSRect)generateBounds
|
||||
{
|
||||
if (self.expression.numberOfElements == 0) {
|
||||
return NSMakeRect(0, [self.font descender], kMPEmptyBoxWidth, self.fontSize);
|
||||
return NSMakeRect(0, kMPEmptyBoxYOrigin, kMPEmptyBoxWidth, kMPEmptyBoxHeight);
|
||||
}
|
||||
CGFloat x = 0, y = 0, width = 0, height = 0;
|
||||
for (NSUInteger index = 0; index < self.expression.numberOfElements; index++) {
|
||||
@@ -211,10 +217,23 @@
|
||||
(CGContextRef)[[NSGraphicsContext currentContext] graphicsPort];
|
||||
CGContextSaveGState(context);
|
||||
|
||||
#ifdef MPDEBUG_DRAW_ORIGIN
|
||||
[[NSColor blueColor] set];
|
||||
[[NSBezierPath bezierPathWithOvalInRect:NSMakeRect(-2, -2, 4, 4)] fill];
|
||||
#endif
|
||||
|
||||
[[NSColor textColor] set];
|
||||
|
||||
#ifdef MPDEBUG_DRAW_BOUNDS
|
||||
[[NSColor greenColor] set];
|
||||
[[NSBezierPath bezierPathWithRect:self.bounds] stroke];
|
||||
[[NSColor textColor] set];
|
||||
#endif
|
||||
|
||||
if (self.expression.numberOfElements == 0) {
|
||||
|
||||
CGContextRestoreGState(context);
|
||||
NSBezierPath *path = [NSBezierPath bezierPathWithRect:NSMakeRect(0, 0 + self.font.descender, kMPEmptyBoxWidth, self.fontSize)];
|
||||
NSBezierPath *path = [NSBezierPath bezierPathWithRect:NSMakeRect(0, kMPEmptyBoxDrawingYOrigin, kMPEmptyBoxDrawingWidth, kMPEmptyBoxDrawingHeight)];
|
||||
path.lineWidth = 0.5;
|
||||
[path stroke];
|
||||
return;
|
||||
@@ -239,6 +258,12 @@
|
||||
// Move to the appropriate position
|
||||
CGContextSetTextPosition(context, x, 0);
|
||||
|
||||
#ifdef MPDEBUG_DRAW_BASELINE
|
||||
[[NSColor redColor] set];
|
||||
NSRectFill(NSMakeRect(x, -1, elementBounds.size.width, 1));
|
||||
[[NSColor textColor] set];
|
||||
#endif
|
||||
|
||||
// Perform the drawing
|
||||
CTLineDraw(line, context);
|
||||
|
||||
|
||||
@@ -50,6 +50,7 @@
|
||||
[current clearCacheInRange:rangePath.rangeAtLastIndex
|
||||
replacementLength:replacementLength];
|
||||
[self.expressionView invalidateIntrinsicContentSize];
|
||||
self.expressionView.error = nil;
|
||||
self.expressionView.needsDisplay = YES;
|
||||
}
|
||||
|
||||
|
||||
@@ -10,6 +10,8 @@
|
||||
|
||||
#import <Cocoa/Cocoa.h>
|
||||
|
||||
#import "MPParseError.h"
|
||||
|
||||
@class MPExpressionView, MPExpressionStorage, MPExpressionLayout, MPRangePath;
|
||||
|
||||
@interface MPExpressionView : NSView
|
||||
@@ -23,7 +25,10 @@
|
||||
@property (readonly, nonatomic, strong) MPExpressionStorage *expressionStorage;
|
||||
|
||||
// @property (nonatomic, getter = isEditable) BOOL editable;
|
||||
@property (nonatomic) BOOL allowsIntelligentReplacements;
|
||||
|
||||
@property (nonatomic, strong) MPRangePath *selection;
|
||||
@property (nonatomic, strong) MPParseError *error;
|
||||
|
||||
@property (nonatomic, weak) id target;
|
||||
@property (nonatomic) SEL action;
|
||||
|
||||
@@ -16,12 +16,17 @@
|
||||
#import "NSIndexPath+MPAdditions.h"
|
||||
|
||||
#import "MPSumFunction.h"
|
||||
#import "MPParenthesisFunction.h"
|
||||
#import "MPParenthesisFunctionLayout.h"
|
||||
|
||||
#import "MPFunctionsViewController.h"
|
||||
|
||||
|
||||
@interface MPExpressionView ()
|
||||
|
||||
@property (nonatomic, weak) NSButton *functionsButton;
|
||||
@property (nonatomic, strong) NSPopover *functionsPopover;
|
||||
@property (nonatomic, strong) MPFunctionsViewController *functionsViewController;
|
||||
|
||||
@property (nonatomic, strong) NSTimer *caretTimer;
|
||||
@property (nonatomic) NSTimeInterval caretBlinkRate;
|
||||
@@ -303,7 +308,7 @@
|
||||
- (void)initializeExpressionView
|
||||
{
|
||||
// Setup the Expression Storage
|
||||
MPExpressionStorage *expressionStorage = [[MPExpressionStorage alloc] initWithElements:@[@"12345", [[MPSumFunction alloc] init], [[MPSumFunction alloc] init]]];
|
||||
MPExpressionStorage *expressionStorage = [[MPExpressionStorage alloc] init];
|
||||
expressionStorage.expressionView = self;
|
||||
_expressionStorage = expressionStorage;
|
||||
|
||||
@@ -347,18 +352,40 @@
|
||||
self.needsDisplay = YES;
|
||||
}
|
||||
|
||||
- (void)setError:(MPParseError *)error
|
||||
{
|
||||
_error = error;
|
||||
self.needsDisplay = YES;
|
||||
}
|
||||
|
||||
#pragma mark Actions
|
||||
- (void)showFunctions:(id)sender
|
||||
{
|
||||
NSViewController *controller = [[NSViewController alloc] initWithNibName:nil
|
||||
bundle:nil];
|
||||
controller.view = [[NSView alloc] init];
|
||||
NSPopover *popover = [[NSPopover alloc] init];
|
||||
popover.contentSize = NSMakeSize(100.0, 100.0);
|
||||
popover.contentViewController = controller;
|
||||
popover.animates = YES;
|
||||
popover.behavior = NSPopoverBehaviorSemitransient;
|
||||
[popover showRelativeToRect:[sender bounds] ofView:sender preferredEdge:NSMaxYEdge];
|
||||
if (self.functionsPopover == nil || self.functionsViewController == nil) {
|
||||
self.functionsViewController = [[MPFunctionsViewController alloc] init];
|
||||
self.functionsViewController.target = self;
|
||||
self.functionsViewController.action = @selector(insertFunction:);
|
||||
self.functionsPopover = [[NSPopover alloc] init];
|
||||
self.functionsPopover.contentViewController = self.functionsViewController;
|
||||
self.functionsPopover.animates = YES;
|
||||
self.functionsPopover.behavior = NSPopoverBehaviorSemitransient;
|
||||
}
|
||||
if (self.functionsPopover.isShown) {
|
||||
[self.functionsPopover close];
|
||||
} else {
|
||||
[self.functionsPopover showRelativeToRect:[sender bounds] ofView:sender preferredEdge:NSMaxYEdge];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)insertFunction:(MPFunction *)function
|
||||
{
|
||||
[self.functionsPopover close];
|
||||
[self.expressionStorage replaceSymbolsInRangePath:self.selection withElements:@[function]];
|
||||
MPExpression *targetExpression = [self.expressionStorage elementAtIndexPath:[self.selection.location indexPathByRemovingLastIndex]];
|
||||
NSIndexPath *functionPath = [self.selection.location indexPathByReplacingLastIndexWithIndex:[targetExpression indexOfElementAtLocation:self.selection.location.lastIndex
|
||||
offset:NULL]];
|
||||
MPFunctionLayout *functionLayout = (MPFunctionLayout *)[self.expressionStorage.rootLayout childLayoutAtIndexPath:functionPath];
|
||||
self.selection = MPMakeRangePath([[functionPath indexPathByAddingIndex:functionLayout.indexOfLeadingChild] indexPathByAddingIndex:0], 0);
|
||||
}
|
||||
|
||||
#pragma mark NSView Stuff
|
||||
@@ -372,6 +399,20 @@
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (BOOL)becomeFirstResponder
|
||||
{
|
||||
[self restartCaretTimer];
|
||||
return [super becomeFirstResponder];
|
||||
}
|
||||
|
||||
- (BOOL)resignFirstResponder
|
||||
{
|
||||
[self.caretTimer invalidate];
|
||||
self.caretVisible = NO;
|
||||
self.needsDisplay = YES;
|
||||
return [super resignFirstResponder];
|
||||
}
|
||||
|
||||
- (BOOL)isFlipped
|
||||
{
|
||||
return NO;
|
||||
@@ -415,17 +456,40 @@
|
||||
- (void)keyDown:(NSEvent *)theEvent
|
||||
{
|
||||
NSString *characters = theEvent.characters;
|
||||
|
||||
if ([characters isEqualToString:@"("]) {
|
||||
[self insertParenthesisFunction];
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
NSString *decimalSeparator = [NSRegularExpression escapedPatternForString:[[NSLocale currentLocale] objectForKey:NSLocaleDecimalSeparator]];
|
||||
NSMutableCharacterSet *allowedCharacters = [NSMutableCharacterSet alphanumericCharacterSet];
|
||||
[allowedCharacters addCharactersInString:@"+-*= "];
|
||||
[allowedCharacters addCharactersInString:[NSString stringWithFormat:@"+-*= %@", decimalSeparator]];
|
||||
|
||||
if (characters.length == 1 && [characters stringByTrimmingCharactersInSet:allowedCharacters].length == 0) {
|
||||
MPExpression *targetExpression = [self.expressionStorage elementAtIndexPath:[self.selection.location indexPathByRemovingLastIndex]];
|
||||
[targetExpression replaceSymbolsInRange:self.selection.rangeAtLastIndex withElements:@[characters]];
|
||||
[self.expressionStorage replaceSymbolsInRangePath:self.selection withElements:@[characters]];
|
||||
self.selection = MPMakeRangePath([self.selection.location indexPathByIncrementingLastIndex], 0);
|
||||
} else {
|
||||
[self interpretKeyEvents:@[theEvent]];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)insertParenthesisFunction
|
||||
{
|
||||
MPExpression *selectedElementsExpression = [self.expressionStorage subexpressionWithRangePath:self.selection];
|
||||
MPParenthesisFunction *function = [[MPParenthesisFunction alloc] init];
|
||||
function.expression = selectedElementsExpression;
|
||||
[self.expressionStorage replaceSymbolsInRangePath:self.selection
|
||||
withElements:@[function]];
|
||||
|
||||
MPExpression *targetExpression = [self.expressionStorage elementAtIndexPath:[self.selection.location indexPathByRemovingLastIndex]];
|
||||
NSIndexPath *functionPath = [self.selection.location indexPathByReplacingLastIndexWithIndex:[targetExpression indexOfElementAtLocation:self.selection.location.lastIndex
|
||||
offset:NULL]];
|
||||
self.selection = MPMakeRangePath([[functionPath indexPathByAddingIndex:0] indexPathByAddingIndex:0], self.selection.length);
|
||||
}
|
||||
|
||||
- (void)insertNewline:(id)sender
|
||||
{
|
||||
if (self.target && self.action) {
|
||||
@@ -571,6 +635,30 @@
|
||||
self.selection = MPMakeRangePath(location, maxLocation.lastIndex-location.lastIndex);
|
||||
}
|
||||
|
||||
- (void)moveUp:(id)sender
|
||||
{
|
||||
NSIndexPath *targetExpressionPath = [self.selection.location indexPathByRemovingLastIndex];
|
||||
MPExpression *targetExpression = [self.expressionStorage elementAtIndexPath:targetExpressionPath];
|
||||
if (targetExpression.parent != nil) {
|
||||
NSIndexPath *functionPath = [targetExpressionPath indexPathByRemovingLastIndex];
|
||||
MPFunctionLayout *functionLayout = (MPFunctionLayout *)[self.expressionStorage.rootLayout childLayoutAtIndexPath:functionPath];
|
||||
NSUInteger newChildIndex = [functionLayout indexOfChildAboveChildAtIndex:targetExpressionPath.lastIndex];
|
||||
self.selection = MPMakeRangePath([[targetExpressionPath indexPathByReplacingLastIndexWithIndex:newChildIndex] indexPathByAddingIndex:0], 0);
|
||||
}
|
||||
}
|
||||
|
||||
- (void)moveDown:(id)sender
|
||||
{
|
||||
NSIndexPath *targetExpressionPath = [self.selection.location indexPathByRemovingLastIndex];
|
||||
MPExpression *targetExpression = [self.expressionStorage elementAtIndexPath:targetExpressionPath];
|
||||
if (targetExpression.parent != nil) {
|
||||
NSIndexPath *functionPath = [targetExpressionPath indexPathByRemovingLastIndex];
|
||||
MPFunctionLayout *functionLayout = (MPFunctionLayout *)[self.expressionStorage.rootLayout childLayoutAtIndexPath:functionPath];
|
||||
NSUInteger newChildIndex = [functionLayout indexOfChildBelowChildAtIndex:targetExpressionPath.lastIndex];
|
||||
self.selection = MPMakeRangePath([[targetExpressionPath indexPathByReplacingLastIndexWithIndex:newChildIndex] indexPathByAddingIndex:0], 0);
|
||||
}
|
||||
}
|
||||
|
||||
- (void)selectAll:(id)sender
|
||||
{
|
||||
NSIndexPath *location = [NSIndexPath indexPathWithIndex:0];
|
||||
@@ -579,13 +667,42 @@
|
||||
|
||||
- (void)deleteBackward:(id)sender
|
||||
{
|
||||
MPExpression *targetExpression = [self.expressionStorage elementAtIndexPath:[self.selection.location indexPathByRemovingLastIndex]];
|
||||
if (self.selection.length > 0) {
|
||||
[targetExpression replaceSymbolsInRange:self.selection.rangeAtLastIndex withElements:@[]];
|
||||
[self.expressionStorage replaceSymbolsInRangePath:self.selection withElements:@[]];
|
||||
self.selection = MPMakeRangePath(self.selection.location, 0);
|
||||
} else if (self.selection.location.lastIndex > 0) {
|
||||
[targetExpression replaceSymbolsInRange:NSMakeRange(self.selection.location.lastIndex-1, 1) withElements:@[]];
|
||||
self.selection = MPMakeRangePath([self.selection.location indexPathByDecrementingLastIndex], 0);
|
||||
MPExpression *targetExpression = [self.expressionStorage elementAtIndexPath:[self.selection.location indexPathByRemovingLastIndex]];
|
||||
id <MPExpressionElement> elementToDelete = [targetExpression elementAtIndex:[targetExpression indexOfElementAtLocation:self.selection.location.lastIndex-1
|
||||
offset:NULL]];
|
||||
if ([elementToDelete isFunction]) {
|
||||
self.selection = MPMakeRangePath(self.selection.location.indexPathByDecrementingLastIndex, 1);
|
||||
} else {
|
||||
[targetExpression replaceSymbolsInRange:NSMakeRange(self.selection.location.lastIndex-1, 1) withElements:@[]];
|
||||
self.selection = MPMakeRangePath([self.selection.location indexPathByDecrementingLastIndex], 0);
|
||||
}
|
||||
} else {
|
||||
NSIndexPath *targetExpressionPath = [self.selection.location indexPathByRemovingLastIndex];
|
||||
MPExpression *targetExpression = [self.expressionStorage elementAtIndexPath:targetExpressionPath];
|
||||
if (targetExpression.parent != nil) {
|
||||
NSIndexPath *functionPath = [targetExpressionPath indexPathByRemovingLastIndex];
|
||||
MPFunction *function = [self.expressionStorage elementAtIndexPath:functionPath];
|
||||
MPFunctionLayout *functionLayout = (MPFunctionLayout *)[self.expressionStorage.rootLayout childLayoutAtIndexPath:functionPath];
|
||||
NSIndexSet *remainingIndexes = [functionLayout indexesOfRemainingChildren];
|
||||
|
||||
NSMutableArray *remainder = [[NSMutableArray alloc] init];
|
||||
for (NSUInteger index = remainingIndexes.firstIndex;
|
||||
index <= remainingIndexes.lastIndex;
|
||||
index = [remainingIndexes indexGreaterThanIndex:index]) {
|
||||
[remainder addObjectsFromArray:[function childAtIndex:index].elements];
|
||||
}
|
||||
|
||||
NSIndexPath *newTargetExpressionPath = [functionPath indexPathByRemovingLastIndex];
|
||||
MPExpression *newTargetExpression = [self.expressionStorage elementAtIndexPath:newTargetExpressionPath];
|
||||
NSIndexPath *newSelectionLocation = [functionPath indexPathByReplacingLastIndexWithIndex:[newTargetExpression locationOfElementAtIndex:functionPath.lastIndex]];
|
||||
|
||||
[self.expressionStorage replaceSymbolsInRangePath:MPMakeRangePath(functionPath, 1) withElements:remainder];
|
||||
self.selection = MPMakeRangePath(newSelectionLocation, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -626,6 +743,11 @@
|
||||
// Calculate the position of the expression (probably also forces layout of the expression the first time)
|
||||
NSPoint expressionOrigin = self.expressionOrigin;
|
||||
|
||||
NSAffineTransform *transform = [NSAffineTransform transform];
|
||||
[transform translateXBy:expressionOrigin.x
|
||||
yBy:expressionOrigin.y];
|
||||
[transform concat];
|
||||
|
||||
// Draw the selection
|
||||
if (self.caretVisible || self.selection.length > 0) {
|
||||
if (self.selection.length == 0) {
|
||||
@@ -633,15 +755,12 @@
|
||||
} else {
|
||||
[[NSColor selectedTextBackgroundColor] set];
|
||||
}
|
||||
NSAffineTransform *transform = [NSAffineTransform transform];
|
||||
[transform translateXBy:expressionOrigin.x
|
||||
yBy:expressionOrigin.y];
|
||||
[transform concat];
|
||||
NSRectFill([self selectionRect]);
|
||||
[transform invert];
|
||||
[transform concat];
|
||||
}
|
||||
|
||||
[transform invert];
|
||||
[transform concat];
|
||||
|
||||
// Draw the expression
|
||||
[[NSColor textColor] set];
|
||||
[self.expressionStorage.rootLayout drawAtPoint:expressionOrigin];
|
||||
|
||||
@@ -26,6 +26,8 @@
|
||||
#pragma mark Cache Methods
|
||||
- (CTLineRef)lineForPrivateCacheIndex:(NSUInteger)index
|
||||
generator:(CTLineRef (^)())generator;
|
||||
- (id)objectForPrivateCacheIndex:(NSUInteger)index
|
||||
generator:(id (^)())generator;
|
||||
|
||||
// Should also implement accessor method for special function type:
|
||||
// - (MPCustomFunction *)customFunction
|
||||
@@ -34,10 +36,12 @@
|
||||
// }
|
||||
|
||||
#pragma mark Size and Drawing Methods
|
||||
- (BOOL)childAtIndexUsesSmallSize:(NSUInteger)index; // May be implemented
|
||||
- (NSPoint)offsetOfChildLayoutAtIndex:(NSUInteger)index; // To be implemented
|
||||
- (NSIndexPath *)indexPathForMousePoint:(NSPoint)point; // To be implemented
|
||||
- (NSIndexPath *)indexPathForMousePoint:(NSPoint)point;
|
||||
- (NSIndexPath *)indexPathForLocalMousePoint:(NSPoint)point; // To be implemented
|
||||
- (NSRect)generateBounds; // To be implemented
|
||||
- (void)drawAtPoint:(NSPoint)point; // To be implemented
|
||||
- (void)draw; // To be implemented
|
||||
|
||||
// Specify the child that is used when the cursor enters the function from the left or right respectively
|
||||
- (NSUInteger)indexOfLeadingChild; // To be implemented
|
||||
@@ -46,5 +50,8 @@
|
||||
// The index of the child before (left) or after (right) the child at @c index. return NSNotFound if there is no child before or after @c index.
|
||||
- (NSUInteger)indexOfChildBeforeChildAtIndex:(NSUInteger)index; // May be implemented
|
||||
- (NSUInteger)indexOfChildAfterChildAtIndex:(NSUInteger)index; // May be implemented
|
||||
- (NSUInteger)indexOfChildBelowChildAtIndex:(NSUInteger)index; // May be implemented
|
||||
- (NSUInteger)indexOfChildAboveChildAtIndex:(NSUInteger)index; // May be implemented
|
||||
- (NSIndexSet *)indexesOfRemainingChildren; // May be implemented
|
||||
|
||||
@end
|
||||
@@ -12,6 +12,10 @@
|
||||
|
||||
#import "MPSumFunction.h"
|
||||
#import "MPSumFunctionLayout.h"
|
||||
#import "MPParenthesisFunction.h"
|
||||
#import "MPParenthesisFunctionLayout.h"
|
||||
|
||||
#import "NSIndexPath+MPAdditions.h"
|
||||
|
||||
@implementation MPFunctionLayout
|
||||
|
||||
@@ -22,6 +26,8 @@
|
||||
Class class = [function class];
|
||||
if (class == [MPSumFunction class]) {
|
||||
return [[MPSumFunctionLayout alloc] initWithFunction:function parent:parent];
|
||||
} else if (class == [MPParenthesisFunction class]) {
|
||||
return [[MPParenthesisFunctionLayout alloc] initWithFunction:function parent:parent];
|
||||
}
|
||||
return [[self alloc] initWithFunction:function
|
||||
parent:parent];
|
||||
@@ -51,6 +57,13 @@
|
||||
return (__bridge CTLineRef)(lineObject);
|
||||
}
|
||||
|
||||
- (id)objectForPrivateCacheIndex:(NSUInteger)index
|
||||
generator:(id (^)())generator
|
||||
{
|
||||
NSUInteger actualIndex = self.function.numberOfChildren + index;
|
||||
return [self cachableObjectForIndex:actualIndex generator:generator];
|
||||
}
|
||||
|
||||
- (MPLayout *)childLayoutAtIndex:(NSUInteger)index
|
||||
{
|
||||
return [self cachableObjectForIndex:index generator:^id{
|
||||
@@ -58,11 +71,36 @@
|
||||
MPExpressionLayout *layout = [[MPExpressionLayout alloc] initWithExpression:child
|
||||
parent:self];
|
||||
layout.flipped = self.flipped;
|
||||
layout.usesSmallSize = (index == 0 || index == 1) ? YES : self.usesSmallSize;
|
||||
layout.usesSmallSize = self.usesSmallSize ? YES : [self childAtIndexUsesSmallSize:index];
|
||||
return layout;
|
||||
}];
|
||||
}
|
||||
|
||||
- (BOOL)childAtIndexUsesSmallSize:(NSUInteger)index
|
||||
{
|
||||
return NO;
|
||||
}
|
||||
|
||||
- (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];
|
||||
}
|
||||
}
|
||||
return [self indexPathForLocalMousePoint:point];
|
||||
}
|
||||
|
||||
- (NSUInteger)indexOfChildBeforeChildAtIndex:(NSUInteger)index
|
||||
{
|
||||
return NSNotFound;
|
||||
@@ -73,4 +111,19 @@
|
||||
return NSNotFound;
|
||||
}
|
||||
|
||||
- (NSUInteger)indexOfChildBelowChildAtIndex:(NSUInteger)index
|
||||
{
|
||||
return index;
|
||||
}
|
||||
|
||||
- (NSUInteger)indexOfChildAboveChildAtIndex:(NSUInteger)index
|
||||
{
|
||||
return index;
|
||||
}
|
||||
|
||||
- (NSIndexSet *)indexesOfRemainingChildren
|
||||
{
|
||||
return [NSIndexSet indexSet];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
24
MathPad/MPFunctionsViewController.h
Normal file
24
MathPad/MPFunctionsViewController.h
Normal file
@@ -0,0 +1,24 @@
|
||||
//
|
||||
// MPFunctionsViewController.h
|
||||
// MathPad
|
||||
//
|
||||
// Created by Kim Wittenburg on 28.09.14.
|
||||
// Copyright (c) 2014 Kim Wittenburg. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Cocoa/Cocoa.h>
|
||||
|
||||
@class MPFunctionsCollectionView;
|
||||
|
||||
@interface MPFunctionsViewController : NSViewController
|
||||
|
||||
- (id)init;
|
||||
|
||||
@property (weak) IBOutlet MPFunctionsCollectionView *collectionView;
|
||||
@property (nonatomic, strong) NSArray *functionPrototypes;
|
||||
@property (nonatomic, strong) NSString *currentDescription;
|
||||
|
||||
@property (nonatomic, weak) id target;
|
||||
@property (nonatomic) SEL action; // 1 argument: The function to insert
|
||||
|
||||
@end
|
||||
252
MathPad/MPFunctionsViewController.m
Normal file
252
MathPad/MPFunctionsViewController.m
Normal file
@@ -0,0 +1,252 @@
|
||||
//
|
||||
// MPFunctionsViewController.m
|
||||
// MathPad
|
||||
//
|
||||
// Created by Kim Wittenburg on 28.09.14.
|
||||
// Copyright (c) 2014 Kim Wittenburg. All rights reserved.
|
||||
//
|
||||
|
||||
#import "MPFunctionsViewController.h"
|
||||
#import "MPFunction.h"
|
||||
#import "MPFunctionLayout.h"
|
||||
|
||||
#import "MPSumFunction.h"
|
||||
#import "MPParenthesisFunction.h"
|
||||
|
||||
|
||||
@class MPFunctionTemplatePrototype;
|
||||
|
||||
@interface MPFunctionsCollectionView : NSCollectionView
|
||||
|
||||
@property (nonatomic, weak) MPFunctionTemplatePrototype *hoverItem;
|
||||
|
||||
@property (nonatomic, weak) id target;
|
||||
@property (nonatomic) SEL action;
|
||||
|
||||
@end
|
||||
|
||||
|
||||
@interface MPFunctionTemplateView : NSView
|
||||
|
||||
@property (nonatomic, strong) MPFunction *functionTemplate;
|
||||
@property (readonly, nonatomic, strong) MPFunctionLayout *functionTemplateLayout;
|
||||
@property (nonatomic, strong) NSTrackingArea *trackingArea;
|
||||
@property (nonatomic) BOOL mouseOver;
|
||||
|
||||
@end
|
||||
|
||||
|
||||
|
||||
@interface MPFunctionTemplatePrototype : NSCollectionViewItem
|
||||
@end
|
||||
|
||||
|
||||
@implementation MPFunctionsCollectionView
|
||||
|
||||
- (void)mouseDown:(NSEvent *)theEvent
|
||||
{
|
||||
}
|
||||
|
||||
- (void)mouseUp:(NSEvent *)theEvent
|
||||
{
|
||||
NSPoint pointInView = [self convertPoint:theEvent.locationInWindow
|
||||
fromView:nil];
|
||||
for (NSUInteger index = 0; index < self.content.count; index++) {
|
||||
NSCollectionViewItem *viewItem = [self itemAtIndex:index];
|
||||
if (NSMouseInRect(pointInView, viewItem.view.frame, self.isFlipped)) {
|
||||
if (self.target && self.action) {
|
||||
[self.target performSelector:self.action
|
||||
withObject:[viewItem.representedObject copy]
|
||||
afterDelay:0.0];
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
|
||||
|
||||
@implementation MPFunctionTemplateView
|
||||
|
||||
- (void)updateTrackingAreas
|
||||
{
|
||||
if (!self.trackingArea) {
|
||||
self.trackingArea = [[NSTrackingArea alloc] initWithRect:self.bounds
|
||||
options:NSTrackingMouseEnteredAndExited|NSTrackingActiveInKeyWindow|NSTrackingInVisibleRect
|
||||
owner:self
|
||||
userInfo:nil];
|
||||
[self addTrackingArea:self.trackingArea];
|
||||
}
|
||||
[super updateTrackingAreas];
|
||||
}
|
||||
|
||||
- (void)mouseEntered:(NSEvent *)theEvent
|
||||
{
|
||||
self.mouseOver = YES;
|
||||
self.needsDisplay = YES;
|
||||
}
|
||||
|
||||
- (void)mouseExited:(NSEvent *)theEvent
|
||||
{
|
||||
self.mouseOver = NO;
|
||||
self.needsDisplay = YES;
|
||||
}
|
||||
|
||||
- (void)setFunctionTemplate:(MPFunction *)functionTemplate
|
||||
{
|
||||
_functionTemplate = functionTemplate;
|
||||
_functionTemplateLayout = nil;
|
||||
}
|
||||
|
||||
@synthesize functionTemplateLayout = _functionTemplateLayout;
|
||||
- (MPFunctionLayout *)functionTemplateLayout
|
||||
{
|
||||
if (!_functionTemplateLayout) {
|
||||
_functionTemplateLayout = [MPFunctionLayout functionLayoutForFunction:self.functionTemplate
|
||||
parent:nil];
|
||||
_functionTemplateLayout.usesSmallSize = YES;
|
||||
}
|
||||
return _functionTemplateLayout;
|
||||
}
|
||||
|
||||
- (NSSize)intrinsicContentSize
|
||||
{
|
||||
return [self.functionTemplateLayout bounds].size;
|
||||
}
|
||||
|
||||
- (BOOL)isOpaque
|
||||
{
|
||||
return NO;
|
||||
}
|
||||
|
||||
- (void)drawRect:(NSRect)dirtyRect
|
||||
{
|
||||
if (self.mouseOver) {
|
||||
[[NSColor selectedTextBackgroundColor] set];
|
||||
NSBezierPath *background = [NSBezierPath bezierPathWithRoundedRect:self.bounds
|
||||
xRadius:10
|
||||
yRadius:10];
|
||||
[background fill];
|
||||
}
|
||||
[[NSColor textColor] set];
|
||||
NSPoint origin = NSMakePoint((self.bounds.size.width - self.functionTemplateLayout.bounds.size.width) / 2, (self.bounds.size.height - self.functionTemplateLayout.bounds.size.height) / 2);
|
||||
origin.y -= self.functionTemplateLayout.bounds.origin.y;
|
||||
[self.functionTemplateLayout drawAtPoint:origin];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
|
||||
|
||||
@implementation MPFunctionTemplatePrototype
|
||||
|
||||
static void *MPFunctionTemplateViewMouseOverContext = @"MPFunctionTemplateViewMouseOverContext";
|
||||
|
||||
- (id)initWithCoder:(NSCoder *)aDecoder
|
||||
{
|
||||
self = [super initWithCoder:aDecoder];
|
||||
if (self) {
|
||||
MPFunctionTemplateView *view = (MPFunctionTemplateView *)self.view;
|
||||
[view addObserver:self
|
||||
forKeyPath:@"mouseOver"
|
||||
options:0
|
||||
context:MPFunctionTemplateViewMouseOverContext];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)observeValueForKeyPath:(NSString *)keyPath
|
||||
ofObject:(id)object
|
||||
change:(NSDictionary *)change
|
||||
context:(void *)context
|
||||
{
|
||||
if (context == MPFunctionTemplateViewMouseOverContext) {
|
||||
MPFunctionTemplateView *view = (MPFunctionTemplateView *)self.view;
|
||||
((MPFunctionsCollectionView *)self.collectionView).hoverItem = view.mouseOver ? self : nil;
|
||||
} else {
|
||||
[super observeValueForKeyPath:keyPath
|
||||
ofObject:object
|
||||
change:change
|
||||
context:context];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)setRepresentedObject:(id)representedObject
|
||||
{
|
||||
[super setRepresentedObject:representedObject];
|
||||
((MPFunctionTemplateView *)self.view).functionTemplate = representedObject;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
|
||||
|
||||
@interface MPFunctionsViewController ()
|
||||
|
||||
@end
|
||||
|
||||
@implementation MPFunctionsViewController
|
||||
|
||||
- (id)init
|
||||
{
|
||||
return [self initWithNibName:@"MPFunctionsViewController"
|
||||
bundle:[NSBundle bundleForClass:[self class]]];
|
||||
}
|
||||
|
||||
- (id)initWithNibName:(NSString *)nibNameOrNil
|
||||
bundle:(NSBundle *)nibBundleOrNil
|
||||
{
|
||||
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
|
||||
if (self) {
|
||||
self.functionPrototypes = @[[[MPSumFunction alloc] init], [[MPParenthesisFunction alloc] init]];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
static void *MPCollectionViewHoverItemChangeContext = @"MPCollectionViewHoverItemChangeContext";
|
||||
|
||||
- (void)loadView
|
||||
{
|
||||
[super loadView];
|
||||
[self.collectionView addObserver:self
|
||||
forKeyPath:@"hoverItem"
|
||||
options:0
|
||||
context:MPCollectionViewHoverItemChangeContext];
|
||||
self.collectionView.target = self.target;
|
||||
self.collectionView.action = self.action;
|
||||
}
|
||||
|
||||
- (void)setTarget:(id)target
|
||||
{
|
||||
_target = target;
|
||||
if (self.collectionView) {
|
||||
self.collectionView.target = target;
|
||||
}
|
||||
}
|
||||
|
||||
- (void)setAction:(SEL)action
|
||||
{
|
||||
_action = action;
|
||||
if (self.collectionView) {
|
||||
self.collectionView.action = action;
|
||||
}
|
||||
}
|
||||
|
||||
- (void)observeValueForKeyPath:(NSString *)keyPath
|
||||
ofObject:(id)object
|
||||
change:(NSDictionary *)change
|
||||
context:(void *)context
|
||||
{
|
||||
if (context == MPCollectionViewHoverItemChangeContext) {
|
||||
self.currentDescription = [[self.collectionView.hoverItem.representedObject class] performSelector:@selector(localizedFunctionName)];
|
||||
} else {
|
||||
[super observeValueForKeyPath:keyPath
|
||||
ofObject:object
|
||||
change:change
|
||||
context:context];
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
83
MathPad/MPFunctionsViewController.xib
Normal file
83
MathPad/MPFunctionsViewController.xib
Normal file
@@ -0,0 +1,83 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="6245" systemVersion="13F34" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES">
|
||||
<dependencies>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="6245"/>
|
||||
</dependencies>
|
||||
<objects>
|
||||
<customObject id="-2" userLabel="File's Owner" customClass="MPFunctionsViewController">
|
||||
<connections>
|
||||
<outlet property="collectionView" destination="QmA-Ge-oq3" id="mYG-bs-5TG"/>
|
||||
<outlet property="view" destination="Hz6-mo-xeY" id="0bl-1N-x8E"/>
|
||||
</connections>
|
||||
</customObject>
|
||||
<customObject id="-1" userLabel="First Responder" customClass="FirstResponder"/>
|
||||
<customObject id="-3" userLabel="Application" customClass="NSObject"/>
|
||||
<customView id="Hz6-mo-xeY" customClass="MPWhiteView">
|
||||
<rect key="frame" x="0.0" y="0.0" width="320" height="185"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<subviews>
|
||||
<scrollView borderType="none" autohidesScrollers="YES" horizontalLineScroll="10" horizontalPageScroll="10" verticalLineScroll="10" verticalPageScroll="10" usesPredominantAxisScrolling="NO" translatesAutoresizingMaskIntoConstraints="NO" id="9w0-UQ-Fqx">
|
||||
<rect key="frame" x="10" y="25" width="300" height="150"/>
|
||||
<clipView key="contentView" copiesOnScroll="NO" id="Z8C-m4-8Mb">
|
||||
<rect key="frame" x="1" y="1" width="248" height="158"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<collectionView selectable="YES" id="QmA-Ge-oq3" customClass="MPFunctionsCollectionView">
|
||||
<rect key="frame" x="0.0" y="0.0" width="248" height="158"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<color key="primaryBackgroundColor" name="controlBackgroundColor" catalog="System" colorSpace="catalog"/>
|
||||
<connections>
|
||||
<binding destination="-2" name="content" keyPath="functionPrototypes" id="sPD-4B-zL5"/>
|
||||
<outlet property="itemPrototype" destination="4Wf-e2-Nmy" id="v9O-tD-Y7U"/>
|
||||
</connections>
|
||||
</collectionView>
|
||||
</subviews>
|
||||
</clipView>
|
||||
<scroller key="horizontalScroller" hidden="YES" verticalHuggingPriority="750" horizontal="YES" id="umr-K7-88h">
|
||||
<rect key="frame" x="1" y="144" width="233" height="15"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
</scroller>
|
||||
<scroller key="verticalScroller" hidden="YES" verticalHuggingPriority="750" doubleValue="1" horizontal="NO" id="MEs-Qt-Wze">
|
||||
<rect key="frame" x="234" y="1" width="15" height="143"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
</scroller>
|
||||
</scrollView>
|
||||
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="D89-Gi-YJm">
|
||||
<rect key="frame" x="-2" y="0.0" width="324" height="17"/>
|
||||
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" alignment="center" title="Description" id="xrL-Xy-aRm">
|
||||
<font key="font" metaFont="system"/>
|
||||
<color key="textColor" name="disabledControlTextColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
|
||||
</textFieldCell>
|
||||
<connections>
|
||||
<binding destination="-2" name="value" keyPath="currentDescription" id="0Vx-OA-1Zy">
|
||||
<dictionary key="options">
|
||||
<string key="NSNullPlaceholder">Choose an Element</string>
|
||||
</dictionary>
|
||||
</binding>
|
||||
</connections>
|
||||
</textField>
|
||||
</subviews>
|
||||
<constraints>
|
||||
<constraint firstAttribute="bottom" secondItem="D89-Gi-YJm" secondAttribute="bottom" id="6QP-Uy-i2A"/>
|
||||
<constraint firstItem="9w0-UQ-Fqx" firstAttribute="leading" secondItem="Hz6-mo-xeY" secondAttribute="leading" constant="10" id="GOC-rC-AE6"/>
|
||||
<constraint firstItem="9w0-UQ-Fqx" firstAttribute="centerX" secondItem="D89-Gi-YJm" secondAttribute="centerX" id="Qk9-hA-Jcj"/>
|
||||
<constraint firstItem="9w0-UQ-Fqx" firstAttribute="top" secondItem="Hz6-mo-xeY" secondAttribute="top" constant="10" id="RFi-H1-0CV"/>
|
||||
<constraint firstItem="D89-Gi-YJm" firstAttribute="leading" secondItem="Hz6-mo-xeY" secondAttribute="leading" id="Rup-Ep-vEV"/>
|
||||
<constraint firstItem="D89-Gi-YJm" firstAttribute="top" secondItem="9w0-UQ-Fqx" secondAttribute="bottom" constant="8" symbolic="YES" id="xGL-ZL-fb1"/>
|
||||
<constraint firstAttribute="trailing" secondItem="9w0-UQ-Fqx" secondAttribute="trailing" constant="10" id="zb3-nc-Iai"/>
|
||||
</constraints>
|
||||
<point key="canvasLocation" x="-101" y="140.5"/>
|
||||
</customView>
|
||||
<collectionViewItem id="4Wf-e2-Nmy" customClass="MPFunctionTemplatePrototype">
|
||||
<connections>
|
||||
<outlet property="view" destination="dE9-Vu-psk" id="hX8-fz-7FR"/>
|
||||
</connections>
|
||||
</collectionViewItem>
|
||||
<view id="dE9-Vu-psk" customClass="MPFunctionTemplateView">
|
||||
<rect key="frame" x="0.0" y="0.0" width="50" height="50"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<point key="canvasLocation" x="119" y="-114.5"/>
|
||||
</view>
|
||||
</objects>
|
||||
</document>
|
||||
@@ -42,6 +42,7 @@
|
||||
|
||||
#pragma mark Calculation and Drawing Methods
|
||||
- (CTLineRef)createLineForString:(NSString *)aString;
|
||||
- (CTLineRef)createLineForString:(NSString *)aString usingFont:(NSFont *)font;
|
||||
|
||||
@property (nonatomic, getter = isFlipped) BOOL flipped;
|
||||
@property (nonatomic) BOOL usesSmallSize;
|
||||
|
||||
@@ -136,9 +136,16 @@
|
||||
|
||||
#pragma mark Calculation and Drawing Methods
|
||||
- (CTLineRef)createLineForString:(NSString *)aString
|
||||
{
|
||||
return [self createLineForString:aString
|
||||
usingFont:self.font];
|
||||
}
|
||||
|
||||
- (CTLineRef)createLineForString:(NSString *)aString
|
||||
usingFont:(NSFont *)font
|
||||
{
|
||||
NSAttributedString *text = [[NSAttributedString alloc] initWithString:aString
|
||||
attributes:@{NSFontAttributeName: self.font}];
|
||||
attributes:@{NSFontAttributeName: font}];
|
||||
CFAttributedStringRef attributedString = CFBridgingRetain(text);
|
||||
CTLineRef line = CTLineCreateWithAttributedString(attributedString);
|
||||
CFRelease(attributedString); // TODO: Is this release appropriate?
|
||||
|
||||
15
MathPad/MPParenthesisFunction.h
Normal file
15
MathPad/MPParenthesisFunction.h
Normal file
@@ -0,0 +1,15 @@
|
||||
//
|
||||
// MPParenthesisFunction.h
|
||||
// MathPad
|
||||
//
|
||||
// Created by Kim Wittenburg on 17.09.14.
|
||||
// Copyright (c) 2014 Kim Wittenburg. All rights reserved.
|
||||
//
|
||||
|
||||
#import <MathKit/MathKit.h>
|
||||
|
||||
@interface MPParenthesisFunction : MPFunction
|
||||
|
||||
@property (nonatomic, strong) MPExpression *expression;
|
||||
|
||||
@end
|
||||
90
MathPad/MPParenthesisFunction.m
Normal file
90
MathPad/MPParenthesisFunction.m
Normal file
@@ -0,0 +1,90 @@
|
||||
|
||||
//
|
||||
// MPParenthesisFunction.m
|
||||
// MathPad
|
||||
//
|
||||
// Created by Kim Wittenburg on 17.09.14.
|
||||
// Copyright (c) 2014 Kim Wittenburg. All rights reserved.
|
||||
//
|
||||
|
||||
#import "MPParenthesisFunction.h"
|
||||
#import "MPExpressionEvaluator.h"
|
||||
|
||||
@implementation MPParenthesisFunction
|
||||
|
||||
+ (NSString *)localizedFunctionName
|
||||
{
|
||||
return NSLocalizedString(@"Parenthesis", @"Name of Parenthesis Function");
|
||||
}
|
||||
|
||||
- (instancetype)init
|
||||
{
|
||||
self = [super init];
|
||||
if (self) {
|
||||
_expression = [[MPExpression alloc] init];
|
||||
_expression.parent = self;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)setExpression:(MPExpression *)expression
|
||||
{
|
||||
_expression.parent = nil;
|
||||
_expression = expression;
|
||||
_expression.parent = self;
|
||||
}
|
||||
|
||||
- (NSUInteger)numberOfChildren
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
- (MPExpression *)childAtIndex:(NSUInteger)index
|
||||
{
|
||||
return index == 0 ? self.expression : nil;
|
||||
}
|
||||
|
||||
- (void)setChild:(MPExpression *)child
|
||||
atIndex:(NSUInteger)index
|
||||
{
|
||||
if (index == 0) {
|
||||
self.expression = child;
|
||||
}
|
||||
}
|
||||
|
||||
- (NSArray *)children
|
||||
{
|
||||
return @[self.expression];
|
||||
}
|
||||
|
||||
- (MPTerm *)parseWithError:(MPParseError *__autoreleasing *)error
|
||||
{
|
||||
MPExpressionEvaluator *evaluator = self.expression.evaluator;
|
||||
return [evaluator parseExpectingVariable:NO
|
||||
error:error];
|
||||
}
|
||||
|
||||
- (NSDecimalNumber *)evaluateWithError:(MPParseError *__autoreleasing *)error
|
||||
{
|
||||
return [self.expression evaluateWithError:error];
|
||||
}
|
||||
|
||||
- (NSString *)description
|
||||
{
|
||||
return [NSString stringWithFormat:@"(%@)", self.expression.description];
|
||||
}
|
||||
|
||||
- (NSUInteger)hash
|
||||
{
|
||||
#warning Unimplemented Method
|
||||
return [super hash] * self.expression.hash;
|
||||
}
|
||||
|
||||
- (id)copyWithZone:(NSZone *)zone
|
||||
{
|
||||
MPParenthesisFunction *copy = [[MPParenthesisFunction allocWithZone:zone] init];
|
||||
copy.expression = self.expression.copy;
|
||||
return copy;
|
||||
}
|
||||
|
||||
@end
|
||||
13
MathPad/MPWhiteView.h
Normal file
13
MathPad/MPWhiteView.h
Normal file
@@ -0,0 +1,13 @@
|
||||
//
|
||||
// MPWhiteView.h
|
||||
// MathPad
|
||||
//
|
||||
// Created by Kim Wittenburg on 28.09.14.
|
||||
// Copyright (c) 2014 Kim Wittenburg. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Cocoa/Cocoa.h>
|
||||
|
||||
@interface MPWhiteView : NSView
|
||||
|
||||
@end
|
||||
20
MathPad/MPWhiteView.m
Normal file
20
MathPad/MPWhiteView.m
Normal file
@@ -0,0 +1,20 @@
|
||||
//
|
||||
// MPWhiteView.m
|
||||
// MathPad
|
||||
//
|
||||
// Created by Kim Wittenburg on 28.09.14.
|
||||
// Copyright (c) 2014 Kim Wittenburg. All rights reserved.
|
||||
//
|
||||
|
||||
#import "MPWhiteView.h"
|
||||
|
||||
@implementation MPWhiteView
|
||||
|
||||
- (void)drawRect:(NSRect)dirtyRect {
|
||||
[super drawRect:dirtyRect];
|
||||
|
||||
[[NSColor whiteColor] set];
|
||||
NSRectFill(dirtyRect);
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -7,7 +7,6 @@
|
||||
//
|
||||
|
||||
#import "NSString+MPExpressionElement.h"
|
||||
#import "MPElementParser.h"
|
||||
|
||||
@implementation NSString (MPExpressionElement)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user