1 /* vi:set ts=8 sts=4 sw=4 ft=objc:
3 * VIM - Vi IMproved by Bram Moolenaar
4 * MacVim GUI port by Bjorn Winckler
6 * Do ":help uganda" in Vim to read copying and usage conditions.
7 * Do ":help credits" in Vim to see a list of people who contributed.
8 * See README.txt for an overview of the Vim source code.
13 * Dispatches keyboard and mouse input to the backend. Handles drag-n-drop of
16 * Support for input managers is somewhat hacked together. Marked text is
17 * drawn "pseudo-inline"; it will simply draw on top of existing text and it
18 * does not respect Vim-window boundaries.
21 #import "MMAppController.h"
22 #import "MMTextStorage.h"
23 #import "MMTextView.h"
24 #import "MMTextViewHelper.h"
25 #import "MMTypesetter.h"
26 #import "MMVimController.h"
27 #import "MMWindowController.h"
28 #import "Miscellaneous.h"
32 // This is taken from gui.h
33 #define DRAW_CURSOR 0x20
37 @interface MMTextView (Private)
38 - (MMWindowController *)windowController;
39 - (MMVimController *)vimController;
40 - (void)setShouldDrawInsertionPoint:(BOOL)on;
41 - (void)drawInsertionPointAtRow:(int)row column:(int)col shape:(int)shape
42 fraction:(int)percent;
43 - (void)drawInvertedRectAtRow:(int)row column:(int)col numRows:(int)nrows
44 numColumns:(int)ncols invert:(int)invert;
49 @implementation MMTextView
51 - (id)initWithFrame:(NSRect)frame
53 // Set up a Cocoa text system. Note that the textStorage is released in
54 // -[MMVimView dealloc].
55 MMTextStorage *textStorage = [[MMTextStorage alloc] init];
56 NSLayoutManager *lm = [[NSLayoutManager alloc] init];
57 NSTextContainer *tc = [[NSTextContainer alloc] initWithContainerSize:
58 NSMakeSize(1.0e7,1.0e7)];
60 NSString *typesetterString = [[NSUserDefaults standardUserDefaults]
61 stringForKey:MMTypesetterKey];
62 if ([typesetterString isEqual:@"MMTypesetter"]) {
63 NSTypesetter *typesetter = [[MMTypesetter alloc] init];
64 [lm setTypesetter:typesetter];
66 } else if ([typesetterString isEqual:@"MMTypesetter2"]) {
67 NSTypesetter *typesetter = [[MMTypesetter2 alloc] init];
68 [lm setTypesetter:typesetter];
71 // Only MMTypesetter supports different cell width multipliers.
72 [[NSUserDefaults standardUserDefaults]
73 setFloat:1.0 forKey:MMCellWidthMultiplierKey];
76 // The characters in the text storage are in display order, so disable
77 // bidirectional text processing (this call is 10.4 only).
78 [[lm typesetter] setBidiProcessingEnabled:NO];
80 [tc setWidthTracksTextView:NO];
81 [tc setHeightTracksTextView:NO];
82 [tc setLineFragmentPadding:0];
84 [textStorage addLayoutManager:lm];
85 [lm addTextContainer:tc];
87 // The text storage retains the layout manager which in turn retains
88 // the text container.
92 // NOTE: This will make the text storage the principal owner of the text
93 // system. Releasing the text storage will in turn release the layout
94 // manager, the text container, and finally the text view (self). This
95 // complicates deallocation somewhat, see -[MMVimView dealloc].
96 if (![super initWithFrame:frame textContainer:tc]) {
97 [textStorage release];
101 helper = [[MMTextViewHelper alloc] init];
102 [helper setTextView:self];
104 // NOTE: If the default changes to 'NO' then the intialization of
105 // p_antialias in option.c must change as well.
121 [helper setTextView:nil];
122 [helper dealloc]; helper = nil;
127 - (BOOL)shouldDrawInsertionPoint
129 // NOTE: The insertion point is drawn manually in drawRect:. It would be
130 // nice to be able to use the insertion point related methods of
131 // NSTextView, but it seems impossible to get them to work properly (search
132 // the cocoabuilder archives).
136 - (void)setPreEditRow:(int)row column:(int)col
138 [helper setPreEditRow:row column:col];
141 #define MM_DEBUG_DRAWING 0
143 - (void)performBatchDrawWithData:(NSData *)data
145 MMTextStorage *textStorage = (MMTextStorage *)[self textStorage];
149 const void *bytes = [data bytes];
150 const void *end = bytes + [data length];
151 int cursorRow = -1, cursorCol = 0;
154 NSLog(@"====> BEGIN %s", _cmd);
156 [textStorage beginEditing];
158 // TODO: Sanity check input
160 while (bytes < end) {
161 int type = *((int*)bytes); bytes += sizeof(int);
163 if (ClearAllDrawType == type) {
165 NSLog(@" Clear all");
167 [textStorage clearAll];
168 } else if (ClearBlockDrawType == type) {
169 unsigned color = *((unsigned*)bytes); bytes += sizeof(unsigned);
170 int row1 = *((int*)bytes); bytes += sizeof(int);
171 int col1 = *((int*)bytes); bytes += sizeof(int);
172 int row2 = *((int*)bytes); bytes += sizeof(int);
173 int col2 = *((int*)bytes); bytes += sizeof(int);
176 NSLog(@" Clear block (%d,%d) -> (%d,%d)", row1, col1,
179 [textStorage clearBlockFromRow:row1 column:col1
180 toRow:row2 column:col2
181 color:[NSColor colorWithArgbInt:color]];
182 } else if (DeleteLinesDrawType == type) {
183 unsigned color = *((unsigned*)bytes); bytes += sizeof(unsigned);
184 int row = *((int*)bytes); bytes += sizeof(int);
185 int count = *((int*)bytes); bytes += sizeof(int);
186 int bot = *((int*)bytes); bytes += sizeof(int);
187 int left = *((int*)bytes); bytes += sizeof(int);
188 int right = *((int*)bytes); bytes += sizeof(int);
191 NSLog(@" Delete %d line(s) from %d", count, row);
193 [textStorage deleteLinesFromRow:row lineCount:count
194 scrollBottom:bot left:left right:right
195 color:[NSColor colorWithArgbInt:color]];
196 } else if (DrawStringDrawType == type) {
197 int bg = *((int*)bytes); bytes += sizeof(int);
198 int fg = *((int*)bytes); bytes += sizeof(int);
199 int sp = *((int*)bytes); bytes += sizeof(int);
200 int row = *((int*)bytes); bytes += sizeof(int);
201 int col = *((int*)bytes); bytes += sizeof(int);
202 int cells = *((int*)bytes); bytes += sizeof(int);
203 int flags = *((int*)bytes); bytes += sizeof(int);
204 int len = *((int*)bytes); bytes += sizeof(int);
205 NSString *string = [[NSString alloc]
206 initWithBytes:(void*)bytes length:len
207 encoding:NSUTF8StringEncoding];
211 NSLog(@" Draw string at (%d,%d) length=%d flags=%d fg=0x%x "
212 "bg=0x%x sp=0x%x (%@)", row, col, len, flags, fg, bg, sp,
213 len > 0 ? [string substringToIndex:1] : @"");
215 // NOTE: If this is a call to draw the (block) cursor, then cancel
216 // any previous request to draw the insertion point, or it might
217 // get drawn as well.
218 if (flags & DRAW_CURSOR)
219 [self setShouldDrawInsertionPoint:NO];
221 [textStorage drawString:string
222 atRow:row column:col cells:cells
224 foregroundColor:[NSColor colorWithRgbInt:fg]
225 backgroundColor:[NSColor colorWithArgbInt:bg]
226 specialColor:[NSColor colorWithRgbInt:sp]];
229 } else if (InsertLinesDrawType == type) {
230 unsigned color = *((unsigned*)bytes); bytes += sizeof(unsigned);
231 int row = *((int*)bytes); bytes += sizeof(int);
232 int count = *((int*)bytes); bytes += sizeof(int);
233 int bot = *((int*)bytes); bytes += sizeof(int);
234 int left = *((int*)bytes); bytes += sizeof(int);
235 int right = *((int*)bytes); bytes += sizeof(int);
238 NSLog(@" Insert %d line(s) at row %d", count, row);
240 [textStorage insertLinesAtRow:row lineCount:count
241 scrollBottom:bot left:left right:right
242 color:[NSColor colorWithArgbInt:color]];
243 } else if (DrawCursorDrawType == type) {
244 unsigned color = *((unsigned*)bytes); bytes += sizeof(unsigned);
245 int row = *((int*)bytes); bytes += sizeof(int);
246 int col = *((int*)bytes); bytes += sizeof(int);
247 int shape = *((int*)bytes); bytes += sizeof(int);
248 int percent = *((int*)bytes); bytes += sizeof(int);
251 NSLog(@" Draw cursor at (%d,%d)", row, col);
253 [helper setInsertionPointColor:[NSColor colorWithRgbInt:color]];
254 [self drawInsertionPointAtRow:row column:col shape:shape
256 } else if (DrawInvertedRectDrawType == type) {
257 int row = *((int*)bytes); bytes += sizeof(int);
258 int col = *((int*)bytes); bytes += sizeof(int);
259 int nr = *((int*)bytes); bytes += sizeof(int);
260 int nc = *((int*)bytes); bytes += sizeof(int);
261 int invert = *((int*)bytes); bytes += sizeof(int);
264 NSLog(@" Draw inverted rect: row=%d col=%d nrows=%d ncols=%d",
267 [self drawInvertedRectAtRow:row column:col numRows:nr numColumns:nc
269 } else if (SetCursorPosDrawType == type) {
270 cursorRow = *((int*)bytes); bytes += sizeof(int);
271 cursorCol = *((int*)bytes); bytes += sizeof(int);
273 NSLog(@"WARNING: Unknown draw type (type=%d)", type);
277 [textStorage endEditing];
279 if (cursorRow >= 0) {
280 unsigned off = [textStorage characterIndexForRow:cursorRow
282 unsigned maxoff = [[textStorage string] length];
283 if (off > maxoff) off = maxoff;
285 [self setSelectedRange:NSMakeRange(off, 0)];
288 // NOTE: During resizing, Cocoa only sends draw messages before Vim's rows
289 // and columns are changed (due to ipc delays). Force a redraw here.
290 if ([self inLiveResize])
294 NSLog(@"<==== END %s", _cmd);
298 - (void)setMouseShape:(int)shape
300 [helper setMouseShape:shape];
303 - (void)setAntialias:(BOOL)state
310 return [(MMTextStorage*)[self textStorage] font];
313 - (void)setFont:(NSFont *)newFont
315 [(MMTextStorage*)[self textStorage] setFont:newFont];
320 return [(MMTextStorage*)[self textStorage] fontWide];
323 - (void)setWideFont:(NSFont *)newFont
325 [(MMTextStorage*)[self textStorage] setWideFont:newFont];
330 return [(MMTextStorage*)[self textStorage] cellSize];
333 - (void)setLinespace:(float)newLinespace
335 return [(MMTextStorage*)[self textStorage] setLinespace:newLinespace];
340 MMTextStorage *ts = (MMTextStorage *)[self textStorage];
346 MMTextStorage *ts = (MMTextStorage *)[self textStorage];
347 return [ts maxColumns];
350 - (void)getMaxRows:(int*)rows columns:(int*)cols
352 return [(MMTextStorage*)[self textStorage] getMaxRows:rows columns:cols];
355 - (void)setMaxRows:(int)rows columns:(int)cols
357 return [(MMTextStorage*)[self textStorage] setMaxRows:rows columns:cols];
360 - (NSRect)rectForRowsInRange:(NSRange)range
362 return [(MMTextStorage*)[self textStorage] rectForRowsInRange:range];
365 - (NSRect)rectForColumnsInRange:(NSRange)range
367 return [(MMTextStorage*)[self textStorage] rectForColumnsInRange:range];
370 - (void)setDefaultColorsBackground:(NSColor *)bgColor
371 foreground:(NSColor *)fgColor
373 [self setBackgroundColor:bgColor];
374 return [(MMTextStorage*)[self textStorage]
375 setDefaultColorsBackground:bgColor foreground:fgColor];
378 - (NSColor *)defaultBackgroundColor
380 return [(MMTextStorage*)[self textStorage] defaultBackgroundColor];
383 - (NSColor *)defaultForegroundColor
385 return [(MMTextStorage*)[self textStorage] defaultForegroundColor];
388 - (NSSize)constrainRows:(int *)rows columns:(int *)cols toSize:(NSSize)size
390 NSUserDefaults *ud = [NSUserDefaults standardUserDefaults];
391 int right = [ud integerForKey:MMTextInsetRightKey];
392 int bot = [ud integerForKey:MMTextInsetBottomKey];
394 size.width -= [self textContainerOrigin].x + right;
395 size.height -= [self textContainerOrigin].y + bot;
397 NSSize newSize = [(MMTextStorage*)[self textStorage] fitToSize:size
401 newSize.width += [self textContainerOrigin].x + right;
402 newSize.height += [self textContainerOrigin].y + bot;
407 - (NSSize)desiredSize
409 NSSize size = [(MMTextStorage*)[self textStorage] size];
411 NSUserDefaults *ud = [NSUserDefaults standardUserDefaults];
412 int right = [ud integerForKey:MMTextInsetRightKey];
413 int bot = [ud integerForKey:MMTextInsetBottomKey];
415 size.width += [self textContainerOrigin].x + right;
416 size.height += [self textContainerOrigin].y + bot;
423 NSSize cellSize = [(MMTextStorage*)[self textStorage] cellSize];
424 NSSize size = { MMMinColumns*cellSize.width, MMMinRows*cellSize.height };
426 NSUserDefaults *ud = [NSUserDefaults standardUserDefaults];
427 int right = [ud integerForKey:MMTextInsetRightKey];
428 int bot = [ud integerForKey:MMTextInsetBottomKey];
430 size.width += [self textContainerOrigin].x + right;
431 size.height += [self textContainerOrigin].y + bot;
436 - (BOOL)convertPoint:(NSPoint)point toRow:(int *)row column:(int *)column
438 MMTextStorage *ts = (MMTextStorage*)[self textStorage];
439 NSSize cellSize = [ts cellSize];
440 if (!(cellSize.width > 0 && cellSize.height > 0))
442 NSPoint origin = [self textContainerOrigin];
444 if (row) *row = floor((point.y-origin.y-1) / cellSize.height);
445 if (column) *column = floor((point.x-origin.x-1) / cellSize.width);
447 //NSLog(@"convertPoint:%@ toRow:%d column:%d", NSStringFromPoint(point),
453 - (NSPoint)pointForRow:(int)row column:(int)col
455 // Return the upper-left coordinate for (row,column).
456 // NOTE: The coordinate system is flipped!
457 NSPoint pt = [self textContainerOrigin];
458 MMTextStorage *ts = (MMTextStorage*)[self textStorage];
459 NSSize cellSize = [ts cellSize];
461 pt.x += col * cellSize.width;
462 pt.y += row * cellSize.height;
467 - (NSRect)rectForRow:(int)row column:(int)col numRows:(int)nr
470 // Return the rect for the block which covers the specified rows and
471 // columns. The upper-left corner is the origin of this rect.
472 // NOTE: The coordinate system is flipped!
474 MMTextStorage *ts = (MMTextStorage*)[self textStorage];
475 NSSize cellSize = [ts cellSize];
477 rect.origin = [self textContainerOrigin];
478 rect.origin.x += col * cellSize.width;
479 rect.origin.y += row * cellSize.height;
480 rect.size.width = cellSize.width * nc;
481 rect.size.height = cellSize.height * nr;
491 - (void)drawRect:(NSRect)rect
493 NSGraphicsContext *context = [NSGraphicsContext currentContext];
494 [context setShouldAntialias:antialias];
496 [super drawRect:rect];
499 CGContextRef cgctx = (CGContextRef)[context graphicsPort];
500 CGContextSaveGState(cgctx);
501 CGContextSetBlendMode(cgctx, kCGBlendModeDifference);
502 CGContextSetRGBFillColor(cgctx, 1.0, 1.0, 1.0, 1.0);
505 CGRect *rect = (CGRect*)invertRects;
506 for (i = 0; i < numInvertRects; ++i)
507 CGContextFillRect(cgctx, rect[i]);
509 CGContextRestoreGState(cgctx);
516 if ([self hasMarkedText]) {
517 shouldDrawInsertionPoint = YES;
518 MMTextStorage *ts = (MMTextStorage*)[self textStorage];
519 NSSize inset = [self textContainerInset];
521 // HACK! Get the baseline of the zeroth glyph and use that as the
522 // baseline for the marked text. (Is there a better way to figure out
523 // what baseline NSTextView uses?)
524 NSLayoutManager *lm = [self layoutManager];
525 NSTypesetter *tsr = [lm typesetter];
526 float baseline = [tsr baselineOffsetInLayoutManager:lm glyphIndex:0];
528 // Also adjust for 'linespace' option (TODO: Why not .5*linespace?)
529 baseline -= floor([ts linespace]);
531 inset.height -= baseline;
533 int len = [[helper markedText] length];
534 // The following implementation should be re-written with
535 // more efficient way...
537 // Calculate how many wide-font characters can be inserted at
538 // a first line, and draw those characters.
539 int cols = ([ts actualColumns] - insertionPointColumn);
540 NSFont *theFont = [[self markedTextAttributes]
541 valueForKey:NSFontAttributeName];
542 if (theFont == [ts fontWide])
545 int lend = cols > len ? len : cols;
546 NSAttributedString *aString = [[helper markedText]
547 attributedSubstringFromRange:NSMakeRange(done, lend)];
548 [aString drawAtPoint:NSMakePoint(
549 [helper preEditColumn]*[ts cellSize].width + inset.width,
550 [helper preEditRow]*[ts cellSize].height + inset.height)];
553 // Check whether there're charecters that aren't drawn at
554 // the first line. If everything is already done, the follow
558 // Calculate How many rows are needed to draw all the left
560 int rows = (len - done) / ([ts actualColumns] / 2) + 1;
561 for (r = 1; r <= rows; r++) {
562 lend = len - done > [ts actualColumns] / 2
563 ? [ts actualColumns] / 2 : len - done;
564 aString = [[helper markedText] attributedSubstringFromRange:
565 NSMakeRange(done, lend)];
566 [aString drawAtPoint:NSMakePoint(
568 ([helper preEditRow] + r)*[ts cellSize].height
575 if (shouldDrawInsertionPoint) {
576 MMTextStorage *ts = (MMTextStorage*)[self textStorage];
578 NSRect ipRect = [ts boundingRectForCharacterAtRow:[helper preEditRow]
579 column:[helper preEditColumn]];
580 ipRect.origin.x += [self textContainerOrigin].x;
581 ipRect.origin.y += [self textContainerOrigin].y;
583 // Draw insertion point inside marked text.
584 if ([self hasMarkedText]) {
585 NSFont *theFont = [[self markedTextAttributes]
586 valueForKey:NSFontAttributeName];
587 if (theFont == [ts font])
588 ipRect.origin.x += [ts cellSize].width *
589 ([helper imRange].location +
590 [helper imRange].length);
592 ipRect.origin.x += [ts cellSize].width * 2 *
593 ([helper imRange].location +
594 [helper imRange].length);
597 if (MMInsertionPointHorizontal == insertionPointShape) {
598 int frac = ([ts cellSize].height * insertionPointFraction + 99)/100;
599 ipRect.origin.y += ipRect.size.height - frac;
600 ipRect.size.height = frac;
601 } else if (MMInsertionPointVertical == insertionPointShape) {
602 int frac = ([ts cellSize].width * insertionPointFraction + 99)/100;
603 ipRect.size.width = frac;
604 } else if (MMInsertionPointVerticalRight == insertionPointShape) {
605 int frac = ([ts cellSize].width * insertionPointFraction + 99)/100;
606 ipRect.origin.x += ipRect.size.width - frac;
607 ipRect.size.width = frac;
610 [[helper insertionPointColor] set];
611 if (MMInsertionPointHollow == insertionPointShape) {
617 // NOTE: We only draw the cursor once and rely on Vim to say when it
618 // should be drawn again.
619 shouldDrawInsertionPoint = NO;
621 //NSLog(@"%s draw insertion point %@ shape=%d color=%@", _cmd,
622 // NSStringFromRect(ipRect), insertionPointShape,
623 // [helper insertionPointColor]);
627 // this code invalidates the shadow, so we don't
628 // get shifting ghost text on scroll and resize
629 // but makes speed unusable
630 MMTextStorage *ts = (MMTextStorage*)[self textStorage];
631 if ([ts defaultBackgroundAlpha] < 1.0f) {
632 if (floor(NSAppKitVersionNumber) <= NSAppKitVersionNumber10_1)
634 [[self window] setHasShadow:NO];
635 [[self window] setHasShadow:YES];
638 [[self window] invalidateShadow];
644 - (void)keyDown:(NSEvent *)event
646 [helper keyDown:event];
649 - (void)insertText:(id)string
651 [helper insertText:string];
654 - (void)doCommandBySelector:(SEL)selector
656 [helper doCommandBySelector:selector];
659 - (BOOL)performKeyEquivalent:(NSEvent *)event
661 return [helper performKeyEquivalent:event];
664 - (BOOL)hasMarkedText
666 return [helper hasMarkedText];
669 - (NSRange)markedRange
671 return [helper markedRange];
674 - (NSDictionary *)markedTextAttributes
676 return [helper markedTextAttributes];
679 - (void)setMarkedTextAttributes:(NSDictionary *)attr
681 [helper setMarkedTextAttributes:attr];
684 - (void)setMarkedText:(id)text selectedRange:(NSRange)range
686 [helper setMarkedText:text selectedRange:range];
694 - (NSRect)firstRectForCharacterRange:(NSRange)range
696 return [helper firstRectForCharacterRange:range];
699 - (void)scrollWheel:(NSEvent *)event
701 [helper scrollWheel:event];
704 - (void)mouseDown:(NSEvent *)event
706 [helper mouseDown:event];
709 - (void)rightMouseDown:(NSEvent *)event
711 [helper mouseDown:event];
714 - (void)otherMouseDown:(NSEvent *)event
716 [helper mouseDown:event];
719 - (void)mouseUp:(NSEvent *)event
721 [helper mouseUp:event];
724 - (void)rightMouseUp:(NSEvent *)event
726 [helper mouseUp:event];
729 - (void)otherMouseUp:(NSEvent *)event
731 [helper mouseUp:event];
734 - (void)mouseDragged:(NSEvent *)event
736 [helper mouseDragged:event];
739 - (void)rightMouseDragged:(NSEvent *)event
741 [helper mouseDragged:event];
744 - (void)otherMouseDragged:(NSEvent *)event
746 [helper mouseDragged:event];
749 - (void)mouseMoved:(NSEvent *)event
751 [helper mouseMoved:event];
754 - (void)mouseEntered:(NSEvent *)event
756 [helper mouseEntered:event];
759 - (void)mouseExited:(NSEvent *)event
761 [helper mouseExited:event];
764 - (void)setFrame:(NSRect)frame
766 [super setFrame:frame];
767 [helper setFrame:frame];
770 - (void)viewDidMoveToWindow
772 [helper viewDidMoveToWindow];
775 - (void)viewWillMoveToWindow:(NSWindow *)newWindow
777 [helper viewWillMoveToWindow:newWindow];
780 - (NSMenu*)menuForEvent:(NSEvent *)event
782 // HACK! Return nil to disable NSTextView's popup menus (Vim provides its
783 // own). Called when user Ctrl-clicks in the view (this is already handled
784 // in rightMouseDown:).
788 - (NSArray *)acceptableDragTypes
790 return [NSArray arrayWithObjects:NSFilenamesPboardType,
791 NSStringPboardType, nil];
794 - (BOOL)performDragOperation:(id <NSDraggingInfo>)sender
796 return [helper performDragOperation:sender];
799 - (NSDragOperation)draggingEntered:(id <NSDraggingInfo>)sender
801 return [helper draggingEntered:sender];
804 - (NSDragOperation)draggingUpdated:(id <NSDraggingInfo>)sender
806 return [helper draggingUpdated:sender];
809 - (void)changeFont:(id)sender
811 MMTextStorage *ts = (MMTextStorage*)[self textStorage];
814 NSFont *oldFont = [ts font];
815 NSFont *newFont = [sender convertFont:oldFont];
818 NSString *name = [newFont displayName];
819 unsigned len = [name lengthOfBytesUsingEncoding:NSUTF8StringEncoding];
821 NSMutableData *data = [NSMutableData data];
822 float pointSize = [newFont pointSize];
824 [data appendBytes:&pointSize length:sizeof(float)];
826 ++len; // include NUL byte
827 [data appendBytes:&len length:sizeof(unsigned)];
828 [data appendBytes:[name UTF8String] length:len];
830 [[self vimController] sendMessage:SetFontMsgID data:data];
835 - (void)resetCursorRects
837 // No need to set up cursor rects since Vim handles cursor changes.
840 - (void)updateFontPanel
842 // The font panel is updated whenever the font is set.
847 // NOTE: The menu items cut/copy/paste/undo/redo/select all/... must be bound
848 // to the same actions as in IB otherwise they will not work with dialogs. All
849 // we do here is forward these actions to the Vim process.
851 - (IBAction)cut:(id)sender
853 [[self windowController] vimMenuItemAction:sender];
856 - (IBAction)copy:(id)sender
858 [[self windowController] vimMenuItemAction:sender];
861 - (IBAction)paste:(id)sender
863 [[self windowController] vimMenuItemAction:sender];
866 - (IBAction)undo:(id)sender
868 [[self windowController] vimMenuItemAction:sender];
871 - (IBAction)redo:(id)sender
873 [[self windowController] vimMenuItemAction:sender];
876 - (IBAction)selectAll:(id)sender
878 [[self windowController] vimMenuItemAction:sender];
881 - (BOOL)validateMenuItem:(NSMenuItem *)item
883 if ([item action] == @selector(cut:)
884 || [item action] == @selector(copy:)
885 || [item action] == @selector(paste:)
886 || [item action] == @selector(undo:)
887 || [item action] == @selector(redo:)
888 || [item action] == @selector(selectAll:))
899 @implementation MMTextView (Private)
901 - (MMWindowController *)windowController
903 id windowController = [[self window] windowController];
904 if ([windowController isKindOfClass:[MMWindowController class]])
905 return (MMWindowController*)windowController;
909 - (MMVimController *)vimController
911 return [[self windowController] vimController];
914 - (void)setShouldDrawInsertionPoint:(BOOL)on
916 shouldDrawInsertionPoint = on;
919 - (void)drawInsertionPointAtRow:(int)row column:(int)col shape:(int)shape
920 fraction:(int)percent
922 // This only stores where to draw the insertion point, the actual drawing
923 // is done in drawRect:.
924 shouldDrawInsertionPoint = YES;
925 insertionPointRow = row;
926 insertionPointColumn = col;
927 insertionPointShape = shape;
928 insertionPointFraction = percent;
931 - (void)drawInvertedRectAtRow:(int)row column:(int)col numRows:(int)nrows
932 numColumns:(int)ncols invert:(int)invert
935 // The result should be inverted.
936 int n = numInvertRects++;
937 invertRects = reallocf(invertRects,
938 numInvertRects*sizeof(NSRect));
939 if (NULL != invertRects) {
940 invertRects[n] = [self rectForRow:row column:col numRows:nrows
942 [self setNeedsDisplayInRect:invertRects[n]];
944 n = numInvertRects = 0;
947 // The result should look normal; all we need to do is to mark
948 // the rect for redrawing and Cocoa will redraw the text.
949 NSRect rect = [self rectForRow:row column:col numRows:nrows
951 [self setNeedsDisplayInRect:rect];
955 @end // MMTextView (Private)