diff --git a/src/MacVim/MMAtsuiTextView.h b/src/MacVim/MMAtsuiTextView.h index ae176e95c7..0219fe490b 100644 --- a/src/MacVim/MMAtsuiTextView.h +++ b/src/MacVim/MMAtsuiTextView.h @@ -9,20 +9,21 @@ */ #import - +#import "MMTextView.h" enum { MMMaxCellsPerChar = 2 }; @class MMTextViewHelper; -@interface MMAtsuiTextView : NSView { +@interface MMAtsuiTextView : NSView { // From MMTextStorage int maxRows, maxColumns; NSColor *defaultBackgroundColor; NSColor *defaultForegroundColor; NSSize cellSize; NSFont *font; + NSFont *fontWide; float linespace; float ascender; @@ -44,28 +45,33 @@ enum { MMMaxCellsPerChar = 2 }; // MMTextStorage methods // - (int)maxRows; +- (int)maxColumns; - (void)getMaxRows:(int*)rows columns:(int*)cols; - (void)setMaxRows:(int)rows columns:(int)cols; - (void)setDefaultColorsBackground:(NSColor *)bgColor foreground:(NSColor *)fgColor; +- (NSColor *)defaultBackgroundColor; +- (NSColor *)defaultForegroundColor; - (NSRect)rectForRowsInRange:(NSRange)range; - (NSRect)rectForColumnsInRange:(NSRange)range; - (void)setFont:(NSFont *)newFont; - (void)setWideFont:(NSFont *)newFont; - (NSFont *)font; +- (NSFont *)fontWide; - (NSSize)cellSize; - (void)setLinespace:(float)newLinespace; // // MMTextView methods // -- (void)setShouldDrawInsertionPoint:(BOOL)on; - (void)setPreEditRow:(int)row column:(int)col; -- (void)hideMarkedTextField; - (void)setMouseShape:(int)shape; - (void)setAntialias:(BOOL)state; - (BOOL)convertPoint:(NSPoint)point toRow:(int *)row column:(int *)column; +- (NSPoint)pointForRow:(int)row column:(int)col; +- (NSRect)rectForRow:(int)row column:(int)col numRows:(int)nr + numColumns:(int)nc; // // NSTextView methods diff --git a/src/MacVim/MMAtsuiTextView.m b/src/MacVim/MMAtsuiTextView.m index 10b6279913..7721801506 100644 --- a/src/MacVim/MMAtsuiTextView.m +++ b/src/MacVim/MMAtsuiTextView.m @@ -87,7 +87,7 @@ column:(int)col2 color:(NSColor *)color; - (void)clearAll; - (void)drawInsertionPointAtRow:(int)row column:(int)col shape:(int)shape - fraction:(int)percent color:(NSColor *)color; + fraction:(int)percent; - (void)drawInvertedRectAtRow:(int)row column:(int)col numRows:(int)nrows numColumns:(int)ncols; @end @@ -139,6 +139,8 @@ defaultLineHeightForFont(NSFont *font) - (void)dealloc { + LOG_DEALLOC + [self disposeAtsuStyles]; [font release]; font = nil; [defaultBackgroundColor release]; defaultBackgroundColor = nil; @@ -155,6 +157,11 @@ defaultLineHeightForFont(NSFont *font) return maxRows; } +- (int)maxColumns +{ + return maxColumns; +} + - (void)getMaxRows:(int*)rows columns:(int*)cols { if (rows) *rows = maxRows; @@ -176,15 +183,22 @@ defaultLineHeightForFont(NSFont *font) defaultBackgroundColor = bgColor ? [bgColor retain] : nil; } - // NOTE: The default foreground color isn't actually used for anything, but - // other class instances might want to be able to access it so it is stored - // here. if (defaultForegroundColor != fgColor) { [defaultForegroundColor release]; defaultForegroundColor = fgColor ? [fgColor retain] : nil; } } +- (NSColor *)defaultBackgroundColor +{ + return defaultBackgroundColor; +} + +- (NSColor *)defaultForegroundColor +{ + return defaultForegroundColor; +} + - (void)setTextContainerInset:(NSSize)size { insetSize = size; @@ -247,6 +261,18 @@ defaultLineHeightForFont(NSFont *font) - (void)setWideFont:(NSFont *)newFont { + if (!newFont) { + if (font) [self setWideFont:font]; + } else if (newFont != fontWide) { + float pointSize = [newFont pointSize]; + NSFontDescriptor *desc = [newFont fontDescriptor]; + NSDictionary *dictWide = [NSDictionary + dictionaryWithObject:[NSNumber numberWithFloat:2*cellSize.width] + forKey:NSFontFixedAdvanceAttribute]; + desc = [desc fontDescriptorByAddingAttributes:dictWide]; + fontWide = [NSFont fontWithDescriptor:desc size:pointSize]; + [fontWide retain]; + } } - (NSFont *)font @@ -254,6 +280,11 @@ defaultLineHeightForFont(NSFont *font) return font; } +- (NSFont *)fontWide +{ + return fontWide; +} + - (NSSize)cellSize { return cellSize; @@ -274,17 +305,13 @@ defaultLineHeightForFont(NSFont *font) - - (void)setShouldDrawInsertionPoint:(BOOL)on { } - (void)setPreEditRow:(int)row column:(int)col { -} - -- (void)hideMarkedTextField -{ + [helper setPreEditRow:row column:col]; } - (void)setMouseShape:(int)shape @@ -297,9 +324,6 @@ defaultLineHeightForFont(NSFont *font) antialias = state; } - - - - (void)keyDown:(NSEvent *)event { [helper keyDown:event]; @@ -322,11 +346,32 @@ defaultLineHeightForFont(NSFont *font) - (BOOL)hasMarkedText { - return NO; + return [helper hasMarkedText]; +} + +- (NSRange)markedRange +{ + return [helper markedRange]; +} + +- (NSDictionary *)markedTextAttributes +{ + return [helper markedTextAttributes]; +} + +- (void)setMarkedTextAttributes:(NSDictionary *)attr +{ + [helper setMarkedTextAttributes:attr]; +} + +- (void)setMarkedText:(id)text selectedRange:(NSRange)range +{ + [helper setMarkedText:text selectedRange:range]; } - (void)unmarkText { + [helper unmarkText]; } - (void)scrollWheel:(NSEvent *)event @@ -462,6 +507,63 @@ defaultLineHeightForFont(NSFont *font) NSPoint pt = { insetSize.width, insetSize.height }; [contentImage compositeToPoint:pt operation:NSCompositeCopy]; + + if ([self hasMarkedText]) { + int len = [[helper markedText] length]; + int rows = 0; + int cols = maxColumns - [helper preEditColumn]; + NSFont *theFont = [[self markedTextAttributes] + valueForKey:NSFontAttributeName]; + if (theFont == [self fontWide]) + cols = cols / 2; + int done = 0; + int lend = cols > len ? len : cols; + NSAttributedString *aString = [[helper markedText] + attributedSubstringFromRange:NSMakeRange(done, lend)]; + NSPoint pt = [self pointForRow:[helper preEditRow] + column:[helper preEditColumn]]; + [aString drawAtPoint:pt]; + done = lend; + if (done != len) { + int r; + rows = (len - done) / (maxColumns / 2) + 1; + for (r = 1; r <= rows; r++) { + lend = len - done > maxColumns / 2 + ? maxColumns / 2 : len - done; + aString = [[helper markedText] attributedSubstringFromRange: + NSMakeRange(done, lend)]; + NSPoint pt = [self pointForRow:[helper preEditRow]+r + column:0]; + [aString drawAtPoint:pt]; + done += lend; + } + } + + rows = maxRows - 1 - [helper preEditRow]; + cols = [helper preEditColumn]; + if (theFont == fontWide) { + cols += ([helper imRange].location+[helper imRange].length) * 2; + if (cols >= maxColumns - 1) { + rows -= cols / maxColumns; + cols = cols % 2 ? cols % maxColumns + 1 : + cols % maxColumns; + } + } else { + cols += ([helper imRange].location+[helper imRange].length); + if (cols >= maxColumns) { + rows -= cols / maxColumns; + cols = cols % 2 ? cols % maxColumns + 1 : + cols % maxColumns; + } + } + + // TODO: Could IM be in "right-left" mode? If so the insertion point + // will be on the wrong side. + [self drawInsertionPointAtRow:rows + column:cols + shape:MMInsertionPointVertical + fraction:25]; + } } - (BOOL) wantsDefaultClipping @@ -580,9 +682,9 @@ defaultLineHeightForFont(NSFont *font) #if MM_DEBUG_DRAWING NSLog(@" Draw cursor at (%d,%d)", row, col); #endif + [helper setInsertionPointColor:[NSColor colorWithRgbInt:color]]; [self drawInsertionPointAtRow:row column:col shape:shape - fraction:percent - color:[NSColor colorWithRgbInt:color]]; + fraction:percent]; } else if (DrawInvertedRectDrawType == type) { int row = *((int*)bytes); bytes += sizeof(int); int col = *((int*)bytes); bytes += sizeof(int); @@ -742,12 +844,67 @@ defaultLineHeightForFont(NSFont *font) if (row) *row = floor((point.y-origin.y-1) / cellSize.height); if (column) *column = floor((point.x-origin.x-1) / cellSize.width); - //NSLog(@"convertPoint:%@ toRow:%d column:%d", NSStringFromPoint(point), - // *row, *column); - return YES; } +- (NSPoint)pointForRow:(int)row column:(int)col +{ + // Return the lower left coordinate of the cell at (row,column). + NSPoint pt; + + pt.x = insetSize.width + col*cellSize.width; + pt.y = [self frame].size.height - + (insetSize.height + (1+row)*cellSize.height); + + return pt; +} + +- (NSRect)rectForRow:(int)row column:(int)col numRows:(int)nr + numColumns:(int)nc +{ + // Return the rect for the block which covers the specified rows and + // columns. The lower-left corner is the origin of this rect. + NSRect rect; + + rect.origin.x = insetSize.width + col*cellSize.width; + rect.origin.y = [self frame].size.height - + (insetSize.height + (nr+row)*cellSize.height); + rect.size.width = nc*cellSize.width; + rect.size.height = nr*cellSize.height; + + return rect; +} + +- (NSArray *)validAttributesForMarkedText +{ + return nil; +} + +- (NSAttributedString *)attributedSubstringFromRange:(NSRange)range +{ + return nil; +} + +- (NSUInteger)characterIndexForPoint:(NSPoint)point +{ + return NSNotFound; +} + +- (NSInteger)conversationIdentifier +{ + return (NSInteger)self; +} + +- (NSRange)selectedRange +{ + return [helper imRange]; +} + +- (NSRect)firstRectForCharacterRange:(NSRange)range +{ + return [helper firstRectForCharacterRange:range]; +} + @end // MMAtsuiTextView @@ -861,7 +1018,7 @@ defaultLineHeightForFont(NSFont *font) - (NSRect)rectFromRow:(int)row1 column:(int)col1 toRow:(int)row2 column:(int)col2 { - NSPoint origin = [self originForRow: row1 column: col1]; + NSPoint origin = [self originForRow:row1 column:col1]; return NSMakeRect(origin.x, origin.y, (col2 + 1 - col1) * cellSize.width, (row2 + 1 - row1) * cellSize.height); @@ -879,7 +1036,7 @@ defaultLineHeightForFont(NSFont *font) //NSLog(@"resizeContentImage"); [contentImage release]; contentImage = [[NSImage alloc] initWithSize:[self textAreaSize]]; - [contentImage setFlipped: YES]; + [contentImage setFlipped:YES]; imageSize = [self textAreaSize]; } @@ -1057,7 +1214,7 @@ defaultLineHeightForFont(NSFont *font) } - (void)drawInsertionPointAtRow:(int)row column:(int)col shape:(int)shape - fraction:(int)percent color:(NSColor *)color + fraction:(int)percent { NSPoint origin = [self originForRow:row column:col]; NSRect rect = NSMakeRect(origin.x, origin.y, @@ -1078,7 +1235,7 @@ defaultLineHeightForFont(NSFont *font) rect.size.width = frac; } - [color set]; + [[helper insertionPointColor] set]; if (MMInsertionPointHollow == shape) { NSFrameRect(rect); } else { diff --git a/src/MacVim/MMTextView.h b/src/MacVim/MMTextView.h index 250f1f9e1b..2547f60857 100644 --- a/src/MacVim/MMTextView.h +++ b/src/MacVim/MMTextView.h @@ -19,12 +19,6 @@ int insertionPointColumn; int insertionPointShape; int insertionPointFraction; - NSRange imRange; - NSRange markedRange; - NSDictionary *markedTextAttributes; - NSMutableAttributedString *markedText; - int preEditRow; - int preEditColumn; BOOL antialias; NSRect *invertRects; int numInvertRects; @@ -34,7 +28,6 @@ - (id)initWithFrame:(NSRect)frame; -- (void)setShouldDrawInsertionPoint:(BOOL)on; - (void)setPreEditRow:(int)row column:(int)col; - (void)performBatchDrawWithData:(NSData *)data; - (void)setMouseShape:(int)shape; @@ -45,16 +38,20 @@ // - (NSFont *)font; - (void)setFont:(NSFont *)newFont; +- (NSFont *)fontWide; - (void)setWideFont:(NSFont *)newFont; - (NSSize)cellSize; - (void)setLinespace:(float)newLinespace; - (int)maxRows; +- (int)maxColumns; - (void)getMaxRows:(int*)rows columns:(int*)cols; - (void)setMaxRows:(int)rows columns:(int)cols; - (NSRect)rectForRowsInRange:(NSRange)range; - (NSRect)rectForColumnsInRange:(NSRange)range; - (void)setDefaultColorsBackground:(NSColor *)bgColor foreground:(NSColor *)fgColor; +- (NSColor *)defaultBackgroundColor; +- (NSColor *)defaultForegroundColor; - (NSSize)constrainRows:(int *)rows columns:(int *)cols toSize:(NSSize)size; - (NSSize)desiredSize; @@ -62,5 +59,8 @@ - (BOOL)convertPoint:(NSPoint)point toRow:(int *)row column:(int *)column; +- (NSPoint)pointForRow:(int)row column:(int)col; +- (NSRect)rectForRow:(int)row column:(int)col numRows:(int)nr + numColumns:(int)nc; @end diff --git a/src/MacVim/MMTextView.m b/src/MacVim/MMTextView.m index 6308bba396..d9faf52334 100644 --- a/src/MacVim/MMTextView.m +++ b/src/MacVim/MMTextView.m @@ -35,13 +35,11 @@ @interface MMTextView (Private) -- (BOOL)convertRow:(int)row column:(int)column toPoint:(NSPoint *)point; -- (BOOL)convertRow:(int)row column:(int)column numRows:(int)nr - numColumns:(int)nc toRect:(NSRect *)rect; - (MMWindowController *)windowController; - (MMVimController *)vimController; +- (void)setShouldDrawInsertionPoint:(BOOL)on; - (void)drawInsertionPointAtRow:(int)row column:(int)col shape:(int)shape - fraction:(int)percent color:(NSColor *)color; + fraction:(int)percent; - (void)drawInvertedRectAtRow:(int)row column:(int)col numRows:(int)nrows numColumns:(int)ncols invert:(int)invert; @end @@ -103,8 +101,6 @@ helper = [[MMTextViewHelper alloc] init]; [helper setTextView:self]; - imRange = NSMakeRange(0, 0); - markedRange = NSMakeRange(0, 0); // NOTE: If the default changes to 'NO' then the intialization of // p_antialias in option.c must change as well. antialias = YES; @@ -116,12 +112,6 @@ { LOG_DEALLOC - if (markedText) { - imRange = NSMakeRange(0, 0); - [markedText release]; - markedText = nil; - } - if (invertRects) { free(invertRects); invertRects = NULL; @@ -143,15 +133,9 @@ return NO; } -- (void)setShouldDrawInsertionPoint:(BOOL)on -{ - shouldDrawInsertionPoint = on; -} - - (void)setPreEditRow:(int)row column:(int)col { - preEditRow = row; - preEditColumn = col; + [helper setPreEditRow:row column:col]; } #define MM_DEBUG_DRAWING 0 @@ -231,13 +215,8 @@ // NOTE: If this is a call to draw the (block) cursor, then cancel // any previous request to draw the insertion point, or it might // get drawn as well. - if (flags & DRAW_CURSOR) { + if (flags & DRAW_CURSOR) [self setShouldDrawInsertionPoint:NO]; - //NSColor *color = [NSColor colorWithRgbInt:bg]; - //[self drawInsertionPointAtRow:row column:col - // shape:MMInsertionPointBlock - // color:color]; - } [textStorage drawString:string atRow:row column:col cells:cells @@ -271,9 +250,9 @@ #if MM_DEBUG_DRAWING NSLog(@" Draw cursor at (%d,%d)", row, col); #endif + [helper setInsertionPointColor:[NSColor colorWithRgbInt:color]]; [self drawInsertionPointAtRow:row column:col shape:shape - fraction:percent - color:[NSColor colorWithRgbInt:color]]; + fraction:percent]; } else if (DrawInvertedRectDrawType == type) { int row = *((int*)bytes); bytes += sizeof(int); int col = *((int*)bytes); bytes += sizeof(int); @@ -335,6 +314,11 @@ [(MMTextStorage*)[self textStorage] setFont:newFont]; } +- (NSFont *)fontWide +{ + return [(MMTextStorage*)[self textStorage] fontWide]; +} + - (void)setWideFont:(NSFont *)newFont { [(MMTextStorage*)[self textStorage] setWideFont:newFont]; @@ -356,6 +340,12 @@ return [ts maxRows]; } +- (int)maxColumns +{ + MMTextStorage *ts = (MMTextStorage *)[self textStorage]; + return [ts maxColumns]; +} + - (void)getMaxRows:(int*)rows columns:(int*)cols { return [(MMTextStorage*)[self textStorage] getMaxRows:rows columns:cols]; @@ -384,6 +374,16 @@ setDefaultColorsBackground:bgColor foreground:fgColor]; } +- (NSColor *)defaultBackgroundColor +{ + return [(MMTextStorage*)[self textStorage] defaultBackgroundColor]; +} + +- (NSColor *)defaultForegroundColor +{ + return [(MMTextStorage*)[self textStorage] defaultForegroundColor]; +} + - (NSSize)constrainRows:(int *)rows columns:(int *)cols toSize:(NSSize)size { NSUserDefaults *ud = [NSUserDefaults standardUserDefaults]; @@ -449,6 +449,39 @@ return YES; } +- (NSPoint)pointForRow:(int)row column:(int)col +{ + // Return the upper-left coordinate for (row,column). + // NOTE: The coordinate system is flipped! + NSPoint pt = [self textContainerOrigin]; + MMTextStorage *ts = (MMTextStorage*)[self textStorage]; + NSSize cellSize = [ts cellSize]; + + pt.x += col * cellSize.width; + pt.y += row * cellSize.height; + + return pt; +} + +- (NSRect)rectForRow:(int)row column:(int)col numRows:(int)nr + numColumns:(int)nc +{ + // Return the rect for the block which covers the specified rows and + // columns. The upper-left corner is the origin of this rect. + // NOTE: The coordinate system is flipped! + NSRect rect; + MMTextStorage *ts = (MMTextStorage*)[self textStorage]; + NSSize cellSize = [ts cellSize]; + + rect.origin = [self textContainerOrigin]; + rect.origin.x += col * cellSize.width; + rect.origin.y += row * cellSize.height; + rect.size.width = cellSize.width * nc; + rect.size.height = cellSize.height * nr; + + return rect; +} + - (BOOL)isOpaque { return NO; @@ -496,7 +529,7 @@ inset.height -= baseline; - int len = [markedText length]; + int len = [[helper markedText] length]; // The following implementation should be re-written with // more efficient way... @@ -509,11 +542,11 @@ cols = cols / 2; int done = 0; int lend = cols > len ? len : cols; - NSAttributedString *aString = [markedText attributedSubstringFromRange: - NSMakeRange(done, lend)]; + NSAttributedString *aString = [[helper markedText] + attributedSubstringFromRange:NSMakeRange(done, lend)]; [aString drawAtPoint:NSMakePoint( - preEditColumn*[ts cellSize].width + inset.width, - preEditRow*[ts cellSize].height + inset.height)]; + [helper preEditColumn]*[ts cellSize].width + inset.width, + [helper preEditRow]*[ts cellSize].height + inset.height)]; done = lend; // Check whether there're charecters that aren't drawn at @@ -527,11 +560,11 @@ for (r = 1; r <= rows; r++) { lend = len - done > [ts actualColumns] / 2 ? [ts actualColumns] / 2 : len - done; - aString = [markedText attributedSubstringFromRange: + aString = [[helper markedText] attributedSubstringFromRange: NSMakeRange(done, lend)]; [aString drawAtPoint:NSMakePoint( inset.width, - (preEditRow + r)*[ts cellSize].height + ([helper preEditRow] + r)*[ts cellSize].height + inset.height)]; done += lend; } @@ -541,8 +574,8 @@ if (shouldDrawInsertionPoint) { MMTextStorage *ts = (MMTextStorage*)[self textStorage]; - NSRect ipRect = [ts boundingRectForCharacterAtRow:preEditRow - column:preEditColumn]; + NSRect ipRect = [ts boundingRectForCharacterAtRow:[helper preEditRow] + column:[helper preEditColumn]]; ipRect.origin.x += [self textContainerOrigin].x; ipRect.origin.y += [self textContainerOrigin].y; @@ -552,10 +585,12 @@ valueForKey:NSFontAttributeName]; if (theFont == [ts font]) ipRect.origin.x += [ts cellSize].width * - (imRange.location + imRange.length); + ([helper imRange].location + + [helper imRange].length); else ipRect.origin.x += [ts cellSize].width * 2 * - (imRange.location + imRange.length); + ([helper imRange].location + + [helper imRange].length); } if (MMInsertionPointHorizontal == insertionPointShape) { @@ -571,7 +606,7 @@ ipRect.size.width = frac; } - [[self insertionPointColor] set]; + [[helper insertionPointColor] set]; if (MMInsertionPointHollow == insertionPointShape) { NSFrameRect(ipRect); } else { @@ -584,7 +619,7 @@ //NSLog(@"%s draw insertion point %@ shape=%d color=%@", _cmd, // NSStringFromRect(ipRect), insertionPointShape, - // [self insertionPointColor]); + // [helper insertionPointColor]); } #if 0 @@ -627,109 +662,37 @@ - (BOOL)hasMarkedText { - //NSLog(@"%s", _cmd); - //return markedText && [markedText length] > 0; - return markedRange.length > 0 ? YES : NO; + return [helper hasMarkedText]; } - (NSRange)markedRange { - if ([self hasMarkedText]) { - return markedRange; - } else - return NSMakeRange(NSNotFound, 0); + return [helper markedRange]; } - (NSDictionary *)markedTextAttributes { - return markedTextAttributes; + return [helper markedTextAttributes]; } - (void)setMarkedTextAttributes:(NSDictionary *)attr { - if (attr != markedTextAttributes) { - [markedTextAttributes release]; - markedTextAttributes = [attr retain]; - } + [helper setMarkedTextAttributes:attr]; } - - (void)setMarkedText:(id)text selectedRange:(NSRange)range { - //NSLog(@"setMarkedText:'%@' selectedRange:%@", text, - // NSStringFromRange(range)); - - MMTextStorage *ts = (MMTextStorage*)[self textStorage]; - if (!ts) - return; - [self unmarkText]; - - if (text && [text length] > 0) { - if ([text isKindOfClass:[NSAttributedString class]]) { - [self setMarkedTextAttributes: - [NSDictionary dictionaryWithObjectsAndKeys: - [ts fontWide], NSFontAttributeName, - [ts defaultBackgroundColor], NSBackgroundColorAttributeName, - [ts defaultForegroundColor], NSForegroundColorAttributeName, - nil]]; - markedText = [[NSMutableAttributedString alloc] - initWithString:[text string] - attributes:[self markedTextAttributes]]; - } else { - [self setMarkedTextAttributes: - [NSDictionary dictionaryWithObjectsAndKeys: - [ts font], NSFontAttributeName, - [ts defaultBackgroundColor], NSBackgroundColorAttributeName, - [ts defaultForegroundColor], NSForegroundColorAttributeName, - nil]]; - markedText = [[NSMutableAttributedString alloc] - initWithString:text - attributes:[self markedTextAttributes]]; - } - - markedRange = NSMakeRange(0, [markedText length]); - if (markedRange.length) { - [markedText addAttribute:NSUnderlineStyleAttributeName - value:[NSNumber numberWithInt:1] - range:markedRange]; - } - imRange = range; - if (range.length) { - [markedText addAttribute:NSUnderlineStyleAttributeName - value:[NSNumber numberWithInt:2] - range:range]; - } - } - [self setNeedsDisplay: YES]; + [helper setMarkedText:text selectedRange:range]; } - (void)unmarkText { - //NSLog(@"%s", _cmd); - imRange = NSMakeRange(0, 0); - markedRange = NSMakeRange(NSNotFound, 0); - [markedText release]; - markedText = nil; + [helper unmarkText]; } - (NSRect)firstRectForCharacterRange:(NSRange)range { - //NSLog(@"%s%@", _cmd, NSStringFromRange(range)); - // HACK! This method is called when the input manager wants to pop up an - // auxiliary window. The position where this should be is controller by - // Vim by sending SetPreEditPositionMsgID so compute a position based on - // the pre-edit (row,column) pair. - MMTextStorage *ts = (MMTextStorage*)[self textStorage]; - - NSRect rect = [ts boundingRectForCharacterAtRow:preEditRow - column:preEditColumn]; - rect.origin.x += [self textContainerOrigin].x; - rect.origin.y += [self textContainerOrigin].y + [ts cellSize].height; - - rect.origin = [self convertPoint:rect.origin toView:nil]; - rect.origin = [[self window] convertBaseToScreen:rect.origin]; - - return rect; + return [helper firstRectForCharacterRange:range]; } - (void)scrollWheel:(NSEvent *)event @@ -926,6 +889,7 @@ return YES; } + @end // MMTextView @@ -933,37 +897,6 @@ @implementation MMTextView (Private) -- (BOOL)convertRow:(int)row column:(int)column toPoint:(NSPoint *)point -{ - MMTextStorage *ts = (MMTextStorage*)[self textStorage]; - NSSize cellSize = [ts cellSize]; - if (!(point && cellSize.width > 0 && cellSize.height > 0)) - return NO; - - *point = [self textContainerOrigin]; - point->x += column * cellSize.width; - point->y += row * cellSize.height; - - return YES; -} - -- (BOOL)convertRow:(int)row column:(int)column numRows:(int)nr - numColumns:(int)nc toRect:(NSRect *)rect -{ - MMTextStorage *ts = (MMTextStorage*)[self textStorage]; - NSSize cellSize = [ts cellSize]; - if (!(rect && cellSize.width > 0 && cellSize.height > 0)) - return NO; - - rect->origin = [self textContainerOrigin]; - rect->origin.x += column * cellSize.width; - rect->origin.y += row * cellSize.height; - rect->size.width = cellSize.width * nc; - rect->size.height = cellSize.height * nr; - - return YES; -} - - (MMWindowController *)windowController { id windowController = [[self window] windowController]; @@ -977,12 +910,14 @@ return [[self windowController] vimController]; } -- (void)drawInsertionPointAtRow:(int)row column:(int)col shape:(int)shape - fraction:(int)percent color:(NSColor *)color +- (void)setShouldDrawInsertionPoint:(BOOL)on { - //NSLog(@"drawInsertionPointAtRow:%d column:%d shape:%d color:%@", - // row, col, shape, color); + shouldDrawInsertionPoint = on; +} +- (void)drawInsertionPointAtRow:(int)row column:(int)col shape:(int)shape + fraction:(int)percent +{ // This only stores where to draw the insertion point, the actual drawing // is done in drawRect:. shouldDrawInsertionPoint = YES; @@ -990,8 +925,6 @@ insertionPointColumn = col; insertionPointShape = shape; insertionPointFraction = percent; - - [self setInsertionPointColor:color]; } - (void)drawInvertedRectAtRow:(int)row column:(int)col numRows:(int)nrows @@ -1003,8 +936,8 @@ invertRects = reallocf(invertRects, numInvertRects*sizeof(NSRect)); if (NULL != invertRects) { - [self convertRow:row column:col numRows:nrows numColumns:ncols - toRect:&invertRects[n]]; + invertRects[n] = [self rectForRow:row column:col numRows:nrows + numColumns:ncols]; [self setNeedsDisplayInRect:invertRects[n]]; } else { n = numInvertRects = 0; @@ -1012,9 +945,8 @@ } else { // The result should look normal; all we need to do is to mark // the rect for redrawing and Cocoa will redraw the text. - NSRect rect; - [self convertRow:row column:col numRows:nrows numColumns:ncols - toRect:&rect]; + NSRect rect = [self rectForRow:row column:col numRows:nrows + numColumns:ncols]; [self setNeedsDisplayInRect:rect]; } } diff --git a/src/MacVim/MMTextViewHelper.h b/src/MacVim/MMTextViewHelper.h index ef7e1798a4..5f56fb7b25 100644 --- a/src/MacVim/MMTextViewHelper.h +++ b/src/MacVim/MMTextViewHelper.h @@ -30,9 +30,20 @@ enum { BOOL isAutoscrolling; int mouseShape; NSTrackingRectTag trackingRectTag; + NSColor *insertionPointColor; + + // Input Manager + NSRange imRange; + NSRange markedRange; + NSDictionary *markedTextAttributes; + NSMutableAttributedString *markedText; + int preEditRow; + int preEditColumn; } - (void)setTextView:(id)view; +- (void)setInsertionPointColor:(NSColor *)color; +- (NSColor *)insertionPointColor; - (void)keyDown:(NSEvent *)event; - (void)insertText:(id)string; @@ -53,4 +64,20 @@ enum { - (NSDragOperation)draggingUpdated:(id )sender; - (void)setMouseShape:(int)shape; +// Input Manager +- (BOOL)hasMarkedText; +- (NSRange)markedRange; +- (NSDictionary *)markedTextAttributes; +- (void)setMarkedTextAttributes:(NSDictionary *)attr; +- (void)setMarkedText:(id)text selectedRange:(NSRange)range; +- (void)unmarkText; +- (NSMutableAttributedString *)markedText; +- (void)setPreEditRow:(int)row column:(int)col; +- (int)preEditRow; +- (int)preEditColumn; +- (void)setImRange:(NSRange)range; +- (NSRange)imRange; +- (void)setMarkedRange:(NSRange)range; +- (NSRect)firstRectForCharacterRange:(NSRange)range; + @end diff --git a/src/MacVim/MMTextViewHelper.m b/src/MacVim/MMTextViewHelper.m index 08e4f70a0a..3916d08e04 100644 --- a/src/MacVim/MMTextViewHelper.m +++ b/src/MacVim/MMTextViewHelper.m @@ -49,12 +49,32 @@ static float MMDragAreaSize = 73.0f; @implementation MMTextViewHelper +- (void)dealloc +{ + [markedText release]; markedText = nil; + + [super dealloc]; +} + - (void)setTextView:(id)view { // Only keep a weak reference to owning text view. textView = view; } +- (void)setInsertionPointColor:(NSColor *)color +{ + if (color != insertionPointColor) { + [insertionPointColor release]; + insertionPointColor = [color retain]; + } +} + +- (NSColor *)insertionPointColor +{ + return insertionPointColor; +} + - (void)keyDown:(NSEvent *)event { //NSLog(@"%s %@", _cmd, event); @@ -515,6 +535,158 @@ static float MMDragAreaSize = 73.0f; [self setCursor]; } +- (BOOL)hasMarkedText +{ + return markedRange.length > 0 ? YES : NO; +} + +- (NSRange)markedRange +{ + if ([self hasMarkedText]) + return markedRange; + else + return NSMakeRange(NSNotFound, 0); +} + +- (NSDictionary *)markedTextAttributes +{ + return markedTextAttributes; +} + +- (void)setMarkedTextAttributes:(NSDictionary *)attr +{ + if (attr != markedTextAttributes) { + [markedTextAttributes release]; + markedTextAttributes = [attr retain]; + } +} + +- (void)setMarkedText:(id)text selectedRange:(NSRange)range +{ + [self unmarkText]; + + if (!(text && [text length] > 0)) + return; + + // HACK! Determine if the marked text is wide or normal width. This seems + // to always use 'wide' when there are both wide and normal width + // characters. + NSString *string = text; + NSFont *theFont = [textView font]; + if ([text isKindOfClass:[NSAttributedString class]]) { + theFont = [textView fontWide]; + string = [text string]; + } + + // TODO: Use special colors for marked text. + [self setMarkedTextAttributes: + [NSDictionary dictionaryWithObjectsAndKeys: + theFont, NSFontAttributeName, + [textView defaultBackgroundColor], NSBackgroundColorAttributeName, + [textView defaultForegroundColor], NSForegroundColorAttributeName, + nil]]; + + markedText = [[NSMutableAttributedString alloc] + initWithString:string + attributes:[self markedTextAttributes]]; + + markedRange = NSMakeRange(0, [markedText length]); + if (markedRange.length) { + [markedText addAttribute:NSUnderlineStyleAttributeName + value:[NSNumber numberWithInt:1] + range:markedRange]; + } + imRange = range; + if (range.length) { + [markedText addAttribute:NSUnderlineStyleAttributeName + value:[NSNumber numberWithInt:2] + range:range]; + } + + [textView setNeedsDisplay:YES]; +} + +- (void)unmarkText +{ + imRange = NSMakeRange(0, 0); + markedRange = NSMakeRange(NSNotFound, 0); + [markedText release]; + markedText = nil; +} + +- (NSMutableAttributedString *)markedText +{ + return markedText; +} + +- (void)setPreEditRow:(int)row column:(int)col +{ + preEditRow = row; + preEditColumn = col; +} + +- (int)preEditRow +{ + return preEditRow; +} + +- (int)preEditColumn +{ + return preEditColumn; +} + +- (void)setImRange:(NSRange)range +{ + imRange = range; +} + +- (NSRange)imRange +{ + return imRange; +} + +- (void)setMarkedRange:(NSRange)range +{ + markedRange = range; +} + +- (NSRect)firstRectForCharacterRange:(NSRange)range +{ + // This method is called when the input manager wants to pop up an + // auxiliary window. The position where this should be is controlled by + // Vim by sending SetPreEditPositionMsgID so compute a position based on + // the pre-edit (row,column) pair. + int col = preEditColumn; + int row = preEditRow + 1; + + NSFont *theFont = [[textView markedTextAttributes] + valueForKey:NSFontAttributeName]; + if (theFont == [textView fontWide]) { + col += imRange.location * 2; + if (col >= [textView maxColumns] - 1) { + row += (col / [textView maxColumns]); + col = col % 2 ? col % [textView maxColumns] + 1 : + col % [textView maxColumns]; + } + } else { + col += imRange.location; + if (col >= [textView maxColumns]) { + row += (col / [textView maxColumns]); + col = col % [textView maxColumns]; + } + } + + NSRect rect = [textView rectForRow:row + column:col + numRows:1 + numColumns:range.length]; + + rect.origin = [textView convertPoint:rect.origin toView:nil]; + rect.origin = [[textView window] convertBaseToScreen:rect.origin]; + + return rect; +} + @end // MMTextViewHelper diff --git a/src/MacVim/MacVim.h b/src/MacVim/MacVim.h index bf51c9a803..7c49ca039e 100644 --- a/src/MacVim/MacVim.h +++ b/src/MacVim/MacVim.h @@ -257,3 +257,17 @@ ATSFontContainerRef loadFonts(); // MacVim Apple Event Constants #define keyMMUntitledWindow 'MMuw' + + + + +#if MAC_OS_X_VERSION_MAX_ALLOWED <= MAC_OS_X_VERSION_10_4 +// NSInteger was introduced in 10.5 +# if __LP64__ || NS_BUILD_32_LIKE_64 +typedef long NSInteger; +typedef unsigned long NSUInteger; +# else +typedef int NSInteger; +typedef unsigned int NSUInteger; +# endif +#endif