From 81e7ee1724b8605dcaa8514dca16aaed3d1c2891 Mon Sep 17 00:00:00 2001 From: "bjorn.winckler" Date: Fri, 24 Aug 2007 20:34:41 +0000 Subject: [PATCH] Manual drawing of the insertion point (now also works in replace mode) git-svn-id: http://macvim.googlecode.com/svn/trunk@189 96c4425d-ca35-0410-94e5-3396d5c13a8f --- MMBackend.h | 3 ++- MMBackend.m | 31 +++++++++++--------------- MMTextStorage.h | 2 +- MMTextStorage.m | 2 +- MMTextView.h | 6 ++++- MMTextView.m | 66 +++++++++++++++++++++++++++++++++++++++++++++++++++---- MMVimController.m | 28 +++++++++-------------- MacVim.h | 11 ++++++++-- MacVim.m | 1 - gui_macvim.m | 15 +++++++++++++ 10 files changed, 118 insertions(+), 47 deletions(-) diff --git a/MMBackend.h b/MMBackend.h index f30850f0..42c2a742 100644 --- a/MMBackend.h +++ b/MMBackend.h @@ -47,6 +47,8 @@ flags:(int)flags; - (void)insertLinesFromRow:(int)row count:(int)count scrollBottom:(int)bottom left:(int)left right:(int)right; +- (void)drawCursorAtRow:(int)row column:(int)col shape:(int)shape + color:(int)color; - (void)flushQueue:(BOOL)force; - (BOOL)waitForInput:(int)milliseconds; - (void)exit; @@ -60,7 +62,6 @@ saving:(int)saving; - (int)presentDialogWithType:(int)type title:(char *)title message:(char *)msg buttons:(char *)btns textField:(char *)txtfield; -- (void)updateInsertionPoint; - (void)addMenuWithTag:(int)tag parent:(int)parentTag name:(char *)name atIndex:(int)index; - (void)addMenuItemWithTag:(int)tag parent:(int)parentTag name:(char *)name diff --git a/MMBackend.m b/MMBackend.m index de05cc62..992f05e8 100644 --- a/MMBackend.m +++ b/MMBackend.m @@ -269,6 +269,19 @@ static int specialKeyToNSKey(int key); [drawData appendBytes:&right length:sizeof(int)]; } +- (void)drawCursorAtRow:(int)row column:(int)col shape:(int)shape + color:(int)color +{ + int type = DrawCursorDrawType; + + [drawData appendBytes:&type length:sizeof(int)]; + + [drawData appendBytes:&color length:sizeof(int)]; + [drawData appendBytes:&row length:sizeof(int)]; + [drawData appendBytes:&col length:sizeof(int)]; + [drawData appendBytes:&shape length:sizeof(int)]; +} + - (void)flushQueue:(BOOL)force { // NOTE! This method gets called a lot; if we were to flush every time it @@ -284,9 +297,6 @@ static int specialKeyToNSKey(int key); } if ([queue count] > 0) { - // TODO: Come up with a better way to handle the insertion point. - [self updateInsertionPoint]; - @try { [frontendProxy processCommandQueue:queue]; } @@ -513,21 +523,6 @@ static int specialKeyToNSKey(int key); return retval; } -- (void)updateInsertionPoint -{ - NSMutableData *data = [NSMutableData data]; - - int state = get_shape_idx(FALSE); - state = (state == SHAPE_IDX_I) || (state == SHAPE_IDX_CI); - - [data appendBytes:&defaultForegroundColor length:sizeof(int)]; - [data appendBytes:&gui.row length:sizeof(int)]; - [data appendBytes:&gui.col length:sizeof(int)]; - [data appendBytes:&state length:sizeof(int)]; - - [self queueMessage:UpdateInsertionPointMsgID data:data]; -} - - (void)addMenuWithTag:(int)tag parent:(int)parentTag name:(char *)name atIndex:(int)index { diff --git a/MMTextStorage.h b/MMTextStorage.h index 457e195f..1a87213a 100644 --- a/MMTextStorage.h +++ b/MMTextStorage.h @@ -54,7 +54,7 @@ - (NSSize)cellSize; - (NSRect)rectForRowsInRange:(NSRange)range; - (NSRect)rectForColumnsInRange:(NSRange)range; -- (unsigned)offsetFromRow:(int)row column:(int)col; +- (unsigned)characterIndexForRow:(int)row column:(int)col; - (BOOL)resizeToFitSize:(NSSize)size; - (NSSize)fitToSize:(NSSize)size; - (NSSize)fitToSize:(NSSize)size rows:(int *)rows columns:(int *)columns; diff --git a/MMTextStorage.m b/MMTextStorage.m index adeae57a..51a9a2d6 100644 --- a/MMTextStorage.m +++ b/MMTextStorage.m @@ -454,7 +454,7 @@ return rect; } -- (unsigned)offsetFromRow:(int)row column:(int)col +- (unsigned)characterIndexForRow:(int)row column:(int)col { // Ensure the offset returned is valid. // This code also works if maxRows and/or maxColumns is 0. diff --git a/MMTextView.h b/MMTextView.h index 08f9d2e7..911c63ee 100644 --- a/MMTextView.h +++ b/MMTextView.h @@ -21,9 +21,13 @@ int dragColumn; int dragFlags; NSPoint dragPoint; + int insertionPointRow; + int insertionPointColumn; + int insertionPointShape; } - (NSEvent *)lastMouseDownEvent; -- (void)setShouldDrawInsertionPoint:(BOOL)enable; +- (void)drawInsertionPointAtRow:(int)row column:(int)col shape:(int)shape + color:(NSColor *)color; @end diff --git a/MMTextView.m b/MMTextView.m index 906de0f0..e8c8b158 100644 --- a/MMTextView.m +++ b/MMTextView.m @@ -49,14 +49,72 @@ static float MMDragAreaSize = 73.0f; return lastMouseDownEvent; } -- (void)setShouldDrawInsertionPoint:(BOOL)enable +- (BOOL)shouldDrawInsertionPoint { - shouldDrawInsertionPoint = enable; + // NOTE: The insertion point is drawn manually in drawRect:. It would be + // nice to be able to use the insertion point related methods of + // NSTextView, but it seems impossible to get them to work properly (search + // the cocoabuilder archives). + return NO; } -- (BOOL)shouldDrawInsertionPoint +- (void)drawInsertionPointAtRow:(int)row column:(int)col shape:(int)shape + color:(NSColor *)color +{ + // This only stores where to draw the insertion point, the actual drawing + // is done in drawRect:. + shouldDrawInsertionPoint = YES; + insertionPointRow = row; + insertionPointColumn = col; + insertionPointShape = shape; + + [self setInsertionPointColor:color]; +} + +- (void)drawRect:(NSRect)rect { - return shouldDrawInsertionPoint; + [super drawRect:rect]; + + if (shouldDrawInsertionPoint) { + MMTextStorage *ts = (MMTextStorage*)[self textStorage]; + NSLayoutManager *lm = [self layoutManager]; + NSTextContainer *tc = [self textContainer]; + + // Given (row,column), calculate the bounds of the glyph at that spot. + // We use the layout manager because this gives us exactly the size and + // location of the glyph so that we can match the insertion point to + // it. + unsigned charIdx = [ts characterIndexForRow:insertionPointRow + column:insertionPointColumn]; + NSRange glyphRange = + [lm glyphRangeForCharacterRange:NSMakeRange(charIdx,1) + actualCharacterRange:NULL]; + NSRect glyphRect = [lm boundingRectForGlyphRange:glyphRange + inTextContainer:tc]; + glyphRect.origin.x += [self textContainerOrigin].x; + glyphRect.origin.y += [self textContainerOrigin].y; + + if (MMInsertionPointHorizontal == insertionPointShape) { + glyphRect.origin.y += glyphRect.size.height - 1; + glyphRect.size.height = 2; + } else if (MMInsertionPointVertical == insertionPointShape) { + glyphRect.size.width = 2; + } + + if (MMInsertionPointHollow == insertionPointShape) { + // This looks very ugly. + [[self insertionPointColor] set]; + //[NSBezierPath setDefaultLineWidth:2.0]; + //[NSBezierPath setDefaultLineJoinStyle:NSRoundLineJoinStyle]; + [NSBezierPath strokeRect:glyphRect]; + } else { + NSRectFill(glyphRect); + } + + // NOTE: We only draw the cursor once and rely on Vim to say when it + // should be drawn again. + shouldDrawInsertionPoint = NO; + } } - (void)insertText:(id)string diff --git a/MMVimController.m b/MMVimController.m index 4b615725..5a8106c4 100644 --- a/MMVimController.m +++ b/MMVimController.m @@ -505,23 +505,6 @@ static NSMenuItem *findMenuItemWithTagInMenu(NSMenu *root, int tag) [[windowController window] setTitle:string]; [string release]; - } else if (UpdateInsertionPointMsgID == msgid) { - const void *bytes = [data bytes]; - int color = *((int*)bytes); bytes += sizeof(int); - int row = *((int*)bytes); bytes += sizeof(int); - int col = *((int*)bytes); bytes += sizeof(int); - int state = *((int*)bytes); bytes += sizeof(int); - - // TODO! Move to window controller. - MMTextView *textView = [windowController textView]; - if (textView) { - MMTextStorage *textStorage = (MMTextStorage*)[textView textStorage]; - unsigned off = [textStorage offsetFromRow:row column:col]; - - [textView setInsertionPointColor:[NSColor colorWithRgbInt:color]]; - [textView setSelectedRange:NSMakeRange(off, 0)]; - [textView setShouldDrawInsertionPoint:state]; - } } else if (AddMenuMsgID == msgid) { NSString *title = nil; const void *bytes = [data bytes]; @@ -768,7 +751,8 @@ static NSMenuItem *findMenuItemWithTagInMenu(NSMenu *root, int tag) { // TODO! Move to window controller. MMTextStorage *textStorage = [windowController textStorage]; - if (!textStorage) + MMTextView *textView = [windowController textView]; + if (!(textStorage && textView)) return; const void *bytes = [data bytes]; @@ -840,6 +824,14 @@ static NSMenuItem *findMenuItemWithTagInMenu(NSMenu *root, int tag) [textStorage insertLinesAtRow:row lineCount:count scrollBottom:bot left:left right:right color:[NSColor colorWithRgbInt:color]]; + } else if (DrawCursorDrawType == type) { + int color = *((int*)bytes); bytes += sizeof(int); + int row = *((int*)bytes); bytes += sizeof(int); + int col = *((int*)bytes); bytes += sizeof(int); + int shape = *((int*)bytes); bytes += sizeof(int); + + [textView drawInsertionPointAtRow:row column:col shape:shape + color:[NSColor colorWithRgbInt:color]]; } else { NSLog(@"WARNING: Unknown draw type (type=%d)", type); } diff --git a/MacVim.h b/MacVim.h index d97b1205..4bead286 100644 --- a/MacVim.h +++ b/MacVim.h @@ -94,7 +94,6 @@ enum { MouseUpMsgID, MouseDraggedMsgID, FlushQueueMsgID, - UpdateInsertionPointMsgID, AddMenuMsgID, AddMenuItemMsgID, RemoveMenuItemMsgID, @@ -127,7 +126,15 @@ enum { ClearBlockDrawType, DeleteLinesDrawType, ReplaceStringDrawType, - InsertLinesDrawType + InsertLinesDrawType, + DrawCursorDrawType +}; + +enum { + MMInsertionPointBlock, + MMInsertionPointHorizontal, + MMInsertionPointVertical, + MMInsertionPointHollow, }; diff --git a/MacVim.m b/MacVim.m index b8aa0782..ed967924 100644 --- a/MacVim.m +++ b/MacVim.m @@ -32,7 +32,6 @@ char *MessageStrings[] = "MouseUpMsgID", "MouseDraggedMsgID", "FlushQueueMsgID", - "UpdateInsertionPointMsgID", "AddMenuMsgID", "AddMenuItemMsgID", "RemoveMenuItemMsgID", diff --git a/gui_macvim.m b/gui_macvim.m index c9bdd654..c811c440 100644 --- a/gui_macvim.m +++ b/gui_macvim.m @@ -1018,6 +1018,11 @@ gui_mch_dialog( void gui_mch_draw_hollow_cursor(guicolor_T color) { + //NSLog(@"gui_mch_draw_hollow_cursor(color=0x%x)", color); + + return [[MMBackend sharedInstance] drawCursorAtRow:gui.row column:gui.col + shape:MMInsertionPointHollow + color:color]; } @@ -1027,6 +1032,16 @@ gui_mch_draw_hollow_cursor(guicolor_T color) void gui_mch_draw_part_cursor(int w, int h, guicolor_T color) { + //NSLog(@"gui_mch_draw_part_cursor(w=%d, h=%d, color=0x%x)", w, h, color); + + int shape = MMInsertionPointBlock; + switch (shape_table[get_shape_idx(FALSE)].shape) { + case SHAPE_HOR: shape = MMInsertionPointHorizontal; break; + case SHAPE_VER: shape = MMInsertionPointVertical; break; + } + + return [[MMBackend sharedInstance] drawCursorAtRow:gui.row column:gui.col + shape:shape color:color]; } -- 2.11.4.GIT