NSView drawRect vs. autoscrolling
NSView drawRect vs. autoscrolling
- Subject: NSView drawRect vs. autoscrolling
- From: Tom Waters <email@hidden>
- Date: Mon, 11 Jun 2001 17:09:45 -0700
I am wondering how I can have a view, nested in a scrollview, that draws
on itself and stay in synch with the autoscrolling during drag and drop.
It seems like there is a race condition here:
In my drawRect I want to paint a border using [self visibleRect] during
drags. The problem is, when a pending drag causes the view to scroll,
the subsequent drawRect is getting the wrong answer from visibleRect.
After some investigation I think this is more likely: the window system
is just copying bits on the screen, assuming that this will leave the
correct image.
Anytime you draw in a view dependant on the enclosing view, the
scrolling mechanism can't optimize the scrolling via copyarea... is
there some place I can turn this off?
I've tried to discover when i'm being autoscrolled, but the methods in
NSView that seem like they should be called in this case are NEVER
called. If I could get notified of how far the view was being
autoscrolled, I could use setNeedsDisplayInRect to invalidate that one
scanline sliver of bad pixels.
Throw this code in a custom view in IB and wrap it in a scrollview to
see what I mean.
#import <Cocoa/Cocoa.h>
@interface ScrollBugView : NSView
{
BOOL hasDragInside;
}
@end
@implementation ScrollBugView
- (id)initWithFrame:(NSRect)frame
{
[self registerForDraggedTypes: [NSArray arrayWithObject:
NSFilenamesPboardType]];
return [super initWithFrame: NSMakeRect(0, 0, frame.size.width, 2000)];
}
- (BOOL)isFlipped
{
return YES;
}
- (void)drawRect:(NSRect)rect {
int i;
int fontsize = 12;
int start = rect.origin.y / fontsize;
int end = start + (rect.origin.y + rect.size.height) / fontsize + 1;
[[NSColor controlBackgroundColor] set];
NSRectFill(rect);
[[NSColor textColor] set];
for (i = start; i < end; i++) {
[[NSString stringWithFormat: @"%d", i] drawAtPoint:
NSMakePoint(10, i*fontsize) withAttributes: nil];
}
if (hasDragInside) {
[[NSColor redColor] set];
NSFrameRect([self visibleRect]);
}
}
- (NSDragOperation)draggingEntered:(id <NSDraggingInfo>)info
{
hasDragInside = YES;
[self setNeedsDisplayInRect: [self visibleRect]];
return NSDragOperationGeneric;
}
- (void)draggingExited:(id <NSDraggingInfo>)info
{
hasDragInside = NO;
[self setNeedsDisplayInRect: [self visibleRect]];
}
- (BOOL)prepareForDragOperation:(id <NSDraggingInfo>)info
{
[self draggingExited: info];
return NO;
}
// NONE of these methods are ever called!?!???
- (void)scrollRect:(NSRect)aRect
by:(NSSize)offset
{
NSLog(@"scrollRect: %d,%d %dx%d by: %d,%d",
aRect.origin.x, aRect.origin.y, aRect.size.width, aRect.size.height,
offset.width, offset.height);
[super scrollRect: aRect by: offset];
}
- (void)scrollPoint:(NSPoint)aPoint
{
NSLog(@"scrollPoint: %d,%d", aPoint.x, aPoint.y);
[super scrollPoint: aPoint];
}
- (BOOL)scrollRectToVisible:(NSRect)aRect
{
BOOL b = [super scrollRectToVisible: aRect];
NSLog(@"%d = scrollRectToVisible: %d,%d %dx%d", b,
aRect.origin.x, aRect.origin.y, aRect.size.width, aRect.size.height);
return b;
}
- (BOOL)autoscroll:(NSEvent *)theEvent
{
BOOL b = [super autoscroll: theEvent];
NSLog(@"%d = autoscroll: %@", b, theEvent);
return b;
}
@end