7 votes

Afficher les caractères cachés dans NSTextView

J'écris un éditeur de texte pour Mac OS X. J'ai besoin d'afficher les caractères cachés dans un NSTextView (comme les espaces, les tabulations et les caractères spéciaux). J'ai passé beaucoup de temps à chercher comment faire cela, mais je n'ai pas encore trouvé de réponse. Si quelqu'un pouvait m'indiquer la bonne direction, je lui en serais reconnaissant.

11voto

Pol Points 615

Voici une mise en œuvre entièrement fonctionnelle et propre

@interface GILayoutManager : NSLayoutManager
@end

@implementation GILayoutManager

- (void)drawGlyphsForGlyphRange:(NSRange)range atPoint:(NSPoint)point {
  NSTextStorage* storage = self.textStorage;
  NSString* string = storage.string;
  for (NSUInteger glyphIndex = range.location; glyphIndex < range.location + range.length; glyphIndex++) {
    NSUInteger characterIndex = [self characterIndexForGlyphAtIndex: glyphIndex];
    switch ([string characterAtIndex:characterIndex]) {

      case ' ': {
        NSFont* font = [storage attribute:NSFontAttributeName atIndex:characterIndex effectiveRange:NULL];
        [self replaceGlyphAtIndex:glyphIndex withGlyph:[font glyphWithName:@"periodcentered"]];
        break;
      }

      case '\n': {
        NSFont* font = [storage attribute:NSFontAttributeName atIndex:characterIndex effectiveRange:NULL];
        [self replaceGlyphAtIndex:glyphIndex withGlyph:[font glyphWithName:@"carriagereturn"]];
        break;
      }

    }
  }

  [super drawGlyphsForGlyphRange:range atPoint:point];
}

@end

Pour l'installation, utilisez :

[myTextView.textContainer replaceLayoutManager:[[GILayoutManager alloc] init]];

Pour trouver les noms des glyphes des polices, il faut aller dans CoreGraphics :

CGFontRef font = CGFontCreateWithFontName(CFSTR("Menlo-Regular"));
for (size_t i = 0; i < CGFontGetNumberOfGlyphs(font); ++i) {
  printf("%s\n", [CFBridgingRelease(CGFontCopyGlyphNameForGlyph(font, i)) UTF8String]);
}

5voto

e.James Points 51680

Jetez un coup d'œil à la classe NSLayoutManager. Votre NSTextView sera associé à un gestionnaire de mise en page, qui est chargé d'associer un caractère (espace, tabulation, etc.) à un glyphe (l'image de ce caractère dessinée à l'écran).

Dans votre cas, vous seriez sans doute plus intéressé par la rubrique [replaceGlyphAtIndex:withGlyph:](http://developer.apple.com/documentation/Cocoa/Reference/ApplicationKit/Classes/NSLayoutManager_Class/Reference/Reference.html#//apple_ref/occ/instm/NSLayoutManager/replaceGlyphAtIndex:withGlyph:) qui vous permettrait de remplacer des glyphes individuels.

3voto

J'ai écrit un éditeur de texte il y a quelques années - voici un code insignifiant qui devrait vous permettre de chercher (avec un peu de chance) dans la bonne direction (il s'agit d'une sous-classe de NSLayoutManager - et oui, je sais qu'elle fuit comme l'évier de cuisine proverbial) :

- (void)drawGlyphsForGlyphRange:(NSRange)glyphRange atPoint:(NSPoint)containerOrigin
{
    if ([[[[MJDocumentController sharedDocumentController] currentDocument] editor] showInvisibles])
    {
        //init glyphs
        unichar crlf = 0x00B6; 
        NSString *CRLF = [[NSString alloc] initWithCharacters:&crlf length:1];
        unichar space = 0x00B7;
        NSString *SPACE = [[NSString alloc] initWithCharacters:&space length:1];
        unichar tab = 0x2192; 
        NSString *TAB = [[NSString alloc] initWithCharacters:&tab length:1];

        NSString *docContents = [[self textStorage] string];
        NSString *glyph;
        NSPoint glyphPoint;
        NSRect glyphRect;
        NSDictionary *attr = [[NSDictionary alloc] initWithObjectsAndKeys:[NSUnarchiver unarchiveObjectWithData:[[NSUserDefaults standardUserDefaults] objectForKey:@"invisiblesColor"]], NSForegroundColorAttributeName, nil];

        //loop thru current range, drawing glyphs
        int i;
        for (i = glyphRange.location; i < NSMaxRange(glyphRange); i++)
        {
            glyph = @"";

            //look for special chars
            switch ([docContents characterAtIndex:i])
            {
                //space
                case ' ':
                    glyph = SPACE;
                    break;

                //tab
                case '\t':
                    glyph = TAB;
                    break;

                //eol
                case 0x2028:
                case 0x2029:
                case '\n':
                case '\r':
                    glyph = CRLF;
                    break;

                //do nothing
                default:
                    glyph = @"";
                    break;                  
            }

            //should we draw?
            if ([glyph length])
            {
                glyphPoint = [self locationForGlyphAtIndex:i];
                glyphRect = [self lineFragmentRectForGlyphAtIndex:i effectiveRange:NULL];
                glyphPoint.x += glyphRect.origin.x;
                glyphPoint.y = glyphRect.origin.y;
                [glyph drawAtPoint:glyphPoint withAttributes:attr];
            }
        }
    }

    [super drawGlyphsForGlyphRange:glyphRange atPoint:containerOrigin];
}

2voto

titaniumdecoy Points 7548

J'ai résolu le problème de la conversion entre les NSGlyphes et l'unichar correspondant dans le NSTextView. Le code ci-dessous fonctionne à merveille et remplace les espaces par des puces pour le texte visible :

- (void)drawGlyphsForGlyphRange:(NSRange)range atPoint:(NSPoint)origin
{
    NSFont *font = [[CURRENT_TEXT_VIEW typingAttributes]
                       objectForKey:NSFontAttributeName];

    NSGlyph bullet = [font glyphWithName:@"bullet"];

    for (int i = range.location; i != range.location + range.length; i++)
    {
        unsigned charIndex = [self characterIndexForGlyphAtIndex:i];

        unichar c =[[[self textStorage] string] characterAtIndex:charIndex];

        if (c == ' ')
            [self replaceGlyphAtIndex:charIndex withGlyph:bullet];
    }

    [super drawGlyphsForGlyphRange:range atPoint:origin];
}

2voto

Ned Holbrook Points 126

Peut-être que -[NSLayoutManager setShowsControlCharacters :] et/ou -[NSLayoutManager setShowsInvisibleCharacters :] feront ce que vous voulez.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X