From c8fee6645a732f8a3e3a860a45bd6d66cea5df19 Mon Sep 17 00:00:00 2001 From: Bibiko Date: Sat, 30 Jan 2010 13:02:14 +0000 Subject: =?UTF-8?q?=E2=80=A2=20current=20query=20highlighting=20is=20done?= =?UTF-8?q?=20now=20in=20drawRect:=20=20(much=20more=20faster=20and=20than?= =?UTF-8?q?ks=20to=20Jakob)=20=E2=80=A2=20improved=20snippet=20background?= =?UTF-8?q?=20drawings=20esp.=20for=20multiple=20lines=20(commit=20on=20be?= =?UTF-8?q?half=20of=20Jakob)=20=E2=80=A2=20simplified=20code=20for=20chan?= =?UTF-8?q?ging=20and=20setting=20background=20colors=20and=20Pref=20setti?= =?UTF-8?q?ng=20for=20highlight=20current=20query=20by=20observers=20(much?= =?UTF-8?q?=20more=20faster)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Source/CMTextView.m | 154 ++++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 131 insertions(+), 23 deletions(-) (limited to 'Source/CMTextView.m') diff --git a/Source/CMTextView.m b/Source/CMTextView.m index 55e6d4e1..c14f5d59 100644 --- a/Source/CMTextView.m +++ b/Source/CMTextView.m @@ -72,8 +72,23 @@ YY_BUFFER_STATE yy_scan_string (const char *); #pragma mark - +// some helper functions for handling rectangles and points +// needed in roundedBezierPathAroundRange: +static inline CGFloat SPRectTop(NSRect rectangle) { return rectangle.origin.y; } +static inline CGFloat SPRectBottom(NSRect rectangle) { return rectangle.origin.y+rectangle.size.height; } +static inline CGFloat SPRectLeft(NSRect rectangle) { return rectangle.origin.x; } +static inline CGFloat SPRectRight(NSRect rectangle) { return rectangle.origin.x+rectangle.size.width; } +static inline CGFloat SPPointDistance(NSPoint a, NSPoint b) { return sqrt( (a.x-b.x)*(a.x-b.x) + (a.y-b.y)*(a.y-b.y) ); } +static inline NSPoint SPPointOnLine(NSPoint a, NSPoint b, CGFloat t) { return NSMakePoint(a.x*(1.-t) + b.x*t, a.y*(1.-t) + b.y*t); } + + @implementation CMTextView +@synthesize queryHiliteColor; +@synthesize queryEditorBackgroundColor; +@synthesize queryRange; +@synthesize shouldHiliteQuery; + /* * Sort function (mainly used to sort the words in the textView) */ @@ -147,6 +162,11 @@ NSInteger alphabeticSort(id string1, id string2, void *reverse) prefs = [[NSUserDefaults standardUserDefaults] retain]; + // Register observers for the when editor background colors preference changes + [prefs addObserver:self forKeyPath:SPCustomQueryEditorBackgroundColor options:NSKeyValueObservingOptionNew context:NULL]; + [prefs addObserver:self forKeyPath:SPCustomQueryEditorHighlightQueryColor options:NSKeyValueObservingOptionNew context:NULL]; + [prefs addObserver:self forKeyPath:SPCustomQueryHighlightCurrentQuery options:NSKeyValueObservingOptionNew context:NULL]; + } - (void) setConnection:(MCPConnection *)theConnection withVersion:(NSInteger)majorVersion @@ -155,6 +175,23 @@ NSInteger alphabeticSort(id string1, id string2, void *reverse) mySQLmajorVersion = majorVersion; } +/** + * This method is called as part of Key Value Observing which is used to watch for prefernce changes which effect the interface. + */ +- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context +{ + if ([keyPath isEqualToString:SPCustomQueryEditorBackgroundColor]) { + [self setQueryEditorBackgroundColor:[NSUnarchiver unarchiveObjectWithData:[change objectForKey:NSKeyValueChangeNewKey]]]; + [self setNeedsDisplay:YES]; + } else if ([keyPath isEqualToString:SPCustomQueryEditorHighlightQueryColor]) { + [self setQueryHiliteColor:[NSUnarchiver unarchiveObjectWithData:[change objectForKey:NSKeyValueChangeNewKey]]]; + [self setNeedsDisplay:YES]; + } else if ([keyPath isEqualToString:SPCustomQueryHighlightCurrentQuery]) { + [self setShouldHiliteQuery:[[change objectForKey:NSKeyValueChangeNewKey] boolValue]]; + [self setNeedsDisplay:YES]; + } +} + /* * Return an array of NSDictionary containing the sorted strings representing * the set of unique words, SQL keywords, user-defined funcs/procs, tables etc. @@ -2911,40 +2948,109 @@ NSInteger alphabeticSort(id string1, id string2, void *reverse) } - - (void)drawRect:(NSRect)rect { + // Draw textview's background since due to the snippet highlighting we're responsible for it. + [[[NSUnarchiver unarchiveObjectWithData:[prefs dataForKey:SPCustomQueryEditorBackgroundColor]] retain] setFill]; + [[self queryEditorBackgroundColor] setFill]; + NSRectFill(rect); + + // Highlightes the current query if set in the Pref and no snippet session + // and if nothing is selected in the text view + if ([self shouldHiliteQuery] && snippetControlCounter<=-1 && ![self selectedRange].length) { + NSUInteger rectCount; + NSRectArray queryRects = [[self layoutManager] rectArrayForCharacterRange: [self queryRange] + withinSelectedCharacterRange: [self queryRange] + inTextContainer: [self textContainer] + rectCount: &rectCount ]; + [[self queryHiliteColor] setFill]; + NSRectFillList(queryRects, rectCount); + } + // Highlight snippets coming from the Query Favorite text macro if(snippetControlCounter > -1) { - NSInteger i; - for(i=0; i -1) { - NSUInteger rectCount; - NSRange snippetRange = NSMakeRange(snippetControlArray[i][0],snippetControlArray[i][1]); - NSRectArray snippetRects = [[self layoutManager] rectArrayForCharacterRange: snippetRange - withinSelectedCharacterRange: snippetRange - inTextContainer: [self textContainer] - rectCount: &rectCount ]; - for (NSUInteger j=0; j2 || (rectCount>1 && (SPRectRight(rects[1]) >= SPRectLeft(rects[0]) || connectDisconnectedPartsWithLine))) { + // highlight complicated multiline snippet + NSRect lineRects[4]; + lineRects[0] = rects[0]; + lineRects[1] = rects[1]; + lineRects[2] = rects[rectCount-2]; + lineRects[3] = rects[rectCount-1]; + for(int j=0;j<4;j++) lineRects[j] = NSInsetRect(lineRects[j], horzInset, vertInset); + NSPoint vertices[8]; + vertices[0] = NSMakePoint( SPRectLeft(lineRects[0]), SPRectTop(lineRects[0]) ); // point a + vertices[1] = NSMakePoint( SPRectRight(lineRects[0]), SPRectTop(lineRects[0]) ); // point b + vertices[2] = NSMakePoint( SPRectRight(lineRects[2]), SPRectBottom(lineRects[2]) ); // point c + vertices[3] = NSMakePoint( SPRectRight(lineRects[3]), SPRectBottom(lineRects[2]) ); // point d + vertices[4] = NSMakePoint( SPRectRight(lineRects[3]), SPRectBottom(lineRects[3]) ); // point e + vertices[5] = NSMakePoint( SPRectLeft(lineRects[3]), SPRectBottom(lineRects[3]) ); // point f + vertices[6] = NSMakePoint( SPRectLeft(lineRects[1]), SPRectTop(lineRects[1]) ); // point g + vertices[7] = NSMakePoint( SPRectLeft(lineRects[0]), SPRectTop(lineRects[1]) ); // point h + + for (NSUInteger j=0; j<8; j++) { + NSPoint curr = vertices[j]; + NSPoint prev = vertices[(j+8-1)%8]; + NSPoint next = vertices[(j+1)%8]; + + CGFloat s = radius/SPPointDistance(prev, curr); + if (s>0.5) s = 0.5; + CGFloat t = radius/SPPointDistance(curr, next); + if (t>0.5) t = 0.5; + + NSPoint a = SPPointOnLine(curr, prev, 0.5); + NSPoint b = SPPointOnLine(curr, prev, s); + NSPoint c = curr; + NSPoint d = SPPointOnLine(curr, next, t); + NSPoint e = SPPointOnLine(curr, next, 0.5); + + if (j==0) [funkyPath moveToPoint:a]; + [funkyPath lineToPoint: b]; + [funkyPath curveToPoint:d controlPoint1:SPPointOnLine(b, c, kappa) controlPoint2:SPPointOnLine(d, c, kappa)]; + [funkyPath lineToPoint: e]; + } + } else { + //highlight disconnected snippet parts (or single line snippet) + for (NSUInteger j=0; j