Question

I have a bunch of NSTextViews that I would like to share a single selection. I basically want this to behave like selecting text on a web page, where there are multiple text views but you can drag to sequentially select text among them.

I found this document which states that it is possible to have multiple NSTextContainer objects sharing a single NSLayoutManager and thus share the selection. This is halfway to what I want, except for the fact that one NSLayoutManager can only have a single NSTextStorage object. I want each text view to have its own NSTextStorage so that each text view can have its own text, but I still want to be able to select text in multiple text views with one drag. Is this possible?

Was it helpful?

Solution

There's no easy way to solve this problem (as I tried to find by asking this question). It involves all the mouse event handling and text selection calculations you'd expect, so I wrote the code and have open sourced it as INDSequentialTextSelectionManager.

OTHER TIPS

To make this separate text containers work, you would calculate the drawn size of each part of the string and limit the NSTextView to that size:

    NSLayoutManager * layout = [[NSLayoutManager alloc] init];
    NSString * storedString = @"A\nquick\nBrown\nFox";
    NSTextStorage * storage = [[NSTextStorage alloc] initWithString:storedString];
    [storage addLayoutManager:layout];

    //I assume you have a parent view to add the text views
    NSView * view;

    //Assuming you want to split up into separate view by line break
    NSArray * paragraphs = [storedString componentsSeparatedByString:@"\n"];
    for (NSString * paragraph in paragraphs)
    {
        NSSize paragraphSize = [paragraph sizeWithAttributes:@{}];
        //Create a text container only big enough for the string to be displayed by the text view
        NSTextContainer * paragraphContainer = [[NSTextContainer alloc] initWithContainerSize:paragraphSize];
        [layout addTextContainer:paragraphContainer];

        //Use autolayout or calculate size/placement as you go along
        NSRect lazyRectWithoutSizeOrPlacement = NSMakeRect(0, 0, 0, 0);
        NSTextView * textView = [[NSTextView alloc] initWithFrame:lazyRectWithoutSizeOrPlacement
                                                    textContainer:paragraphContainer];
        [view addSubview:textView];
    }

You can add a delegate to the NSLayoutManager to watch your text container usage:

- (void)layoutManager:(NSLayoutManager *)aLayoutManager
didCompleteLayoutForTextContainer:(NSTextContainer *)aTextContainer
                    atEnd:(BOOL)flag
{
    if (aTextContainer == nil)
    {
        //All text was unable to be displayed in existing containers. A new NSTextContainer is needed.
    }
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top