Forum Navigation
You need to log in to create posts and topics.

TextView_LineNumbers

Posted by: svanvoorst <svanvoorst@...>

This demo gives the illusion of line numbers in a text view by utilizing two synchronized scroll views; one containing text and the other containing line numbers.  Both are embedded into a single view to make it easier to 'group' the components and move them en masse.  The window is resizable.

'------- start ----------
/*
   Adds line numbers to an NSTextView by utilizing synchronized NSScrollViews.
   Reference: Apple Doc "Scroll View Programming Guide for Mac", 2010-06-19, pp. 17-20.
   Adapted for FB by S.Van Voorst   {20121024}  Modifications by Bernie Wylde.
*/

BeginCDeclaration
@interface EmbedderView : NSView
//methods automatically called
@end  //interface
EndC

BeginCFunction
@implementation EmbedderView : NSView;

- (id)initWithFrame:(NSRect)frameRect
{
 if ((self = [super initWithFrame:frameRect]) != nil) 
 {
  self = [super initWithFrame:frameRect];
  // Add initialization code here
 }
 return self;
}

- (void)drawRect:(NSRect)rect
{
// ****** Background ***** //
[[NSColor orangeColor] set];
[NSBezierPath fillRect:rect];

}
// ----- Use this if you want 0,0 (origin) to be top, left ---- //
// ----- Otherwise origin will be at bottom, left (Unflipped) ----- //
-(BOOL)isFlipped
{
 return YES;
}
@end //implementation
EndC

BeginCDeclaration
@interface MyDelegate : NSObject
{
  NSWindow *window;
  NSScrollView *rightScrollView;
  NSScrollView *leftScrollView;
  NSTextView *txtView1;
  NSTextView *txtView2;
  NSRect embedderR;
}
- (void) createMenu;
- (void) createWindow;
- (void) calcLineNumbers;
@end
EndC

BeginCFunction
@implementation MyDelegate : NSObject 

- (void) dealloc
{
  [window release];
  [super dealloc];
}

- (void)calcLineNumbers 
{
  NSMutableString *txtView1String = [[NSMutableString alloc] initWithCapacity:0];
  NSLayoutManager *layoutManager = [txtView2 layoutManager];
  unsigned numberOfLines, index, numberOfGlyphs = [layoutManager numberOfGlyphs];
  NSRange lineRange;
  for (numberOfLines = 0, index = 0; index < numberOfGlyphs; numberOfLines++)
  {
   (void) [layoutManager lineFragmentRectForGlyphAtIndex:index effectiveRange: &lineRange];
   index = NSMaxRange(lineRange);
   [txtView1String appendFormat:@"%dn", numberOfLines+1];    
   [txtView1 setString:txtView1String];
  }
   [txtView1String release]; 
}

- (void)textDidChange:(NSNotification *)notification
{
  [self calcLineNumbers];
}

- (void)scrollViewContentBoundsDidChange:(NSNotification *)notification
{
 NSPoint leftOrigin = [[leftScrollView contentView] bounds].origin;
 NSPoint rightOrigin = [[rightScrollView contentView] bounds].origin;
 if ( [notification object] == [rightScrollView contentView] ) {
   leftOrigin.y = rightOrigin.y;
   [[leftScrollView contentView] scrollToPoint:leftOrigin];
  } else {
   rightOrigin.y = leftOrigin.y;
   [[rightScrollView contentView] scrollToPoint:rightOrigin];
       [rightScrollView reflectScrolledClipView:[rightScrollView contentView]];
  }
}

- (void) createMenu
{
// ******** Menu and menubar ********//
  id menubar = [[NSMenu new] autorelease];
  id appMenuItem = [[NSMenuItem new] autorelease];
  [menubar addItem:appMenuItem];
  [NSApp setMainMenu:menubar];
  id appMenu = [[NSMenu new] autorelease];
  id quitMenuItem = [[[NSMenuItem alloc] initWithTitle:@"Quit"
        action:@selector(terminate:) keyEquivalent:@"q"] autorelease];
  [appMenu addItem:quitMenuItem];
  [appMenuItem setSubmenu:appMenu];
}

- (void) createWindow
{
  // ***** window ***** //
  #define _wndW  600
  #define _wndH  550
  window = [[NSWindow alloc] initWithContentRect: NSMakeRect( 0, 0, _wndW, _wndH )
    styleMask: NSTitledWindowMask | NSMiniaturizableWindowMask | NSClosableWindowMask | NSResizableWindowMask
             backing: NSBackingStoreBuffered
                   defer: NO];
  [window center];
  [window setMinSize:NSMakeSize(152,220)];
  [window setTitle: @"NSTextView with line numbers."];

// ------- Create an instance of EmbedderView (NSView) ------ //
 embedderR = NSMakeRect( 20, 80, _wndW - 40, _wndH - 100 );
 EmbedderView *baseView = [[EmbedderView alloc]initWithFrame:embedderR];
 [baseView setAutoresizingMask:NSViewHeightSizable | NSViewWidthSizable];
 [baseView setAutoresizesSubviews:YES];
 [[window contentView] addSubview:baseView];
 [baseView release];

// ****** Left NSTextView with Scroll ****** //
 NSRect leftScrollViewR = NSMakeRect( 10, 10, 50, embedderR.size.height - 20 );
 leftScrollView = [[NSScrollView alloc] initWithFrame: leftScrollViewR];
 [baseView addSubview:leftScrollView];
 [leftScrollView setHasVerticalScroller:NO];
 [leftScrollView setAutoresizingMask:NSViewHeightSizable];
 txtView1 = [[NSTextView alloc] initWithFrame:NSMakeRect( 0, 0, leftScrollViewR.size.width, leftScrollViewR.size.height )];
 [txtView1 setEditable:NO]; 
 [txtView1 setAlignment:NSRightTextAlignment];
 [txtView1 setBackgroundColor:[NSColor lightGrayColor]];
 [txtView1 setHorizontallyResizable:NO];
 [txtView1 setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable];
 [leftScrollView setDocumentView: txtView1];
 [leftScrollView release];
 [txtView1 release];

// ****** Right NSTextView with Scroll ****** //
 NSRect rightScrollViewR = NSMakeRect( 62, 10, embedderR.size.width - 72, embedderR.size.height - 20 );
 rightScrollView = [[NSScrollView alloc] initWithFrame: rightScrollViewR];
 [baseView addSubview:rightScrollView];
 [rightScrollView setHasVerticalScroller: YES];
 [rightScrollView setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable];
 txtView2 = [[NSTextView alloc] initWithFrame:NSMakeRect( 0, 0, rightScrollViewR.size.width, rightScrollViewR.size.height )];
 [txtView2 setMinSize:NSMakeSize( 0.0, [rightScrollView contentSize].height)];
 [txtView2 setMaxSize:NSMakeSize(FLT_MAX, FLT_MAX)];
 [txtView2 setVerticallyResizable:YES];
 [txtView2 setHorizontallyResizable:YES];
 [txtView2 setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable ];
 [[txtView2 textContainer]setContainerSize:NSMakeSize(FLT_MAX, FLT_MAX)];
 [[txtView2 textContainer] setWidthTracksTextView:NO];
 [txtView2 setDelegate:[NSApp delegate]];
 [rightScrollView setDocumentView: txtView2];
 [[txtView2 enclosingScrollView] setHasHorizontalScroller:YES];
 [txtView2 insertText:@"Enter text - Right click for menu."];
 [rightScrollView release];
 [txtView2 release];

// ******* Synchronize the two Scroll Views ******** //
  [[rightScrollView contentView] setPostsBoundsChangedNotifications:YES];
  [[NSNotificationCenter defaultCenter] addObserver:self
                                             selector:@selector(scrollViewContentBoundsDidChange:)
                                                 name:NSViewBoundsDidChangeNotification
                                               object:[rightScrollView contentView]];

  [[leftScrollView contentView] setPostsBoundsChangedNotifications:YES];
  [[NSNotificationCenter defaultCenter] addObserver:self
                                             selector:@selector(scrollViewContentBoundsDidChange:)
                                                 name:NSViewBoundsDidChangeNotification
                                               object:[leftScrollView contentView]];

[window setInitialFirstResponder:txtView2];

// ***** Quit btn ***** //
 NSButton *quitBtn = [[NSButton alloc]initWithFrame:NSMakeRect( _wndW - 130, 30, 95, 30 )];
 [quitBtn setBezelStyle:NSRoundedBezelStyle ];
 [quitBtn setAutoresizingMask:NSViewMinXMargin];
 [quitBtn setTitle: @"Quit" ];
 [quitBtn setAction:@selector(terminate:)];
 [[window contentView] addSubview: quitBtn];
 [quitBtn release];
}

- (void) applicationWillFinishLaunching: (NSNotification *)notification
{
  [self createMenu];
  [self createWindow];
}

- (void) applicationDidFinishLaunching: (NSNotification *)notification
{
  [window makeKeyAndOrderFront: nil];
}
@end
EndC

BeginCCode
  NSAutoreleasePool *pool = [[NSAutoreleasePool alloc]init];
  [NSApplication sharedApplication];
  [NSApp setDelegate: [MyDelegate new]];
  [NSApp run];
  [pool drain];
EndC
'-------- end ----------

Steve Van Voorst


To unsubscribe, e-mail: fbcocoa-unsubscribe@welovegod.org
For additional commands, e-mail: fbcocoa-help@freegroups.net