1//SBCenteringClipView.m
2//Created by Brock Brandenberg
3//Who is much cooler than we are.  Maybe.
4
5#import "SBCenteringClipView.h"
6
7@implementation SBCenteringClipView
8
9// ----------------------------------------
10
11-(void)centerDocument
12{
13    NSRect docRect = [[self documentView] frame];
14    NSRect clipRect = [self bounds];
15
16    // We can leave these values as integers (don't need the "2.0")
17    if( docRect.size.width < clipRect.size.width )
18        clipRect.origin.x = roundf( ( docRect.size.width - clipRect.size.width ) / 2.0 );
19
20    if( docRect.size.height < clipRect.size.height )
21        clipRect.origin.y = roundf( ( docRect.size.height - clipRect.size.height ) / 2.0 );
22
23    // Probably the most efficient way to move the bounds origin.
24    [self scrollToPoint:clipRect.origin];
25
26    // We could use this instead since it allows a scroll view to coordinate scrolling between multiple clip views.
27    //        [[self superview] scrollClipView:self toPoint:clipRect.origin];
28}
29
30// ----------------------------------------
31// We need to override this so that the superclass doesn't override our new origin point.
32
33-(NSPoint)constrainScrollPoint:(NSPoint)proposedNewOrigin
34{
35    NSRect docRect = [[self documentView] frame];
36    NSRect clipRect = [self bounds];
37    NSPoint newScrollPoint = proposedNewOrigin;
38    float maxX = docRect.size.width - clipRect.size.width;
39    float maxY = docRect.size.height - clipRect.size.height;
40
41    // If the clip view is wider than the doc, we can't scroll horizontally
42    if( docRect.size.width < clipRect.size.width )
43        newScrollPoint.x = roundf( maxX / 2.0 );
44    else
45        newScrollPoint.x = roundf( MAX(0,MIN(newScrollPoint.x,maxX)) );
46
47    // If the clip view is taller than the doc, we can't scroll vertically
48    if( docRect.size.height < clipRect.size.height )
49        newScrollPoint.y = roundf( maxY / 2.0 );
50    else
51        newScrollPoint.y = roundf( MAX(0,MIN(newScrollPoint.y,maxY)) );
52
53    return newScrollPoint;
54}
55
56// ----------------------------------------
57// These two methods get called whenever the subview changes
58
59-(void)viewBoundsChanged:(NSNotification *)notification
60{
61    [super viewBoundsChanged:notification];
62    [self centerDocument];
63}
64
65-(void)viewFrameChanged:(NSNotification *)notification
66{
67    [super viewFrameChanged:notification];
68    [self centerDocument];
69}
70
71// ----------------------------------------
72// These superclass methods change the bounds rect directly without sending any notifications,
73// so we're not sure what other work they silently do for us. As a result, we let them do their
74// work and then swoop in behind to change the bounds origin ourselves. This appears to work
75// just fine without us having to reinvent the methods from scratch.
76
77- (void)setFrame:(NSRect)frameRect
78{
79    [super setFrame:frameRect];
80    [self centerDocument];
81}
82
83- (void)setFrameOrigin:(NSPoint)newOrigin
84{
85    [super setFrameOrigin:newOrigin];
86    [self centerDocument];
87}
88
89- (void)setFrameSize:(NSSize)newSize
90{
91    [super setFrameSize:newSize];
92    [self centerDocument];
93}
94
95- (void)setFrameRotation:(float)angle
96{
97    [super setFrameRotation:angle];
98    [self centerDocument];
99}
100
101@end
102