1// 2// CenteringClipView.m 3// avida/apps/viewer-macos 4// 5// Created by David on 4/22/11. 6// Copyright 2011 Michigan State University. All rights reserved. 7// http://avida.devosoft.org/viewer-macos 8// 9// Redistribution and use in source and binary forms, with or without modification, are permitted provided that the 10// following conditions are met: 11// 12// 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the 13// following disclaimer. 14// 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the 15// following disclaimer in the documentation and/or other materials provided with the distribution. 16// 3. Neither the name of Michigan State University, nor the names of contributors may be used to endorse or promote 17// products derived from this software without specific prior written permission. 18// 19// THIS SOFTWARE IS PROVIDED BY MICHIGAN STATE UNIVERSITY AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, 20// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 21// DISCLAIMED. IN NO EVENT SHALL MICHIGAN STATE UNIVERSITY OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 22// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 23// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 24// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE 25// USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26// 27// Authors: David M. Bryson <david@programerror.com> 28// 29 30#import "CenteringClipView.h" 31 32#include <stdio.h> 33 34@implementation CenteringClipView 35 36- (id) initWithFrame:(NSRect)frame { 37 self = [super initWithFrame:frame]; 38 if (self) { 39 viewPoint = NSMakePoint(0, 0); 40 hasHScroll = NO; 41 hasVScroll = NO; 42 adjustingScrollers = NO; 43 [self setAutoresizesSubviews:NO]; 44 } 45 return self; 46} 47 48 49- (void) centerView { 50 NSRect docRect = [[self documentView] frame]; 51 NSRect clipRect = [self bounds]; 52 53 // Center the clipping rect origin x 54 if (docRect.size.width < clipRect.size.width) { 55 clipRect.origin.x = roundf((docRect.size.width - clipRect.size.width) / 2.0); 56 } else { 57 clipRect.origin.x = roundf(viewPoint.x * docRect.size.width - (clipRect.size.width / 2.0)); 58 } 59 60 // Center the clipping rect origin y 61 if (docRect.size.height < clipRect.size.height) { 62 clipRect.origin.y = roundf((docRect.size.height - clipRect.size.height) / 2.0); 63 } else { 64 clipRect.origin.y = roundf(viewPoint.y * docRect.size.width - (clipRect.size.height / 2.0)); 65 } 66 67// printf("-----centerView-----\n"); 68// printf("doc : %f x %f @ %f, %f\n", docRect.size.width, docRect.size.height, docRect.origin.x, docRect.origin.y); 69// printf("clip: %f x %f @ %f, %f\n", clipRect.size.width, clipRect.size.height, clipRect.origin.x, clipRect.origin.y); 70 71 // Scroll the document to the selected center point 72 NSScrollView* scrollView = (NSScrollView*)[self superview]; 73 [self scrollToPoint:[self constrainScrollPoint:clipRect.origin]]; 74 [scrollView reflectScrolledClipView:self]; 75 76 77 if (!adjustingScrollers) { 78 BOOL hScroller = NO; 79 BOOL vScroller = NO; 80 81 // Determine scroll view frame dimensions (without scrollers) 82// const CGFloat scrollerWidth = ([scrollView scrollerStyle] == NSScrollerStyleLegacy) ? [NSScroller scrollerWidth] : 0.0f; 83 const CGFloat scrollerWidth = [NSScroller scrollerWidth]; 84 NSRect frameRect = [super frame]; 85 CGFloat frameWidth = frameRect.size.width; 86 CGFloat frameHeight = frameRect.size.height; 87 if (hasVScroll) frameWidth += scrollerWidth; 88 if (hasHScroll) frameHeight += scrollerWidth; 89 90 // Determine needed scrollers 91 if (docRect.size.width <= frameWidth && docRect.size.height <= frameHeight) { 92 hScroller = NO; 93 vScroller = NO; 94 } else if (docRect.size.width > frameWidth && docRect.size.height <= (frameHeight - scrollerWidth)) { 95 hScroller = YES; 96 vScroller = NO; 97 } else if (docRect.size.height > frameHeight && docRect.size.width <= (frameWidth - scrollerWidth)) { 98 hScroller = NO; 99 vScroller = YES; 100 } else { 101 hScroller = YES; 102 vScroller = YES; 103 } 104 105 // Adjust horizontal scroller visibility 106 if (hScroller != hasHScroll) { 107 hasHScroll = !hasHScroll; 108 adjustingScrollers = YES; 109 NSScroller* horizontalScroller = [scrollView horizontalScroller]; 110 [horizontalScroller setKnobProportion:1.0f]; 111 [horizontalScroller setDoubleValue:0.0]; 112 [scrollView setHasHorizontalScroller:hasHScroll]; 113 adjustingScrollers = NO; 114 } 115 116 // Adjust vertical scroller visibility 117 if (vScroller != hasVScroll) { 118 hasVScroll = !hasVScroll; 119 adjustingScrollers = YES; 120 NSScroller* verticalScroller = [scrollView verticalScroller]; 121 [verticalScroller setKnobProportion:1.0f]; 122 [verticalScroller setDoubleValue:0.0]; 123 [scrollView setHasVerticalScroller:hasVScroll]; 124 adjustingScrollers = NO; 125 } 126 127// NSLog(@"hscroll %@ %d", [scrollView horizontalScroller], [[scrollView horizontalScroller] isHidden]); 128// NSLog(@"vscroll %@ %d", [scrollView verticalScroller], [[scrollView verticalScroller] isHidden]); 129 130// [scrollView flashScrollers]; 131 } 132} 133 134 135// NSClipView Method Overrides 136 137- (NSPoint) constrainScrollPoint:(NSPoint)proposedNewOrigin { 138 NSRect docRect = [[self documentView] frame]; 139 NSRect clipRect = [self bounds]; 140 CGFloat maxX = docRect.size.width - clipRect.size.width; 141 CGFloat maxY = docRect.size.height - clipRect.size.height; 142 143// printf("-----constrainScrollPoint-----\n"); 144// printf("prop: %f, %f\n", proposedNewOrigin.x, proposedNewOrigin.y); 145// printf("doc : %f x %f @ %f, %f\n", docRect.size.width, docRect.size.height, docRect.origin.x, docRect.origin.y); 146// printf("clip: %f x %f @ %f, %f\n", clipRect.size.width, clipRect.size.height, clipRect.origin.x, clipRect.origin.y); 147 148 clipRect.origin = proposedNewOrigin; 149 150 if (docRect.size.width < clipRect.size.width) { 151 clipRect.origin.x = roundf(maxX / 2.0); 152 } else { 153 clipRect.origin.x = roundf(MAX(0, MIN(clipRect.origin.x, maxX))); 154 } 155 156 if (docRect.size.height < clipRect.size.height) { 157 clipRect.origin.y = roundf(maxY / 2.0); 158 } else { 159 clipRect.origin.y = roundf(MAX(0, MIN(clipRect.origin.y, maxY))); 160 } 161 162 viewPoint.x = NSMidX(clipRect) / docRect.size.width; 163 viewPoint.y = NSMidY(clipRect) / docRect.size.height; 164 165// printf("orig: %f, %f\n", clipRect.origin.x, clipRect.origin.y); 166 return clipRect.origin; 167} 168 169 170- (BOOL) copiesOnScroll 171{ 172 NSRect docRect = [[self documentView] frame]; 173 NSRect clipRect = [self bounds]; 174 175 return (roundf(docRect.size.width - clipRect.size.width) >= 0) && (roundf(docRect.size.height - clipRect.size.height) >= 0); 176} 177 178 179- (void) viewBoundsChanged:(NSNotification*)notification { 180 [super viewBoundsChanged:notification]; 181 [self centerView]; 182} 183 184- (void) viewFrameChanged:(NSNotification*)notification { 185 [super viewBoundsChanged:notification]; 186 [self centerView]; 187} 188 189- (void) setFrame:(NSRect)frameRect { 190 [super setFrame:frameRect]; 191 [self centerView]; 192} 193 194- (void) setFrameOrigin:(NSPoint)newOrigin { 195 [super setFrameOrigin:newOrigin]; 196 [self centerView]; 197} 198 199- (void) setFrameSize:(NSSize)newSize { 200 [super setFrameSize:newSize]; 201 [self centerView]; 202} 203 204- (void) setFrameRotation:(CGFloat)angle { 205 [super setFrameRotation:angle]; 206 [self centerView]; 207} 208 209- (void) setDocumentView:(NSView*)docView { 210 [super setDocumentView:docView]; 211 [self centerView]; 212} 213 214@end 215