Reputation: 23675
I'm trying to get the direction of the selected ranges in an NSTextView
. In other words, whether the selected ranges change their location or length when you use shift+leftarrow
and shift+rightarrow
. My first though was that selectionAffinity
represents the direction, but it only seems to apply to multi-line selections.
How can I get the direction of selected ranges?
Upvotes: 12
Views: 819
Reputation: 53112
Step 1: Declare Property
@property (nonatomic) NSRange lastRange;
Step 2: In TextView Delegate, add this:
- (void) textViewDidChangeSelection:(UITextView *)textView
NSRange currentRange = NSMakeRange(textView.selectedRange.location, textView.selectedRange.length);
if (currentRange.length == 0) {
NSLog(@"Nothing selected");
_lastRange = currentRange;
}
else {
if (currentRange.location < _lastRange.location) {
NSLog(@"Selecting LEFT");
}
else {
NSLog(@"Selecting RIGHT");
}
}
}
OSX with all the features requested involved a little bit more work, but here's what I came up with for a working, consistent solution. Renaming is optional, or rather ... encouraged ...
Step 1: Subclass a NSTextViewIn your SubClass.h
:
#import <Cocoa/Cocoa.h>
@interface TheSelectionizer : NSTextView
@property (nonatomic) NSRange lastAnchorPoint;
@end
In your SubClass.m
#import "TheSelectionizer.h"
- (void)setSelectedRange:(NSRange)charRange affinity:(NSSelectionAffinity)affinity stillSelecting:(BOOL)stillSelectingFlag {
if (charRange.length == 0) {
_lastAnchorPoint = charRange;
}
[super setSelectedRange:charRange affinity:affinity stillSelecting:stillSelectingFlag];
}
@end
Step 2: Implement NSTextViewDelegate
- (NSRange) textView:(NSTextView *)textView willChangeSelectionFromCharacterRange:(NSRange)oldSelectedCharRange toCharacterRange:(NSRange)newSelectedCharRange {
if (newSelectedCharRange.length != 0) {
TheSelectionizer * selectionizer = (TheSelectionizer *)textView;
int anchorStart = (int)selectionizer.lastAnchorPoint.location;
int selectionStart = (int)newSelectedCharRange.location;
int selectionLength = (int)newSelectedCharRange.length;
/*
If mouse selects left, and then a user arrows right, or the opposite, anchor point flips.
*/
int difference = anchorStart - selectionStart;
if (difference > 0 && difference != selectionLength) {
if (oldSelectedCharRange.location == newSelectedCharRange.location) {
// We were selecting left via mouse, but now we are selecting to the right via arrows
anchorStart = selectionStart;
}
else {
// We were selecting right via mouse, but now we are selecting to the left via arrows
anchorStart = selectionStart + selectionLength;
}
selectionizer.lastAnchorPoint = NSMakeRange(anchorStart, 0);
}
// Evaluate Selection Direction
if (anchorStart == selectionStart) {
if (oldSelectedCharRange.length < newSelectedCharRange.length) {
// Bigger
NSLog(@"Will select right in overall right selection");
}
else {
// Smaller
NSLog(@"Will select left in overall right selection");
}
}
else {
if (oldSelectedCharRange.length < newSelectedCharRange.length) {
// Bigger
NSLog(@"Will select left in overall left selection");
}
else {
// Smaller
NSLog(@"Will select right in overall left selection");
}
}
}
return newSelectedCharRange;
}
I posted a project just in case someone wants to try it or wants to see it.
Full "project" available HERE
Upvotes: 7
Reputation: 159
Assumed that NSRange yourPreviousRange is declared.
//Check when NSTextView changed its value
@interface delegateAppDelegate : NSObject <NSApplicationDelegate, NSTextViewDelegate> {
NSWindow *window;
}
-(void)textDidChange:(NSNotification *)notification {
NSRange yourRange = notification.object.selectedRange;
if (yourRange.location == yourPreviousRange.location - 1 || yourRange.length == yourPreviousRange.length){
//left direction
} else if (yourRange.location == yourPreviousRange.location || yourRange.length == yourPreviousRange.length + 1){
//right direction
}
yourPreviousRange = yourRange;
}
Upvotes: 0
Reputation: 2917
Use NSTextViewDelegate
methods :
-textView:willChangeSelectionFromCharacterRange:toCharacterRange: or -textView:willChangeSelectionFromCharacterRanges:toCharacterRanges: if you want multi-selections support.
Note that if you only implements -textView:willChangeSelectionFromCharacterRange:toCharacterRange:
the multi-selections will be disallowed.
For example without multi-selections :
- (NSRange)textView:(NSTextView *)aTextView willChangeSelectionFromCharacterRange:(NSRange)oldSelectedCharRange toCharacterRange:(NSRange)newSelectedCharRange
{
if (newSelectedCharRange.length == 0 && oldSelectedCharRange.length == 0)
{
/* move the insertion point */
if (newSelectedCharRange.location < oldSelectedCharRange.location)
NSLog(@"insertion point move left");
else
NSLog(@"insertion point move right");
}
else if (newSelectedCharRange.length == 0 && oldSelectedCharRange.length != 0)
{
/* end a selection and move insertion point */
if (newSelectedCharRange.location == oldSelectedCharRange.location)
NSLog(@"insertion point at start from previous selection");
else if (newSelectedCharRange.location < oldSelectedCharRange.location)
NSLog(@"insertion point move left");
else
NSLog(@"insertion point move right");
}
else if (oldSelectedCharRange.length == 0 && newSelectedCharRange.length != 0)
{
/* start a selection */
if (newSelectedCharRange.location == oldSelectedCharRange.location)
NSLog(@"start a selection at insertion point, move right");
else if (newSelectedCharRange.location < oldSelectedCharRange.location)
NSLog(@"start a selection, move left");
else
NSLog(@"start a selection, move right");
}
else
{
if (newSelectedCharRange.location < oldSelectedCharRange.location)
NSLog(@"selection move left");
else
NSLog(@"selection move right");
}
return newSelectedCharRange;
}
Upvotes: 0