4

I have an NSTextView with images in it. I want to add tracking areas for those images. I need the frame of the cells holding the images in order to create tracking areas.

So my question: how can I get the frame for the NSTextAttachments in the coordinate system of the NSTextView?

I am programmatically changing the size of an image in the text view and this is when I need to create this new tracking area. I am doing the following to create an attributed string with the text attachment, and then programmatically inserting this into my text view's attributed string. But once I do all this I do not know how to create my tracking area for the new attachment.

-(NSAttributedString*)attributedStringAttachmentForImageObject:(id)object {
    NSFileWrapper* fileWrapper = [[NSFileWrapper alloc] initRegularFileWithContents:[object TIFFRepresentationUsingCompression:NSTIFFCompressionLZW factor:1.0]];
    [fileWrapper setPreferredFilename:@"image.tiff"];
    NSTextAttachment* attachment = [[NSTextAttachment alloc] initWithFileWrapper:fileWrapper];
    NSAttributedString* aString = [NSAttributedString attributedStringWithAttachment:attachment];
    [fileWrapper release];
    [attachment release];
    return aString;
}
regulus6633
  • 18,848
  • 5
  • 41
  • 49

1 Answers1

4

Since attachments consist of a single (non visible) glyph (0xFFFC) you can use the glyph messages to get the bounding box. Here's code I use to highlight an attachment in an NSTextView based on the mouse position (which requires to get attachment bounds):

/**
 * Determines the index under the mouse. For highlighting we use the index only if the mouse is actually
 * within the tag bounds. For selection purposes we return the index as it was found even if the mouse pointer
 * is outside the tag bounds.
 */
- (NSUInteger)updateTargetDropIndexAtPoint: (NSPoint)point
{
    CGFloat fraction;
    NSUInteger index = [self.layoutManager glyphIndexForPoint: point
                                              inTextContainer: self.textContainer
                               fractionOfDistanceThroughGlyph: &fraction];
    NSUInteger caretIndex = index;
    if (fraction > 0.5) {
        caretIndex++;
    }

    // For highlighting a tag we need check if the mouse is actually within the tag.
    NSRect bounds = [self.layoutManager boundingRectForGlyphRange: NSMakeRange(index, 1)
                                                  inTextContainer: self.textContainer];
    NSUInteger newIndex;
    if (NSPointInRect(point, bounds)) {
        newIndex = index;
    } else {
        newIndex = NSNotFound;
    }
    if (hotTagIndex != newIndex) {
        NSRect oldBounds = [self.layoutManager boundingRectForGlyphRange: NSMakeRange(hotTagIndex, 1)
                                                         inTextContainer: self.textContainer];
        [self setNeedsDisplayInRect: oldBounds];
        hotTagIndex = newIndex;
        [self setNeedsDisplayInRect: bounds];
    }

    return caretIndex;
}

This code is used in an NSTextView descendant, hence the self.layoutManager access.

Mike Lischke
  • 48,925
  • 16
  • 119
  • 181
  • Hey Mike, I have a quick question for you. Is `hotTagIndex` just an ivar you've declared elsewhere? And by "hot" you mean closest/current/active/highlighted/other-word-for-being-in-the-spotlight, right? Either way, thanks for the snippet! It's nice to see some `NSLayoutManager` code in action. – Ben Stock Sep 01 '14 at 22:07
  • @BenStock: yes the hot tag index is the index of the tag over which the mouse is currently hovering (an iVar). It's used to highlight the tag and to have an index for dragging. – Mike Lischke Sep 02 '14 at 06:34
  • Thanks for the explanation. I've been trying to implement drop-target highlighting for a few `NSTextAttachment` objects in my `NSTextView` subclass, and your above code saved me from a lot of headaches. Before your code, only half of any attachment would highlight. I think it had to do with my lack of understanding of the `fractionOfDistanceThroughGlyph:` part of the method signature. After seeing what you did, it helped a lot. Again, thanks for the code and the quick response! – Ben Stock Sep 02 '14 at 23:36