1/* 2 Copyright (c) 1998-2005 Benhur Stein 3 4 This file is part of Paj�. 5 6 Paj� is free software; you can redistribute it and/or modify it under 7 the terms of the GNU Lesser General Public License as published by the 8 Free Software Foundation; either version 2 of the License, or (at your 9 option) any later version. 10 11 Paj� is distributed in the hope that it will be useful, but WITHOUT ANY 12 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 13 FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License 14 for more details. 15 16 You should have received a copy of the GNU Lesser General Public License 17 along with Paj�; if not, write to the Free Software Foundation, Inc., 18 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. 19*/ 20/* 21 * DrawView.m 22 * 23 * a View that draws lines 24 * 25 * 19960115 BS creation 26 * 19960212 BS clean-up 27 */ 28 29#include "DrawView.h" 30#include "STController.h" 31 32#include "../General/NSUserDefaults+Additions.h" 33#include "../General/Macros.h" 34#include "../General/EntityChunk.h" 35 36#include <math.h> 37 38#define DefaultsPrefix NSStringFromClass([self class]) 39#define DefaultsKey(name) [DefaultsPrefix stringByAppendingString:name] 40 41@implementation DrawView 42 43- (void)dealloc 44{ 45 Assign(startTime, nil); 46 Assign(endTime, nil); 47 Assign(backgroundColor, nil); 48 Assign(selectedBackgroundColor, nil); 49 Assign(entityNameAttributes, nil); 50 Assign(cursorTimeFormat, nil); 51 [super dealloc]; 52} 53 54- (NSColor *)backgroundColor 55{ 56 return backgroundColor; 57} 58 59- (NSColor *)selectedBackgroundColor 60{ 61 return selectedBackgroundColor; 62} 63 64- (void)setBackgroundColor:(NSColor *)color 65{ 66 Assign(backgroundColor, color); 67 [[NSUserDefaults standardUserDefaults] 68 setColor:backgroundColor 69 forKey:DefaultsKey(@"BackgroundColor")]; 70 [self setNeedsDisplay:YES]; 71} 72 73- (void)setSelectedBackgroundColor:(NSColor *)color 74{ 75 Assign(selectedBackgroundColor, color); 76 [[NSUserDefaults standardUserDefaults] 77 setColor:selectedBackgroundColor 78 forKey:DefaultsKey(@"SelectedBackgroundColor")]; 79 [self setNeedsDisplay:YES]; 80} 81 82- (void)setFilter:(PajeFilter *)newFilter 83{ 84 filter = newFilter; 85} 86 87- (PajeFilter *)filter 88{ 89 return filter; 90} 91 92- (void)setController:(STController *)c 93{ 94 controller = c; 95} 96 97- (void)hierarchyChanged 98{ 99 Assign(startTime, [filter startTime]); 100 Assign(endTime, [filter endTime]); 101 NSDebugMLLog(@"tim", @"Hier changed. times=[%@ %@]", startTime, endTime); 102 103 if (startTime != nil && endTime != nil) { 104 [self adjustSize]; 105 } 106} 107 108- (void)dataChangedForEntityType:(PajeEntityType *)entityType 109{ 110 [self adjustSize]; 111} 112 113- (void)colorChangedForEntityType:(PajeEntityType *)entityType 114{ 115 [self setNeedsDisplay:YES]; 116} 117 118- (void)orderChangedForContainerType:(PajeContainerType *)containerType 119{ 120 [self adjustSize]; 121} 122 123- (void)awakeFromNib 124{ 125 NSCursor *cursor; 126 NSImage *cursorImage; 127 NSString *cursorPath; 128 129 // initialize instance variables 130 131 pointsPerSecond = [[NSUserDefaults standardUserDefaults] 132 doubleForKey:DefaultsKey(@"PointsPerSecond")]; 133 if (pointsPerSecond == 0) { 134 pointsPerSecond = 10000; 135 } 136 smallEntityWidth = [[NSUserDefaults standardUserDefaults] 137 integerForKey:DefaultsKey(@"SmallEntityWidth")]; 138 hasZoomed = NO; 139 filter = nil; 140 //trackingRectTag = 0; 141 timeUnitDivisor = 1; 142 Assign(cursorTimeFormat, @"%.6f s"); 143 144 [zoomToSelectionButton setEnabled:NO]; 145 146// [[self window] setBackingType:NSBackingStoreNonretained]; 147 148 // get background color from defaults 149 Assign(backgroundColor, [[NSUserDefaults standardUserDefaults] 150 colorForKey:DefaultsKey(@"BackgroundColor")]); 151 if (backgroundColor == nil) { 152 Assign(backgroundColor, [NSColor controlBackgroundColor]); 153 } 154 Assign(selectedBackgroundColor, [[NSUserDefaults standardUserDefaults] 155 colorForKey:DefaultsKey(@"SelectedBackgroundColor")]); 156 if (selectedBackgroundColor == nil) { 157 Assign(selectedBackgroundColor, [NSColor controlLightHighlightColor]); 158 } 159 160 // initialize the cursor 161 cursorPath = [[NSBundle bundleForClass:[self class]] 162 pathForImageResource:@"crosscursor"]; 163 cursorImage = [[NSImage alloc] initWithContentsOfFile:cursorPath]; 164 cursor = [[NSCursor alloc] initWithImage:cursorImage hotSpot:NSMakePoint(7,9)]; 165 [cursorImage release]; 166 if (cursor != nil) { 167 [[self enclosingScrollView] setDocumentCursor:cursor]; 168 [cursor release]; 169 } 170 171#ifdef GNUSTEP 172[[cursorTimeField window] performSelector:@selector(makeKeyAndOrderFront:) withObject:self afterDelay:0]; 173#endif 174 175 // register to receive color drag-and-drops 176 [self registerForDraggedTypes:[NSArray arrayWithObject:NSColorPboardType]]; 177 178// [[EntityTypeInspector alloc] initWithDelegate:self]; 179 180 [[self enclosingScrollView] setHasHorizontalRuler:YES]; 181 [[[self enclosingScrollView] horizontalRulerView] setReservedThicknessForMarkers:0.0]; 182 [[self enclosingScrollView] setBackgroundColor:[self backgroundColor]/*[NSColor whiteColor]*/]; 183 [[self enclosingScrollView] setDrawsBackground:YES/*NO*/]; 184 185 186 entityNameAttributes = [[NSDictionary alloc] initWithObjectsAndKeys: 187 [NSFont systemFontOfSize:8], @"NSFontAttributeName", 188 nil]; 189 190 //TODO: should register as tool 191} 192 193 194 195- (NSRect)adjustScroll:(NSRect)newVisible 196{ 197 if (hasZoomed) { 198 float lastX = TIMEtoX(endTime); 199 float newX = TIMEtoX(oldMiddleTime) - NSWidth(newVisible) / 2; 200 if ( (newX + NSWidth(newVisible)) > lastX ) 201 newX = lastX - NSWidth(newVisible); 202 if (newX < 0) newX = 0; 203 newVisible.origin.x = newX; 204 hasZoomed = NO; 205 Assign(oldMiddleTime, nil); 206 } 207 newVisible.origin.x = (int)newVisible.origin.x; 208 return newVisible; 209} 210 211- (void)windowDidResize:(NSNotification *)aNotification 212{ 213 [self adjustSize]; 214} 215 216- (void)setRulerUnit 217{ 218 NSString *unitName; 219 NSString *unitAbbreviation; 220 NSRulerView *ruler; 221 double logUnitsToPoints; 222 223 if (pointsPerSecond > 300000000) { 224 timeUnitDivisor = 1000000000; 225 unitName = @"nanoseconds"; 226 unitAbbreviation = @"ns"; 227 } else if (pointsPerSecond > 300000) { 228 timeUnitDivisor = 1000000; 229 unitName = @"microseconds"; 230 unitAbbreviation = @"\xb5s"; 231 } else if (pointsPerSecond > 300) { 232 timeUnitDivisor = 1000; 233 unitName = @"milliseconds"; 234 unitAbbreviation = @"ms"; 235 } else if (pointsPerSecond > 0.1) { 236 timeUnitDivisor = 1; 237 unitName = @"seconds"; 238 unitAbbreviation = @"s"; 239 } else if (pointsPerSecond > .001) { 240 timeUnitDivisor = 1.0/3600.0; 241 unitName = @"hours"; 242 unitAbbreviation = @"h"; 243 } else { 244 timeUnitDivisor = 1.0/3600.0/24.0; 245 unitName = @"days"; 246 unitAbbreviation = @"d"; 247 } 248 249 logUnitsToPoints = log10(timeUnitDivisor/pointsPerSecond); 250 int decimals; 251 if (logUnitsToPoints > 0) { 252 decimals = 0; 253 } else { 254 decimals = -logUnitsToPoints + 0.8; 255 } 256 NSString *format; 257 format = [NSString stringWithFormat:@"%%.%df %@", 258 decimals, unitAbbreviation]; 259 Assign(cursorTimeFormat, format); 260 261 ruler = [[self enclosingScrollView] horizontalRulerView]; 262 if (ruler) { 263 // sets ruler scale 264 NSArray *upArray; 265 NSArray *downArray; 266 267 upArray = [NSArray arrayWithObjects: 268 [NSNumber numberWithFloat:5.0], [NSNumber numberWithFloat:2.0], nil]; 269 downArray = [NSArray arrayWithObjects: 270 [NSNumber numberWithFloat:0.5], [NSNumber numberWithFloat:0.2], nil]; 271 [NSRulerView registerUnitWithName:unitName 272 abbreviation:unitAbbreviation 273 unitToPointsConversionFactor:pointsPerSecond/timeUnitDivisor 274 stepUpCycle:upArray 275 stepDownCycle:downArray]; 276 [ruler setMeasurementUnits:unitName]; 277 } 278} 279 280- (void)removeFromSuperview 281{ 282 if (trackingRectTag != 0) { 283 [self removeTrackingRect:trackingRectTag]; 284 trackingRectTag = 0; 285 } 286 [super removeFromSuperview]; 287} 288 289// set tracking rect to visible rectangle of view. should be called any time 290// the view frame is changed 291- (void)resetTrackingRect 292{ 293 if ([self window] == nil) { 294 return; 295 } 296 if (trackingRectTag != 0) { 297 [self removeTrackingRect:trackingRectTag]; 298 } 299 trackingRectTag = [self addTrackingRect:[self visibleRect] 300 owner:self 301 userData:NULL 302 assumeInside:NO]; 303} 304 305- (void)adjustSize 306{ 307 NSRect newBounds; 308 NSScrollView *scrollView = [self enclosingScrollView]; 309 NSRulerView *ruler = [scrollView horizontalRulerView]; 310 id rootInstance = [filter rootInstance]; 311 312 [self setRulerUnit]; 313 314 [self performSelector:@selector(verifyTimes:) 315 withObject:self 316 afterDelay:0.0]; 317 318 if (rootInstance != nil) { 319 newBounds = [[controller rootLayout] rectOfInstance:rootInstance]; 320 321 newBounds.origin.x = TIMEtoX(startTime); 322 newBounds.size.width = TIMEtoX(endTime) - newBounds.origin.x + 3; 323 newBounds.size.height += 1; 324 [self setBoundsOrigin:newBounds.origin]; 325 [self setFrameSize:newBounds.size]; 326 327 [ruler setOriginOffset: 328 TIMEtoX([NSDate dateWithTimeIntervalSinceReferenceDate:0])]; 329 [scrollView tile]; 330 331 [self resetTrackingRect]; 332 } 333} 334 335- (void)verifyTimes:sender 336{ 337 //FIXME: shouldn't be necessary; encapsulator should be more intelligent 338 NSScrollView *scrollView = [self enclosingScrollView]; 339 [filter verifyStartTime:/*startTime*/XtoTIME(NSMinX([self convertRect:[scrollView frame] 340 fromView:scrollView])) 341 endTime:XtoTIME(NSMaxX([self convertRect:[scrollView frame] 342 fromView:scrollView]))]; 343} 344 345- (void)setFrame:(NSRect)frame 346{ 347 [super setFrame:frame]; 348 349 [self resetTrackingRect]; 350} 351 352- (void)setBounds:(NSRect)bounds 353{ 354 [super setBounds:bounds]; 355 356 [self resetTrackingRect]; 357} 358 359- (void)viewWillMoveToWindow:(NSWindow *)newWindow 360{ 361 if ([self window] != nil && trackingRectTag != 0) { 362 [self removeTrackingRect:trackingRectTag]; 363 trackingRectTag = 0; 364 } 365 [super viewWillMoveToWindow:newWindow]; 366 [self resetTrackingRect]; 367} 368 369 370/* 371 * Changing scales 372 * ------------------------------------------------------------------------ 373 */ 374 375- (void)adjustTimeLimits 376{ 377 NSDate *startTimeLimit; 378 NSDate *endTimeLimit; 379 NSDate *traceStartTime; 380 NSDate *traceEndTime; 381 382 traceStartTime = [controller startTime]; 383 traceEndTime = [controller endTime]; 384 if (oldMiddleTime != nil) { 385 startTimeLimit = XtoTIME(TIMEtoX(oldMiddleTime) - 20000); 386 } else { 387 startTimeLimit = traceStartTime; 388 } 389 if ([startTimeLimit isEarlierThanDate:traceStartTime]) { 390 startTimeLimit = traceStartTime; 391 endTimeLimit = XtoTIME(TIMEtoX(startTimeLimit) + 40000); 392 if ([endTimeLimit isLaterThanDate:traceEndTime]) { 393 endTimeLimit = traceEndTime; 394 } 395 } else { 396 endTimeLimit = XtoTIME(TIMEtoX(startTimeLimit) + 40000); 397 if ([endTimeLimit isLaterThanDate:traceEndTime]) { 398 endTimeLimit = traceEndTime; 399 startTimeLimit = XtoTIME(TIMEtoX(endTimeLimit) - 40000); 400 if ([startTimeLimit isEarlierThanDate:traceStartTime]) { 401 startTimeLimit = traceStartTime; 402 } 403 } 404 } 405 Assign(startTime, startTimeLimit); 406 Assign(endTime, endTimeLimit); 407 NSDebugMLLog(@"tim", @"times=[%@ %@] trace=[%@ %@]", startTime, endTime, traceStartTime, traceEndTime); 408} 409 410- (void)setPointsPerSecond:(double)pps 411{ 412 pointsPerSecond = pps; 413 414 [[NSUserDefaults standardUserDefaults] 415 setDouble:pointsPerSecond 416 forKey:DefaultsKey(@"PointsPerSecond")]; 417 hasZoomed = YES; 418 419 [self adjustTimeLimits]; 420 421 [controller changedTimeScale]; 422} 423 424- (void)saveMiddleTime 425{ 426 if (startTime != nil) { 427 Assign(oldMiddleTime, XtoTIME(NSMidX([self visibleRect]))); 428 } 429} 430 431- (void)getPointsPerSecondFrom:(id)source 432{ 433 Assign(oldMiddleTime, XtoTIME(NSMidX([self visibleRect]))); 434 [self setPointsPerSecond:[source doubleValue]]; 435} 436 437- (void)doubleTimeScale:sender 438{ 439 Assign(oldMiddleTime, XtoTIME(NSMidX([self visibleRect]))); 440 [self setPointsPerSecond:pointsPerSecond * 2]; 441//[self performSelector:@selector(getPointsPerSecondFrom:) withObject:[NSNumber numberWithDouble:pointsPerSecond*1.1] afterDelay:0.1]; 442//[self performSelector:@selector(getPointsPerSecondFrom:) withObject:[NSNumber numberWithDouble:pointsPerSecond*1.5] afterDelay:0.2]; 443//[self performSelector:@selector(getPointsPerSecondFrom:) withObject:[NSNumber numberWithDouble:pointsPerSecond*2.0] afterDelay:0.3]; 444} 445 446- (void)halveTimeScale:sender 447{ 448 Assign(oldMiddleTime, XtoTIME(NSMidX([self visibleRect]))); 449 [self setPointsPerSecond:pointsPerSecond / 2]; 450//[self performSelector:@selector(getPointsPerSecondFrom:) withObject:[NSNumber numberWithDouble:pointsPerSecond/1.1] afterDelay:0.1]; 451//[self performSelector:@selector(getPointsPerSecondFrom:) withObject:[NSNumber numberWithDouble:pointsPerSecond/1.5] afterDelay:0.2]; 452//[self performSelector:@selector(getPointsPerSecondFrom:) withObject:[NSNumber numberWithDouble:pointsPerSecond/2.0] afterDelay:0.3]; 453} 454 455- (void)zoomToSelection:sender 456{ 457 NSRect visible; 458 459 if (!selectionExists) { 460 return; 461 } 462 463 visible = [[self superview] frame]; 464 Assign(oldMiddleTime, XtoTIME((TIMEtoX(selectionStartTime) 465 + TIMEtoX(selectionEndTime)) / 2)); 466 [self setPointsPerSecond: NSWidth(visible) 467 / [selectionEndTime timeIntervalSinceDate:selectionStartTime]]; 468} 469 470- (IBAction)getSmallEntityWidthFrom:sender 471{ 472 smallEntityWidth = [sender intValue]; 473 [self setNeedsDisplay:YES]; 474} 475 476- (double)pointsPerSecond 477{ 478 return pointsPerSecond; 479} 480 481- (NSDate *)startTime 482{ 483 return startTime; 484} 485 486- (double)timeToX:(NSDate *)t 487{ 488 if (startTime == nil) return 0; 489 return TIMEtoX(t); 490} 491 492 493/* 494 * Drawing 495 * ------------------------------------------------------------------------ 496 */ 497 498- (BOOL)isFlipped 499// y-axis is inverted (y-coords augment from top to bottom) 500{ 501 return YES; 502} 503 504- (BOOL)isOpaque 505// this view draws every pixel it owns 506{ 507 return YES; 508} 509 510 511- (void)redrawEntities:(NSArray *)entities 512{ 513 id eEnum, entity; 514 515 if (entities != nil) { 516 eEnum = [entities objectEnumerator]; 517 while ((entity = [eEnum nextObject]) != nil) { 518 [self setNeedsDisplayInRect:[self highlightRectForEntity:entity]]; 519 } 520 } 521} 522 523 524- (NSArray *)highlightedEntities 525{ 526 return highlightedEntities; 527} 528 529- (void)setHighlightedEntities:(NSArray *)entities 530// highlights entities, taking care of unhighlighting previous 531{ 532 if (highlightedEntities != nil) { 533 [self redrawEntities:highlightedEntities]; 534 } 535 Assign(highlightedEntities, entities); 536 if (highlightedEntities != nil) { 537 [self redrawEntities:highlightedEntities]; 538 } 539} 540 541- (void)setCursorEntity:(PajeEntity *)entity 542// highlights entity (and related entities), taking care of unhighlighting previous 543{ 544 if (entity == cursorEntity) { 545 return; 546 } 547 Assign(cursorEntity, entity); 548 if (cursorEntity != nil) { 549 NSArray *related = [filter relatedEntitiesForEntity:cursorEntity]; 550 [self setHighlightedEntities:[related arrayByAddingObject:cursorEntity]]; 551 [entityNameField setStringValue:[filter descriptionForEntity:cursorEntity]]; 552 } else { 553 [self setHighlightedEntities:nil]; 554 [entityNameField setStringValue:@""]; 555 } 556} 557 558 559- (void)drawBackgroundInRect:(NSRect)rect 560// draws the background 561{ 562 // draw background 563 [backgroundColor set]; 564 NSRectFill(rect); 565 566 // draw selection background 567 if (selectionExists) { 568 float selectionStart = TIMEtoX(selectionStartTime); 569 float selectionWidth = TIMEtoX(selectionEndTime) - selectionStart; 570 NSRect selectionRect = NSMakeRect(selectionStart, NSMinY(rect), 571 selectionWidth, NSMaxY(rect)); 572#ifdef GNUSTEP 573 // GNUstep can't draw big rects. 574 selectionRect = NSIntersectionRect(selectionRect, cutRect); 575#endif 576 577 [selectedBackgroundColor set]; 578 NSRectFill(selectionRect); 579 } 580} 581 582 583- (void)drawRect:(NSRect)rect 584{ 585 if ([self window] == nil) return; 586 if (startTime == nil) return; 587 588[self verifyTimes:self]; 589rect = NSInsetRect(rect, -10, -10); 590 591#ifdef GNUSTEP 592 // Big rectangles are not drawn by GNUstep. Cut them with cutRect. 593 cutRect = NSInsetRect([self visibleRect], -200, -200); 594#endif 595 596 NS_DURING 597 598 // set blackground 599 [self drawBackgroundInRect:rect]; 600 601 [self drawInstance:[controller rootInstance] 602 ofDescriptor:[controller rootLayout] 603 inRect:rect]; 604 NS_HANDLER 605 NSLog(@"Ignoring exception caught inside drawRect: %@", localException); 606 NS_ENDHANDLER 607 608 //FIXME: put this in controller 609 [EntityChunk emptyLeastRecentlyUsedChunks]; 610} 611 612 613 614 615 616 617/* 618 * Selection control 619 * ------------------------------------------------------------------------ 620 */ 621 622- (BOOL)isPointInSelection:(NSPoint)point 623{ 624 NSDate *pointInTime; 625 626 if (!selectionExists) { 627 return NO; 628 } 629 630 pointInTime = XtoTIME(point.x); 631 return [pointInTime isLaterThanDate:selectionStartTime] 632 && [pointInTime isEarlierThanDate:selectionEndTime]; 633} 634 635- (void)timeSelectionChanged 636{ 637 NSRect redisplayRect; 638 NSDate *newSelectionStartTime; 639 NSDate *newSelectionEndTime; 640 double ox1, ox2, nx1, nx2; 641 642 newSelectionStartTime = [controller selectionStartTime]; 643 newSelectionEndTime = [controller selectionEndTime]; 644 ox1 = TIMEtoX(selectionStartTime); 645 ox2 = TIMEtoX(selectionEndTime); 646 nx1 = TIMEtoX(newSelectionStartTime); 647 nx2 = TIMEtoX(newSelectionEndTime); 648 if (newSelectionStartTime == nil || nx1 >= nx2) { 649 if (selectionExists) { 650 [self setNeedsDisplayFromX:ox1 toX:ox2]; 651 Assign(selectionStartTime, nil); 652 Assign(selectionEndTime, nil); 653 selectionExists = NO; 654 [zoomToSelectionButton setEnabled:NO]; 655 } 656 return; 657 } 658 if (!selectionExists) { 659 Assign(selectionStartTime, newSelectionStartTime); 660 Assign(selectionEndTime, newSelectionEndTime); 661 selectionExists = YES; 662 [zoomToSelectionButton setEnabled:YES]; 663 [self setNeedsDisplayFromX:nx1 toX:nx2]; 664 return; 665 } 666 667 if (ox2 < nx1 || nx2 < ox1) { 668 [self setNeedsDisplayFromX:ox1 toX:ox2]; 669 Assign(selectionStartTime, newSelectionStartTime); 670 Assign(selectionEndTime, newSelectionEndTime); 671 [self setNeedsDisplayFromX:nx1 toX:nx2]; 672 return; 673 } 674 675 redisplayRect = [self visibleRect]; 676 if (nx1 != ox1) { 677 [self setNeedsDisplayFromX:MIN(nx1, ox1) toX:MAX(nx1, ox1)]; 678 } 679 if (nx2 != ox2) { 680 [self setNeedsDisplayFromX:MIN(nx2, ox2) toX:MAX(nx2, ox2)]; 681 } 682 683 Assign(selectionStartTime, newSelectionStartTime); 684 Assign(selectionEndTime, newSelectionEndTime); 685} 686 687- (void)changeSelectionWithPoint:(NSPoint)point 688{ 689 NSDate *cursorTime; 690 NSRect frameRect = [self frame]; 691 692 if (point.x < NSMinX(frameRect)) point.x = NSMinX(frameRect); 693 if (point.x > NSMaxX(frameRect)) point.x = NSMaxX(frameRect); 694 695 cursorTime = XtoTIME(point.x); 696 [self setCursorTime:cursorTime]; 697 698 if ([cursorTime isEarlierThanDate:selectionAnchorTime]) { 699 [controller setSelectionStartTime:cursorTime 700 endTime:selectionAnchorTime]; 701 } else { 702 [controller setSelectionStartTime:selectionAnchorTime 703 endTime:cursorTime]; 704 } 705 706 // scroll point to visible 707 NSRect visibleRect; 708 visibleRect = [self visibleRect]; 709 visibleRect.origin.x = point.x; 710 visibleRect.size.width = 1; 711 [self scrollRectToVisible:visibleRect]; 712} 713 714- (void)setNeedsDisplayFromX:(double)x1 toX:(double)x2 715{ 716 NSRect redisplayRect = [self visibleRect]; 717 redisplayRect.origin.x = x1; 718 redisplayRect.size.width = x2 - x1; 719 redisplayRect = NSIntegralRect(redisplayRect); 720 [self setNeedsDisplayInRect:redisplayRect]; 721} 722 723- (void)selectAll:(id)sender 724{ 725 [controller setSelectionStartTime:startTime 726 endTime:endTime]; 727} 728 729 730 731/* 732 * Dragging control (NSDraggingDestination protocol) 733 * ------------------------------------------------------------------------ 734 */ 735 736- (unsigned int)draggingUpdated:(id <NSDraggingInfo>)sender 737{ 738 NSPoint point = [self convertPoint:[sender draggingLocation] fromView:nil]; 739 740 [self setCursorEntity:[self findEntityAtPoint:point]]; 741#ifdef GNUSTEP 742return NSDragOperationCopy; 743#else 744// if (cursorEntity) 745 return NSDragOperationAll; 746// else 747// return NSDragOperationNone; 748#endif 749} 750 751#ifdef GNUSTEP 752// this shouldn't be needed (should be the default behaviour of NSView) 753- (BOOL) prepareForDragOperation: (id <NSDraggingInfo>)sender 754{ 755 return YES; 756} 757#endif 758- (BOOL)performDragOperation:(id <NSDraggingInfo>)sender 759{ 760 NSColor *draggedColor; 761 NSPoint point = [self convertPoint:[sender draggingLocation] fromView:nil]; 762 763 draggedColor = [NSColor colorFromPasteboard:[sender draggingPasteboard]]; 764 if (draggedColor == nil) { 765 return NO; 766 } 767 768 // if some entity is under the cursor, the color has been dropped over it. 769 if (cursorEntity != nil) { 770 [filter setColor:draggedColor forEntity:cursorEntity]; 771 [self setCursorEntity:nil]; 772 } else { 773 // didn't drop on an entity, change background color 774 if ([self isPointInSelection:point]) { 775 [self setSelectedBackgroundColor:draggedColor]; 776 } else { 777 [self setBackgroundColor:draggedColor]; 778 } 779 } 780 return YES; 781} 782 783 784/* 785 * Printing 786 * ------------------------------------------------------------------------ 787 */ 788 789- (void)endPrologue 790/* 791 * Spit out the custom PostScript defs. 792 */ 793{ 794 [super endPrologue]; 795} 796@end 797