Как я могу получить направление выбора NSTextView?

Я пытаюсь получить направление выбранных диапазонов в NSTextView. Другими словами, изменяют ли выбранные диапазоны свое местоположение или длину при использовании shift+leftarrow и shift+rightarrow. Мое первое, хотя было то, что selectionAffinity представляет направление, но похоже, что это относится к многострочным выборам.

Как я могу получить направление выбранных диапазонов?

Ответ 1

iOS

Шаг 1: Объявить свойство

@property (nonatomic) NSRange lastRange;

Шаг 2. В делегате TextView добавьте следующее:

- (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

OSX со всеми запрошенными функциями включала в себя немного больше работы, но вот то, что я придумал для рабочего, последовательного решения. Переименование является необязательным, или, скорее,... поощряемым...

 Шаг 1: Подкласс a NSTextView

В SubClass.h:

#import <Cocoa/Cocoa.h>

@interface TheSelectionizer : NSTextView

@property (nonatomic) NSRange lastAnchorPoint;

@end

В 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
 Шаг 2: Внедрение 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;
}

Я опубликовал проект на случай, если кто-то захочет попробовать его или хочет его увидеть.

Полный "проект" доступен ЗДЕСЬ

Ответ 2

Используйте методы NSTextViewDelegate: - textView: willChangeSelectionFromCharacterRange: toCharacterRange: или - textView: willChangeSelectionFromCharacterRanges: toCharacterRanges:, если вам нужна поддержка нескольких вариантов.

Обратите внимание, что если вы реализуете только -textView:willChangeSelectionFromCharacterRange:toCharacterRange:, будут выбраны множественные выборы.

Например, без множественных выборов:

- (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;
}

Ответ 3

Предполагается, что объявлен NSRange yourPreviousRange.

//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;
}