From 8f2f7739090bc5acf5073ae3c23c2627ba1da17b Mon Sep 17 00:00:00 2001 From: Kim Wittenburg Date: Tue, 30 Sep 2014 22:19:08 +0200 Subject: [PATCH] Improved Functions Template Chooser --- MathPad/MPExpressionView.m | 80 ++++++++++++++++----------- MathPad/MPFunctionsViewController.m | 62 ++++++++++----------- MathPad/MPFunctionsViewController.xib | 2 +- 3 files changed, 79 insertions(+), 65 deletions(-) diff --git a/MathPad/MPExpressionView.m b/MathPad/MPExpressionView.m index e3647d5..4b89886 100644 --- a/MathPad/MPExpressionView.m +++ b/MathPad/MPExpressionView.m @@ -24,7 +24,7 @@ @interface MPExpressionView () -@property (nonatomic, weak) NSButton *functionsButton; +@property (nonatomic, strong) NSButton *functionsButton; @property (nonatomic, strong) NSPopover *functionsPopover; @property (nonatomic, strong) MPFunctionsViewController *functionsViewController; @@ -312,30 +312,31 @@ expressionStorage.expressionView = self; _expressionStorage = expressionStorage; - NSBundle *frameworkBundle = [NSBundle bundleForClass:[self class]]; - NSImage *image = [frameworkBundle imageForResource:@"FunctionsButtonDisclosure"]; - [image setName:@"FunctionsButtonDisclosure"]; - // Setup the Functions Button - NSButton *button = [[NSButton alloc] initWithFrame:NSZeroRect]; - button.target = self; - button.action = @selector(showFunctions:); - button.buttonType = NSMomentaryChangeButton; - button.bezelStyle = NSShadowlessSquareBezelStyle; - button.bordered = NO; - NSFont *font = [NSFont fontWithName:@"Times New Roman" size:25.0]; - NSAttributedString *attributedTitle = [[NSAttributedString alloc] initWithString:@"Σ" attributes:@{NSFontAttributeName: font, NSForegroundColorAttributeName: [NSColor colorWithWhite:.61 alpha:1]}]; - button.attributedTitle = attributedTitle; - button.imagePosition = NSImageLeft; - button.image = image; - self.functionsButton = button; - [self addSubview:self.functionsButton]; + [self initializeButtons]; - // Setup Selection self.selection = [[MPRangePath alloc] initWithRange:NSMakeRange(0, 0)]; self.caretBlinkRate = 1.0; [self restartCaretTimer]; } +- (void)initializeButtons +{ + NSButton *functionsButton = self.functionsButton; + [self addSubview:functionsButton]; + NSDictionary *variableBindings = NSDictionaryOfVariableBindings(functionsButton); + [self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"[functionsButton]-10-|" + options:0 + metrics:nil + views:variableBindings]]; + [self addConstraint:[NSLayoutConstraint constraintWithItem:functionsButton + attribute:NSLayoutAttributeCenterY + relatedBy:NSLayoutRelationEqual + toItem:self + attribute:NSLayoutAttributeCenterY + multiplier:1 + constant:0]]; +} + #pragma mark Properties - (void)setExpressionStorage:(MPExpressionStorage *)expressionStorage { @@ -358,6 +359,29 @@ self.needsDisplay = YES; } +- (NSButton *)functionsButton +{ + if (!_functionsButton) { + NSBundle *frameworkBundle = [NSBundle bundleForClass:[self class]]; + NSImage *image = [frameworkBundle imageForResource:@"FunctionsButtonDisclosure"]; + [image setName:@"FunctionsButtonDisclosure"]; + NSButton *button = [[NSButton alloc] initWithFrame:NSMakeRect(0, 0, 100, 100)]; + button.translatesAutoresizingMaskIntoConstraints = NO; + button.target = self; + button.action = @selector(showFunctions:); + button.buttonType = NSMomentaryChangeButton; + button.bezelStyle = NSShadowlessSquareBezelStyle; + button.bordered = NO; + NSFont *font = [NSFont fontWithName:@"Times New Roman" size:25.0]; + NSAttributedString *attributedTitle = [[NSAttributedString alloc] initWithString:@"Σ" attributes:@{NSFontAttributeName: font, NSForegroundColorAttributeName: [NSColor colorWithWhite:.61 alpha:1]}]; + button.attributedTitle = attributedTitle; + button.imagePosition = NSImageLeft; + button.image = image; + _functionsButton = button; + } + return _functionsButton; +} + #pragma mark Actions - (void)showFunctions:(id)sender { @@ -429,16 +453,6 @@ [super setFrame:frameRect]; } -- (void)layout -{ - NSSize buttonSize = [self.functionsButton fittingSize]; - self.functionsButton.frame = NSMakeRect(self.bounds.size.width - buttonSize.width - 10, - (self.bounds.size.height - buttonSize.height) / 2, - buttonSize.width, - buttonSize.height); - [super layout]; -} - - (NSSize)intrinsicContentSize { NSSize size = self.expressionStorage.rootLayout.bounds.size; @@ -458,7 +472,7 @@ NSString *characters = theEvent.characters; if ([characters isEqualToString:@"("]) { - [self insertParenthesisFunction]; + [self insertParenthesisFunction:nil]; return; } @@ -466,7 +480,7 @@ NSString *decimalSeparator = [NSRegularExpression escapedPatternForString:[[NSLocale currentLocale] objectForKey:NSLocaleDecimalSeparator]]; NSMutableCharacterSet *allowedCharacters = [NSMutableCharacterSet alphanumericCharacterSet]; - [allowedCharacters addCharactersInString:[NSString stringWithFormat:@"+-*= %@", decimalSeparator]]; + [allowedCharacters addCharactersInString:[NSString stringWithFormat:@"+-*= !%@", decimalSeparator]]; if (characters.length == 1 && [characters stringByTrimmingCharactersInSet:allowedCharacters].length == 0) { [self.expressionStorage replaceSymbolsInRangePath:self.selection withElements:@[characters]]; @@ -476,7 +490,7 @@ } } -- (void)insertParenthesisFunction +- (void)insertParenthesisFunction:(id)sender { MPExpression *selectedElementsExpression = [self.expressionStorage subexpressionWithRangePath:self.selection]; MPParenthesisFunction *function = [[MPParenthesisFunction alloc] init]; @@ -700,7 +714,7 @@ MPExpression *newTargetExpression = [self.expressionStorage elementAtIndexPath:newTargetExpressionPath]; NSIndexPath *newSelectionLocation = [functionPath indexPathByReplacingLastIndexWithIndex:[newTargetExpression locationOfElementAtIndex:functionPath.lastIndex]]; - [self.expressionStorage replaceSymbolsInRangePath:MPMakeRangePath(functionPath, 1) withElements:remainder]; + [self.expressionStorage replaceSymbolsInRangePath:MPMakeRangePath(newSelectionLocation, 1) withElements:remainder]; self.selection = MPMakeRangePath(newSelectionLocation, 0); } } diff --git a/MathPad/MPFunctionsViewController.m b/MathPad/MPFunctionsViewController.m index 0cefe0e..098506e 100644 --- a/MathPad/MPFunctionsViewController.m +++ b/MathPad/MPFunctionsViewController.m @@ -14,11 +14,11 @@ #import "MPParenthesisFunction.h" -@class MPFunctionTemplatePrototype; +@class MPFunctionTemplateItem; @interface MPFunctionsCollectionView : NSCollectionView -@property (nonatomic, weak) MPFunctionTemplatePrototype *hoverItem; +@property (nonatomic, weak) MPFunctionTemplateItem *hoverItem; @property (nonatomic, weak) id target; @property (nonatomic) SEL action; @@ -37,7 +37,8 @@ -@interface MPFunctionTemplatePrototype : NSCollectionViewItem +@interface MPFunctionTemplateItem : NSCollectionViewItem +@property (nonatomic, copy) NSString *templateName; @end @@ -56,7 +57,7 @@ if (NSMouseInRect(pointInView, viewItem.view.frame, self.isFlipped)) { if (self.target && self.action) { [self.target performSelector:self.action - withObject:[viewItem.representedObject copy] + withObject:[[viewItem.representedObject objectForKey:@"function" ] copy] afterDelay:0.0]; } break; @@ -103,6 +104,7 @@ @synthesize functionTemplateLayout = _functionTemplateLayout; - (MPFunctionLayout *)functionTemplateLayout { + if (!_functionTemplateLayout) { _functionTemplateLayout = [MPFunctionLayout functionLayoutForFunction:self.functionTemplate parent:nil]; @@ -140,21 +142,13 @@ -@implementation MPFunctionTemplatePrototype +@implementation MPFunctionTemplateItem static void *MPFunctionTemplateViewMouseOverContext = @"MPFunctionTemplateViewMouseOverContext"; -- (id)initWithCoder:(NSCoder *)aDecoder +- (id)awakeAfterUsingCoder:(NSCoder *)aDecoder { - self = [super initWithCoder:aDecoder]; - if (self) { - MPFunctionTemplateView *view = (MPFunctionTemplateView *)self.view; - [view addObserver:self - forKeyPath:@"mouseOver" - options:0 - context:MPFunctionTemplateViewMouseOverContext]; - } - return self; + return [super awakeAfterUsingCoder:aDecoder]; } - (void)observeValueForKeyPath:(NSString *)keyPath @@ -175,8 +169,14 @@ static void *MPFunctionTemplateViewMouseOverContext = @"MPFunctionTemplateViewMo - (void)setRepresentedObject:(id)representedObject { + MPFunctionTemplateView *view = (MPFunctionTemplateView *)self.view; + view.functionTemplate = [representedObject objectForKey:@"function"]; + self.templateName = [representedObject objectForKey:@"name"]; + [view addObserver:self + forKeyPath:@"mouseOver" + options:0 + context:MPFunctionTemplateViewMouseOverContext]; [super setRepresentedObject:representedObject]; - ((MPFunctionTemplateView *)self.view).functionTemplate = representedObject; } @end @@ -195,21 +195,14 @@ static void *MPFunctionTemplateViewMouseOverContext = @"MPFunctionTemplateViewMo bundle:[NSBundle bundleForClass:[self class]]]; } -- (id)initWithNibName:(NSString *)nibNameOrNil - bundle:(NSBundle *)nibBundleOrNil +- (void)awakeFromNib { - 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.functionPrototypes = @[ + @{@"function": [[MPSumFunction alloc] init], + @"name": NSLocalizedString(@"Sum", @"Sum Function Name")}, + @{@"function": [[MPParenthesisFunction alloc] init], + @"name": NSLocalizedString(@"Parenthesis", @"Parenthesis Function Name")} + ]; [self.collectionView addObserver:self forKeyPath:@"hoverItem" options:0 @@ -218,6 +211,13 @@ static void *MPCollectionViewHoverItemChangeContext = @"MPCollectionViewHoverIte self.collectionView.action = self.action; } +static void *MPCollectionViewHoverItemChangeContext = @"MPCollectionViewHoverItemChangeContext"; + +- (void)setView:(NSView *)view +{ + [super setView:view]; +} + - (void)setTarget:(id)target { _target = target; @@ -240,7 +240,7 @@ static void *MPCollectionViewHoverItemChangeContext = @"MPCollectionViewHoverIte context:(void *)context { if (context == MPCollectionViewHoverItemChangeContext) { - self.currentDescription = [[self.collectionView.hoverItem.representedObject class] performSelector:@selector(localizedFunctionName)]; + self.currentDescription = self.collectionView.hoverItem.templateName; } else { [super observeValueForKeyPath:keyPath ofObject:object diff --git a/MathPad/MPFunctionsViewController.xib b/MathPad/MPFunctionsViewController.xib index 9f5f5c0..da61fbd 100644 --- a/MathPad/MPFunctionsViewController.xib +++ b/MathPad/MPFunctionsViewController.xib @@ -69,7 +69,7 @@ - +