1/* 2 * TileScrollView.m 3 * 4 * Copyright (C) 1996-2013 by vhf interservice GmbH 5 * Author: Georg Fleischmann 6 * 7 * Created: 1993 8 * Modified: 2013-06-29 (-scaleTo: new - scale to saved scaleFactor) 9 * 2012-08-13 (call of [document -scale:...] with NSSize, scaleFactor, scale -> VFloat) 10 * 2009-09-22 (-magnifyRegion: zero region -> scale to next zoom step, not 5000%) 11 * 12 * This program is free software; you can redistribute it and/or 13 * modify it under the terms of the vhf Public License as 14 * published by vhf interservice GmbH. Among other things, the 15 * License requires that the copyright notices and this notice 16 * be preserved on all copies. 17 * 18 * This program is distributed in the hope that it will be useful, 19 * but WITHOUT ANY WARRANTY; without even the implied warranty of 20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 21 * See the vhf Public License for more details. 22 * 23 * You should have received a copy of the vhf Public License along 24 * with this program; see the file LICENSE. If not, write to vhf. 25 * 26 * vhf interservice GmbH, Im Marxle 3, 72119 Altingen, Germany 27 * eMail: info@vhf.de 28 * http://www.vhf.de 29 */ 30 31#include <AppKit/AppKit.h> 32#include <VHFShared/types.h> 33#include "TileScrollView.h" 34#include "App.h" 35 36@implementation TileScrollView 37 38 39/* instance methods */ 40 41/*+ (NSSize)frameSizeForContentSize:(NSSize)contentSize hasHorizontalScroller:(BOOL)hFlag hasVerticalScroller:(BOOL)vFlag borderType:(NSBorderType)borderType 42{ NSSize size; 43 44 size = [super frameSizeForContentSize:contentSize hasHorizontalScroller:hFlag hasVerticalScroller:vFlag borderType:borderType]; 45 size.height += 28.0; 46 47 return size; 48} 49 50+ (NSSize)contentSizeForFrameSize:(NSSize)frameSize hasHorizontalScroller:(BOOL)hFlag hasVerticalScroller:(BOOL)vFlag borderType:(NSBorderType)borderType 51{ NSSize size; 52 53 size = [super contentSizeForFrameSize:frameSize hasHorizontalScroller:hFlag hasVerticalScroller:vFlag borderType:borderType]; 54 size.height -= 28.0; 55 56 return size; 57}*/ 58 59- initWithFrame:(NSRect)theFrame 60{ 61 [super initWithFrame:theFrame]; 62 63 /* remember the current scale factor */ 64 oldScaleFactor = 1.0; 65 66#ifdef __APPLE__ 67 [self setDrawsBackground:NO]; 68#endif 69 70 return self; 71} 72 73- (void)setDocument:docu 74{ int i; 75 76 document = docu; 77 78 [resPopupListButton setTarget:self]; 79 [resPopupListButton setAction:@selector(changeScale:)]; 80 if ( (i = [resPopupListButton indexOfItemWithTag:100]) >= 0 ) // GNUstep: set to 100% 81 [resPopupListButton selectItemAtIndex:i]; 82} 83 84/* created: 1993-07-04 85 * modified: 2012-08-13 86 * 87 * increment and decrement an entry in the popup menu 88 */ 89- (void)zoomIn:sender 90{ int row; 91 VFloat scaleFactor; 92 NSPoint center; 93 NSRect bRect; 94 95 for (row=0; row<[resPopupListButton numberOfItems]; row++) 96 if (Diff((VFloat)[[resPopupListButton itemAtIndex:row] tag] / 100.0, oldScaleFactor) < 0.001) 97 break; 98 row++; 99 if (row >= [resPopupListButton numberOfItems]) 100 return; 101 [resPopupListButton setTitle:[resPopupListButton itemTitleAtIndex:row]]; 102 103 scaleFactor = [[resPopupListButton itemAtIndex:row] tag] / 100.0; 104 105 bRect = [[self documentView] visibleRect]; 106 center.x = bRect.origin.x+bRect.size.width/2.0; 107 center.y = bRect.origin.y+bRect.size.height/2.0; 108 109 [document scale:NSMakeSize(scaleFactor/oldScaleFactor, scaleFactor/oldScaleFactor) withCenter:center]; 110 oldScaleFactor = scaleFactor; 111 112 [[self window] makeFirstResponder:[document documentView]]; 113} 114 115- (void)zoomOut:sender 116{ int row; 117 VFloat scaleFactor; 118 NSPoint center; 119 NSRect bRect; 120 121 for (row=0; row<[resPopupListButton numberOfItems]; row++) 122 if (Diff((float)[[resPopupListButton itemAtIndex:row] tag] / 100.0, oldScaleFactor) < 0.001) 123 break; 124 row--; 125 if (row < 0) 126 return; 127 128 scaleFactor = (VFloat)[[resPopupListButton itemAtIndex:row] tag] / 100.0; 129 130#if !defined(GNUSTEP_BASE_VERSION) && !defined(__APPLE__) // OpenStep 4.2 131 bRect = [[self documentView] bounds]; 132 if ( ![[self documentView] caching] && 133 Max(bRect.size.width, bRect.size.height)/scaleFactor >= 10000.0) 134 return; 135#endif 136 137 [resPopupListButton setTitle:[resPopupListButton itemTitleAtIndex:row]]; 138 139 bRect = [[self documentView] visibleRect]; 140 center.x = bRect.origin.x+bRect.size.width /2.0; 141 center.y = bRect.origin.y+bRect.size.height/2.0; 142 143 [document scale:NSMakeSize(scaleFactor/oldScaleFactor, scaleFactor/oldScaleFactor) withCenter:center]; 144 oldScaleFactor = scaleFactor; 145 146 [[self window] makeFirstResponder:[document documentView]]; 147} 148 149- (void)magnify:sender 150{ BOOL flag = ([[self documentView] magnify]) ? NO : YES; 151 152 [[self documentView] setMagnify:flag]; 153 if ( flag ) 154 [self setDocumentCursor:[[NSCursor alloc] initWithImage:[NSImage imageNamed:@"cursorMagnify.tiff"] 155 hotSpot:NSMakePoint(7.0, 7.0)]]; 156} 157 158/* modified: 2012-08-13 159 */ 160- (void)magnifyRegion:(NSRect)region 161{ NSPoint center; 162 int row; 163 VFloat scaleFactor, scale = 0.0; 164 NSRect bRect; 165 166 bRect = [[self documentView] visibleRect]; 167 if ( region.size.width && region.size.height ) 168 scale = (bRect.size.width+bRect.size.height) / (region.size.width+region.size.height); 169 center.x = region.origin.x+region.size.width/2.0; 170 center.y = region.origin.y+region.size.height/2.0; 171 172 /* get row of popup relating to current scale */ 173 for (row=0; row<[resPopupListButton numberOfItems]; row++) 174 if (Diff((VFloat)[[resPopupListButton itemAtIndex:row] tag] / 100.0, oldScaleFactor) < 0.001) 175 break; 176 row++; 177 if (row >= [resPopupListButton numberOfItems]) 178 return; 179 180 /* climb up the popup entries and get the new row */ 181 for ( ; scale > 0.0 && row<[resPopupListButton numberOfItems]-1; row++ ) 182 { 183 scaleFactor = [[resPopupListButton itemAtIndex:row] tag] / 100.0; 184 if (scaleFactor / oldScaleFactor >= scale) 185 break; 186 } 187 188 [resPopupListButton setTitle:[resPopupListButton itemTitleAtIndex:row]]; 189 scaleFactor = [[resPopupListButton itemAtIndex:row] tag] / 100.0; 190 191 [document scale:NSMakeSize(scaleFactor/oldScaleFactor, scaleFactor/oldScaleFactor) withCenter:center]; 192 oldScaleFactor = scaleFactor; 193} 194 195- (void)changeScale:sender 196{ NSPoint center; 197 NSRect bRect; 198 VFloat scaleFactor = [[sender selectedItem] tag] / 100.0; 199 200 if (scaleFactor != oldScaleFactor) 201 { 202 203#if !defined(GNUSTEP_BASE_VERSION) && !defined(__APPLE__) // OpenStep 4.2 204 bRect = [[self documentView] bounds]; 205 if ( ![[self documentView] caching] && 206 Max(bRect.size.width, bRect.size.height)/scaleFactor >= 10000.0) 207 return; 208#endif 209 210 //bRect = [[self documentView] bounds]; 211 bRect = [[self documentView] visibleRect]; 212 center.x = bRect.origin.x+bRect.size.width /2.0; 213 center.y = bRect.origin.y+bRect.size.height/2.0; 214 //[window disableDisplay]; 215 [document scale:NSMakeSize(scaleFactor/oldScaleFactor, scaleFactor/oldScaleFactor) withCenter:center]; 216 //[[self window] reenableDisplay]; 217 //[self display]; 218 oldScaleFactor = scaleFactor; 219 } 220 221 [[self window] makeFirstResponder:[document documentView]]; 222} 223 224- (void)scaleTo:(float)scaleFactor 225{ NSPoint center; 226 NSRect bRect; 227 228 if (scaleFactor != oldScaleFactor) 229 { int row = -1; 230 231 for (row=0; row<[resPopupListButton numberOfItems]; row++) 232 if (Diff((float)[[resPopupListButton itemAtIndex:row] tag] / 100.0, scaleFactor) < 0.001) 233 [resPopupListButton selectItemAtIndex:row]; 234 235#if !defined(GNUSTEP_BASE_VERSION) && !defined(__APPLE__) // OpenStep 4.2 236 bRect = [[self documentView] bounds]; 237 if ( ![[self documentView] caching] && 238 Max(bRect.size.width, bRect.size.height)/scaleFactor >= 10000.0) 239 return; 240#endif 241 242 bRect = [[self documentView] visibleRect]; 243 center.x = bRect.origin.x+bRect.size.width /2.0; 244 center.y = bRect.origin.y+bRect.size.height/2.0; 245 [document scale:NSMakeSize(scaleFactor/oldScaleFactor, scaleFactor/oldScaleFactor) withCenter:center]; 246 oldScaleFactor = scaleFactor; 247 } 248 249 [[self window] makeFirstResponder:[document documentView]]; 250} 251 252- (float)scaleFactor 253{ 254 return oldScaleFactor; 255} 256 257- (void)setDocumentView:(NSView *)aView 258{ 259 [super setDocumentView:aView]; 260} 261 262/* 263 * tile gets called whenever the scrollView changes size. Its job is to resize 264 * all of the scrollView's "tiled" views (scrollers, contentView and any other 265 * views we might want to place in the scrollView's bounds). 266 */ 267- (void)tile 268{ static float popupWidth = 0; 269 NSRect scrollerRect, buttonRect; 270 271 /* resize and arrange the scrollers and contentView as usual */ 272 [super tile]; 273 274 /* FIXME: this is a hack to avoid crash with NSRulerView which is released too often 275 * I have no idea where this release comes from! 276 */ 277 { int i; 278 279 for (i=[[self subviews] count]-1; i>=0; i-- ) 280 { id subview = [[self subviews] objectAtIndex:i]; 281 282 if ([subview isKindOfClass:[NSRulerView class]]) 283 { 284 if ([subview retainCount] <= 2) 285 [subview retain]; 286 break; 287 } 288 } 289 } 290 291 if ( !box ) // on Apple we can't tile the scroller, it's too small (box = nil) 292 return; 293 294 if ([box superview] != self) // make sure the popup list is subview of us 295 [self addSubview:box]; 296 297 if (!popupWidth) // get popup width 298 { buttonRect = [box frame]; 299 popupWidth = buttonRect.size.width; 300 } 301 302 scrollerRect = [[self horizontalScroller] frame]; // make the hScroller smaller + stick the popup next to it 303 NSDivideRect(scrollerRect, &buttonRect, &scrollerRect, popupWidth, 2); 304 [[self horizontalScroller] setFrame:scrollerRect]; 305 [box setFrame:buttonRect]; 306} 307 308@end 309