I have an NSScrollView with a custom NSImageView as its document view set up in the xib file. My problem comes when I want to magnify the NSScrollView. I would like it to behave like the Preview app on Mac, and I can get it to magnify just fine, but I want it to magnify with the cursor as the centered point.
I have this code in my custom NSScrollView class:
//Informs the receiver that the user has begun a pinch gesture.
- (void)magnifyWithEvent:(NSEvent *)event {
NSPoint conViewPoint =[[self contentView] convertPoint:[event locationInWindow] fromView:nil];
[self setMagnification:[event magnification]+[self magnification] centeredAtPoint:conViewPoint];
}
This works, however it also causes the scroll view to scroll down as it magnifies (though it doesn't move sideways at all). It's more noticeable when zooming in and out multiple times without lifting from the trackpad.
A similar problem seems to be in this question, however I'm using a pinch gesture and not buttons. I've been trying to offset the y axis scrolling as suggested for that question with
[[self documentView] scrollPoint:scrollPoint]
but I haven't been able to figure out a working formula for scrollPoint
that accounts for the changing content view bounds to keep the point under the cursor in the same place. So, I'm wondering if there is a more proper approach to this or if the scrolling really is needed and I just need to figure out the math.
Thanks for any help with this
EDIT:
So I finally figured out the scrolling math. It took a while and way more complicated attempts, but is pretty simple in the end:
- (void)magnifyWithEvent:(NSEvent *)event {
NSPoint docViewPoint =[[self documentView] convertPoint:[event locationInWindow] fromView:nil];
NSPoint docRectOri=[self documentVisibleRect].origin;
float widthGapSize=-docRectOri.x;
float heightGapSize=-docRectOri.y;
if([event phase]==NSEventPhaseBegan){
startDocPoint=docViewPoint;
startPoint.x=(docViewPoint.x+widthGapSize)*[self magnification];
startPoint.y=(docViewPoint.y+heightGapSize)*[self magnification];
}
scrollPoint.x=startDocPoint.x-(startPoint.x/[self magnification]);
scrollPoint.y=startDocPoint.y-(startPoint.y/[self magnification]);
[self setMagnification:[event magnification]+[self magnification] centeredAtPoint:docViewPoint];
[[self documentView] scrollPoint:scrollPoint];
}
I still don't understand why setMagnification:centeredAtPoint:
doesn't just work and am still wondering if anyone has some input on this as my workaround is very jittery on magnification because of the scrolling.