Archived
1

Improved Selection Algorithm

This commit is contained in:
Kim Wittenburg
2014-09-07 16:49:21 +02:00
parent 88f54b742f
commit d30dbdda9b

View File

@@ -6,8 +6,6 @@
// Copyright (c) 2014 Kim Wittenburg. All rights reserved. // Copyright (c) 2014 Kim Wittenburg. All rights reserved.
// //
#warning X-Origin is not working yet
#import "MPExpressionView.h" #import "MPExpressionView.h"
#import "MPExpressionStorage.h" #import "MPExpressionStorage.h"
#import "MPExpressionLayout.h" #import "MPExpressionLayout.h"
@@ -18,6 +16,8 @@
#import "MPSumFunction.h" #import "MPSumFunction.h"
@interface MPExpressionView () @interface MPExpressionView ()
@property (nonatomic, weak) NSButton *functionsButton; @property (nonatomic, weak) NSButton *functionsButton;
@@ -28,23 +28,37 @@
@property (nonatomic, getter = isSelectionModifyingStart) BOOL selectionModifyingStart; @property (nonatomic, getter = isSelectionModifyingStart) BOOL selectionModifyingStart;
@property (nonatomic, strong) NSIndexPath *mouseAnchor;
@end @end
@interface MPExpressionView (MPDrawing) @interface MPExpressionView (MPDrawing)
- (NSPoint)expressionOrigin; - (NSPoint)expressionOrigin;
@end @end
@interface MPExpressionView (MPSelection) @interface MPExpressionView (MPSelection)
- (void)restartCaretTimer; - (void)restartCaretTimer;
- (void)updateCaret:(NSTimer *)timer; - (void)updateCaret:(NSTimer *)timer;
- (NSRect)selectionRect; - (NSRect)selectionRect;
- (void)selectRangePathWithLocation:(NSIndexPath *)location length:(NSUInteger)length; - (NSIndexPath *)selectionToTheRightOf:(NSIndexPath *)selection
selectWords:(BOOL)flag;
- (NSIndexPath *)selectionToTheLeftOf:(NSIndexPath *)selection
selectWords:(BOOL)flag;
- (MPRangePath *)rangePathEnclosingAnchor:(NSIndexPath *)anchor
newSelection:(NSIndexPath *)newSelection;
@end @end
@implementation MPExpressionView (MPDrawing) @implementation MPExpressionView (MPDrawing)
- (NSPoint)expressionOrigin - (NSPoint)expressionOrigin
@@ -56,6 +70,8 @@
@end @end
@implementation MPExpressionView (MPSelection) @implementation MPExpressionView (MPSelection)
- (void)restartCaretTimer - (void)restartCaretTimer
@@ -85,22 +101,64 @@
return selectionRect; return selectionRect;
} }
- (void)selectRangePathWithLocation:(NSIndexPath *)location length:(NSUInteger)length - (NSIndexPath *)selectionToTheRightOf:(NSIndexPath *)selection
selectWords:(BOOL)flag
{ {
MPExpression *targetExpression = [self.expressionStorage elementAtIndexPath:[location indexPathByRemovingLastIndex]]; MPExpression *targetExpression = [self.expressionStorage elementAtIndexPath:[selection indexPathByRemovingLastIndex]];
NSUInteger locationIndex = location.lastIndex; NSUInteger locationInTarget = selection.lastIndex;
if (locationIndex > targetExpression.length) { NSUInteger locationInElement;
locationIndex = targetExpression.length; NSUInteger targetElementIndex = [targetExpression indexOfElementAtSymbolLocation:locationInTarget
offset:&locationInElement];
id<MPExpressionElement> targetElement;
if (targetElementIndex < targetExpression.numberOfElements) {
targetElement = [targetExpression elementAtIndex:targetElementIndex];
} }
NSUInteger lastSelectedIndex = location.lastIndex + length; if (locationInElement == 0 && !flag) {
if (lastSelectedIndex > targetExpression.length) { NSLog(@"Move to next");
lastSelectedIndex = targetExpression.length; // Move to next element
} else if (locationInTarget < targetExpression.length) {
if (flag) {
locationInTarget = [targetExpression locationOfElementAtIndex:targetElementIndex+1];
} else {
locationInTarget++;
}
} }
self.selection = MPMakeRangePath([location indexPathByReplacingLastIndexWithIndex:locationIndex],lastSelectedIndex - locationIndex); return [selection indexPathByReplacingLastIndexWithIndex:locationInTarget];
}
- (NSIndexPath *)selectionToTheLeftOf:(NSIndexPath *)selection
selectWords:(BOOL)flag
{
MPExpression *targetExpression = [self.expressionStorage elementAtIndexPath:[selection indexPathByRemovingLastIndex]];
NSUInteger locationInTarget = selection.lastIndex;
NSUInteger locationInElement;
NSUInteger targetElementIndex = [targetExpression indexOfElementAtSymbolLocation:locationInTarget
offset:&locationInElement];
if (locationInElement == 0 && !flag) {
// Move to previous element
} else if (locationInTarget > 0) {
if (flag) {
if (locationInElement == 0) {
targetElementIndex--;
}
locationInTarget = [targetExpression locationOfElementAtIndex:targetElementIndex];
} else {
locationInTarget--;
}
}
return [selection indexPathByReplacingLastIndexWithIndex:locationInTarget];
}
- (MPRangePath *)rangePathEnclosingAnchor:(NSIndexPath *)anchor
newSelection:(NSIndexPath *)newSelection
{
} }
@end @end
@implementation MPExpressionView @implementation MPExpressionView
#pragma mark Creation Methods #pragma mark Creation Methods
@@ -125,7 +183,7 @@
- (void)initializeExpressionView - (void)initializeExpressionView
{ {
// Setup the Expression Storage // Setup the Expression Storage
MPExpressionStorage *expressionStorage = [[MPExpressionStorage alloc] initWithElements:@[@"12345", [[MPSumFunction alloc] init], [[MPSumFunction alloc] init]]]; MPExpressionStorage *expressionStorage = [[MPExpressionStorage alloc] initWithElements:@[@"12345", [[MPSumFunction alloc] init]]];
expressionStorage.expressionView = self; expressionStorage.expressionView = self;
_expressionStorage = expressionStorage; _expressionStorage = expressionStorage;
@@ -207,7 +265,7 @@
{ {
NSString *characters = theEvent.characters; NSString *characters = theEvent.characters;
NSMutableCharacterSet *allowedCharacters = [NSMutableCharacterSet alphanumericCharacterSet]; NSMutableCharacterSet *allowedCharacters = [NSMutableCharacterSet alphanumericCharacterSet];
[allowedCharacters addCharactersInString:@"+-*/= "]; [allowedCharacters addCharactersInString:@"+-*= "];
if (characters.length == 1 && [characters stringByTrimmingCharactersInSet:allowedCharacters].length == 0) { if (characters.length == 1 && [characters stringByTrimmingCharactersInSet:allowedCharacters].length == 0) {
MPExpression *targetExpression = [self.expressionStorage elementAtIndexPath:[self.selection.location indexPathByRemovingLastIndex]]; MPExpression *targetExpression = [self.expressionStorage elementAtIndexPath:[self.selection.location indexPathByRemovingLastIndex]];
[targetExpression replaceSymbolsInRange:self.selection.rangeAtLastIndex withElements:@[characters]]; [targetExpression replaceSymbolsInRange:self.selection.rangeAtLastIndex withElements:@[characters]];
@@ -222,9 +280,9 @@
if (self.selection.length > 0) { if (self.selection.length > 0) {
self.selection = MPMakeRangePath(self.selection.maxRangePath, 0); self.selection = MPMakeRangePath(self.selection.maxRangePath, 0);
} else { } else {
NSIndexPath *newSelectionLocation = [self.selection.location indexPathByIncrementingLastIndex]; NSIndexPath *newSelectionLocation = [self selectionToTheRightOf:self.selection.location
[self selectRangePathWithLocation:newSelectionLocation selectWords:NO];
length:0]; self.selection = MPMakeRangePath(newSelectionLocation, 0);
} }
} }
@@ -232,48 +290,27 @@
{ {
if (self.selection.length > 0) { if (self.selection.length > 0) {
self.selection = MPMakeRangePath(self.selection.location, 0); self.selection = MPMakeRangePath(self.selection.location, 0);
[self selectRangePathWithLocation:self.selection.location length:0];
} else { } else {
NSUInteger selectionIndex = self.selection.location.lastIndex; NSIndexPath *newSelectionLocation = [self selectionToTheLeftOf:self.selection.location
if (selectionIndex > 0) { selectWords:NO];
--selectionIndex; self.selection = MPMakeRangePath(newSelectionLocation, 0);
}
NSIndexPath *newSelectionLocation = [self.selection.location indexPathByReplacingLastIndexWithIndex:selectionIndex];
[self selectRangePathWithLocation:newSelectionLocation
length:0];
} }
} }
- (void)moveWordRight:(id)sender - (void)moveWordRight:(id)sender
{ {
NSIndexPath *location; NSIndexPath *location = self.selection.maxRangePath;
if (self.selection.length > 0) { NSIndexPath *newSelectionLocation = [self selectionToTheRightOf:location
location = self.selection.maxRangePath; selectWords:YES];
} else { self.selection = MPMakeRangePath(newSelectionLocation, 0);
location = self.selection.location;
}
MPExpression *targetExpression = [self.expressionStorage elementAtIndexPath:[location indexPathByRemovingLastIndex]];
NSUInteger locationInTarget = NSMaxRange(self.selection.rangeAtLastIndex);
NSUInteger offset;
NSUInteger elementIndex = [targetExpression indexOfElementAtSymbolLocation:locationInTarget
offset:&offset];
NSUInteger newLocation = locationInTarget + [targetExpression elementAtIndex:elementIndex].length - offset;
[self selectRangePathWithLocation:[location indexPathByReplacingLastIndexWithIndex:newLocation]
length:0];
} }
- (void)moveWordLeft:(id)sender - (void)moveWordLeft:(id)sender
{ {
MPExpression *targetExpression = [self.expressionStorage elementAtIndexPath:[self.selection.location indexPathByRemovingLastIndex]]; NSIndexPath *location = self.selection.location;
NSUInteger offset; NSIndexPath *newSelectionLocation = [self selectionToTheLeftOf:location
NSUInteger elementIndex = [targetExpression indexOfElementAtSymbolLocation:self.selection.location.lastIndex offset:&offset]; selectWords:YES];
NSUInteger newLocation = self.selection.location.lastIndex; self.selection = MPMakeRangePath(newSelectionLocation, 0);
if (offset > 0) {
newLocation -= newLocation - offset > 0 ? offset : newLocation;
} else if (newLocation > 0) {
newLocation -= [targetExpression elementAtIndex:elementIndex-1].length;
}
self.selection = MPMakeRangePath([self.selection.location indexPathByReplacingLastIndexWithIndex:newLocation], 0);
} }
- (void)moveToBeginningOfLine:(id)sender - (void)moveToBeginningOfLine:(id)sender
@@ -292,17 +329,16 @@
if (self.selection.length == 0) { if (self.selection.length == 0) {
self.selectionModifyingStart = YES; self.selectionModifyingStart = YES;
} }
NSUInteger start = self.selection.location.lastIndex; NSIndexPath *location = self.selection.location;
NSUInteger length = self.selection.length; NSIndexPath *maxLocation = self.selection.maxRangePath;
if (self.selectionModifyingStart) { if (self.selectionModifyingStart) {
if (start > 0) { location = [self selectionToTheLeftOf:location
--start; selectWords:NO];
++length;
}
} else { } else {
--length; maxLocation = [self selectionToTheLeftOf:maxLocation
selectWords:NO];
} }
self.selection = MPMakeRangePath([self.selection.location indexPathByReplacingLastIndexWithIndex:start], length); self.selection = MPMakeRangePath(location, maxLocation.lastIndex-location.lastIndex);
} }
- (void)moveRightAndModifySelection:(id)sender - (void)moveRightAndModifySelection:(id)sender
@@ -310,26 +346,57 @@
if (self.selection.length == 0) { if (self.selection.length == 0) {
self.selectionModifyingStart = NO; self.selectionModifyingStart = NO;
} }
NSUInteger start = self.selection.location.lastIndex; NSIndexPath *location = self.selection.location;
NSUInteger length = self.selection.length; NSIndexPath *maxLocation = self.selection.maxRangePath;
if (self.selectionModifyingStart) { if (self.selectionModifyingStart) {
++start; location = [self selectionToTheRightOf:location
--length; selectWords:NO];
} else { } else {
++length; maxLocation = [self selectionToTheRightOf:maxLocation
selectWords:NO];
} }
[self selectRangePathWithLocation:[self.selection.location indexPathByReplacingLastIndexWithIndex:start] self.selection = MPMakeRangePath(location, maxLocation.lastIndex-location.lastIndex);
length:length];
} }
- (void)moveWordRightAndModifySelection:(id)sender - (void)moveWordRightAndModifySelection:(id)sender
{ {
#warning Unimplemented Method if (self.selection.length == 0) {
self.selectionModifyingStart = NO;
}
NSIndexPath *location = self.selection.location;
NSIndexPath *maxLocation = self.selection.maxRangePath;
if (self.selectionModifyingStart) {
location = [self selectionToTheRightOf:location
selectWords:YES];
if (location.lastIndex > maxLocation.lastIndex) {
location = [location indexPathByReplacingLastIndexWithIndex:maxLocation.lastIndex];
}
} else {
maxLocation = [self selectionToTheRightOf:maxLocation
selectWords:YES];
}
self.selection = MPMakeRangePath(location, maxLocation.lastIndex-location.lastIndex);
} }
- (void)moveWordLeftAndModifySelection:(id)sender - (void)moveWordLeftAndModifySelection:(id)sender
{ {
#warning Unimplemented Method if (self.selection.length == 0) {
self.selectionModifyingStart = YES;
}
NSIndexPath *location = self.selection.location;
NSIndexPath *maxLocation = self.selection.maxRangePath;
if (self.selectionModifyingStart) {
location = [self selectionToTheLeftOf:location
selectWords:YES];
} else {
maxLocation = [self selectionToTheLeftOf:maxLocation
selectWords:YES];
if (maxLocation.lastIndex < location.lastIndex) {
maxLocation = [maxLocation indexPathByReplacingLastIndexWithIndex:location.lastIndex];
}
}
self.selection = MPMakeRangePath(location, maxLocation.lastIndex-location.lastIndex);
} }
- (void)selectAll:(id)sender - (void)selectAll:(id)sender
@@ -359,9 +426,23 @@
pointInView.x -= expressionOrigin.x; pointInView.x -= expressionOrigin.x;
pointInView.y -= expressionOrigin.y; pointInView.y -= expressionOrigin.y;
NSIndexPath *selectionPath = [self.expressionStorage.rootLayout indexPathForMousePoint:pointInView]; NSIndexPath *selectionPath = [self.expressionStorage.rootLayout indexPathForMousePoint:pointInView];
self.mouseAnchor = selectionPath;
self.selection = MPMakeRangePath(selectionPath, 0); self.selection = MPMakeRangePath(selectionPath, 0);
} }
- (void)mouseDragged:(NSEvent *)theEvent
{
NSPoint pointInView = [self convertPoint:theEvent.locationInWindow
fromView:nil];
NSPoint expressionOrigin = self.expressionOrigin;
pointInView.x -= expressionOrigin.x;
pointInView.y -= expressionOrigin.y;
NSIndexPath *mouseSelectionPath = [self.expressionStorage.rootLayout indexPathForMousePoint:pointInView];
self.selection = [self rangePathEnclosingAnchor:self.mouseAnchor
newSelection:mouseSelectionPath];
}
#pragma mark Drawing Methods #pragma mark Drawing Methods
- (void)drawRect:(NSRect)dirtyRect - (void)drawRect:(NSRect)dirtyRect
{ {