Search code examples
cocoacalayernstextview

How to calculate correct coordinates for selected text in NSTextView?


I need to highlight line with caret in NSTextView using CALayer overlay and grab rect for line with this code in my subclassed NSTextView...:

- (NSRect)overlayRectForRange:(NSRange)aRange
{
    NSScreen *currentScreen = [NSScreen currentScreenForMouseLocation];
    NSRect rect = [self firstRectForCharacterRange:aRange];

    rect = [self convertRectToLayer:rect];
    rect.origin = [currentScreen flipPoint:rect.origin];
    rect = [self.window convertRectToScreen:rect];

    return rect;
}

...and put overlay:

- (void)focusOnLine
{
    NSInteger caretLocation = [aTextView selectedRange].location;
    NSRange neededRange;

    (void)[layoutMgr lineFragmentRectForGlyphAtIndex:caretLocation effectiveRange:&neededRange];
    CALayer *aLayer = [CALayer layer];
    [aLayer setFrame:NSRectToCGRect([aTextView overlayRectForRange:neededRange])];
    [aLayer setBackgroundColor:[[NSColor redColor] coreGraphicsColorWithAlfa:0.5]];
    [[aTextView layer] addSublayer:aLayer];
}

As a result, the selection overlay coincides with width of desired line, but absolutely not matches by Y axis (X axis is ok).

What am I missing?


Solution

  • Okay, I completely rewrote method overlayRectForRange: and now all works fine. There is fixed code:

    - (NSRect)overlayRectForRange:(NSRange)aRange
    {
        NSRange activeRange = [[self layoutManager] glyphRangeForCharacterRange:aRange actualCharacterRange:NULL];
        NSRect neededRect = [[self layoutManager] boundingRectForGlyphRange:activeRange inTextContainer:[self textContainer]];
        NSPoint containerOrigin = [self textContainerOrigin];
        neededRect.origin.x += containerOrigin.x;
        neededRect.origin.y += containerOrigin.y;
    
        neededRect = [self convertRectToLayer:neededRect];
    
        return neededRect;
    }