1/* 2 Project: Graphos 3 GRDocView.m 4 5 Copyright (C) 2000-2018 GNUstep Application Project 6 7 Author: Enrico Sersale (original GDraw implementation) 8 Author: Ing. Riccardo Mottola 9 10 This application is free software; you can redistribute it and/or 11 modify it under the terms of the GNU General Public 12 License as published by the Free Software Foundation; either 13 version 2 of the License, or (at your option) any later version. 14 15 This application is distributed in the hope that it will be useful, 16 but WITHOUT ANY WARRANTY; without even the implied warranty of 17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 18 Library General Public License for more details. 19 20 You should have received a copy of the GNU General Public 21 License along with this library; if not, write to the Free 22 Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 23 */ 24 25#import "GRDocView.h" 26#import "Graphos.h" 27#import "GRDrawableObject.h" 28#import "GRFunctions.h" 29#import "GRBezierPath.h" 30#import "GRBox.h" 31#import "GRBoxEditor.h" 32#import "GRText.h" 33#import "GRTextEditor.h" 34#import "GRCircle.h" 35#import "GRCircleEditor.h" 36#import "GRPropsEditor.h" 37#import "GRImage.h" 38 39#define UNDO_ACTION_OBJPROPS @"Change Object Properties" 40#define UNDO_ACTION_CP_SYMMETRIC @"Change Point to Symmetric" 41#define UNDO_ACTION_CP_CUSP @"Change Point to Cusp" 42#define UNDO_ACTION_CP_EXTRACT @"Change Point by Extracting" 43#define UNDO_ACTION_CP_OVERLAP @"Change Point by Overlapping" 44#define UNDO_ACTION_CP_DELETE @"Delete Point" 45 46#define ZOOM_FACTORS 13 47#define STD_ZOOM_INDEX 5 48float zFactors[ZOOM_FACTORS] = {0.25, 0.33, 0.5, 0.66, 0.75, 1, 1.25, 1.5, 2, 2.5, 3, 4, 6}; 49 50 51@implementation GRDocView 52 53 54- (id)initWithFrame:(NSRect)aRect 55{ 56 pageRect = NSMakeRect(0, 0, 695, 942); 57 a4Rect = NSMakeRect(50, 50, 595, 842); 58 zmdRect = NSMakeRect(50, 50, 595, 842); 59 60 self = [super initWithFrame: pageRect]; 61 if(self) 62 { 63 NSImage *img; 64 65 img = [NSImage imageNamed: @"blackarrow.tiff"]; 66 cur = [[NSCursor alloc] initWithImage: img hotSpot: NSMakePoint(0, 0)]; 67 [cur setOnMouseEntered: YES]; 68 [cur setOnMouseExited: YES]; 69 [self addTrackingRect: [self frame] 70 owner: cur userData: NULL 71 assumeInside: YES]; 72 73 objects = [[NSMutableArray alloc] initWithCapacity: 1]; 74 delObjects = [[NSMutableArray alloc] initWithCapacity: 1]; 75 lastObjects = nil; 76 shiftclick = NO; 77 altclick = NO; 78 ctrlclick = NO; 79 zIndex = STD_ZOOM_INDEX; 80 zFactor = zFactors[zIndex]; 81 } 82 return self; 83} 84 85- (void)dealloc 86{ 87 [cur release]; 88 [objects release]; 89 [delObjects release]; 90 [lastObjects release]; 91 [super dealloc]; 92} 93 94- (NSDictionary *) objectDictionary 95{ 96 NSMutableDictionary *objsdict; 97 NSMutableArray *objectOrder; 98 NSString *str = nil; 99 id obj; 100 NSUInteger counter; 101 NSUInteger p = 0; 102 NSUInteger c = 0; 103 NSUInteger t = 0; 104 NSUInteger b = 0; 105 NSUInteger i = 0; 106 107 objsdict = [NSMutableDictionary dictionaryWithCapacity: 1]; 108 objectOrder = [NSMutableArray arrayWithCapacity: [objects count]]; 109 for(counter = 0; counter < [objects count]; counter++) 110 { 111 obj = [objects objectAtIndex: counter]; 112 NSLog(@"class: %@", [obj className]); 113 if([obj isKindOfClass: [GRBezierPath class]]) 114 { 115 str = [NSString stringWithFormat: @"path%lu", (unsigned long)p]; 116 p++; 117 } 118 else if([obj isKindOfClass: [GRImage class]]) 119 { 120 str = [NSString stringWithFormat: @"image%lu", (unsigned long)i]; 121 i++; 122 } 123 else if([obj isKindOfClass: [GRBox class]]) 124 { 125 str = [NSString stringWithFormat: @"box%lu", (unsigned long)b]; 126 b++; 127 } 128 else if([obj isKindOfClass: [GRCircle class]]) 129 { 130 str = [NSString stringWithFormat: @"circle%lu", (unsigned long)c]; 131 c++; 132 } 133 else if([obj isKindOfClass: [GRText class]]) 134 { 135 str = [NSString stringWithFormat: @"text%lu", (unsigned long)t]; 136 t++; 137 } 138 else 139 { 140 [NSException raise:@"Unhandled object type" format:@"%@", [obj class]]; 141 } 142 if (str) 143 { 144 [objectOrder addObject: str]; 145 [objsdict setObject: [obj objectDescription] forKey: str]; 146 } 147 } 148 [objsdict setObject:[NSNumber numberWithFloat:FILE_FORMAT_VERSION] forKey:@"Version"]; 149 [objsdict setObject:objectOrder forKey:@"Order"]; 150 return [NSDictionary dictionaryWithDictionary: objsdict]; 151} 152 153 154- (BOOL)createObjectsFromDictionary:(NSDictionary *)dict 155{ 156 NSArray *keys; 157 NSString *key; 158 NSDictionary *objdict; 159 GRBezierPath *bzPath; 160 GRText *gGRText; 161 GRBox *box; 162 GRCircle *circle; 163 GRImage *image; 164 NSUInteger i; 165 float version; 166 NSNumber *versionNumber; 167 168 if(!dict) 169 return NO; 170 171 [objects removeAllObjects]; 172 version = 0.0; 173 versionNumber = [dict objectForKey:@"Version"]; 174 if (versionNumber) 175 version = [versionNumber floatValue]; 176 NSLog(@"loading file of version: %f", version); 177 178 if (version < 0.3) 179 { 180 /* loading for files without ordering */ 181 182 NSLog(@"Loading old file version, < 0.3"); 183 keys = [dict allKeys]; 184 for(i = 0; i < [keys count]; i++) 185 { 186 key = [keys objectAtIndex: i]; 187 objdict = [dict objectForKey: key]; 188 if(!objdict) 189 return NO; 190 191 if([key rangeOfString: @"path"].length) 192 { 193 bzPath = [[GRBezierPath alloc] initFromData: objdict 194 inView: self zoomFactor: zFactor]; 195 [objects addObject: bzPath]; 196 [bzPath release]; 197 edind = [objects count] -1; 198 } 199 else if([key rangeOfString: @"text"].length) 200 { 201 gGRText = [[GRText alloc] initFromData: objdict 202 inView: self zoomFactor: zFactor]; 203 [objects addObject: gGRText]; 204 [gGRText release]; 205 } 206 else if([key rangeOfString: @"box"].length) 207 { 208 box = [[GRBox alloc] initFromData: objdict 209 inView: self zoomFactor: zFactor]; 210 [objects addObject: box]; 211 [box release]; 212 } 213 else if([key rangeOfString: @"circle"].length) 214 { 215 circle = [[GRCircle alloc] initFromData: objdict 216 inView: self zoomFactor: zFactor]; 217 [circle setCircle:YES]; 218 [objects addObject: circle]; 219 [circle release]; 220 } 221 else if ([key isEqualToString:@"Version"]) 222 { 223 /* skip, already parsed */ 224 } 225 else 226 { 227 [NSException raise:@"Unsupported object in file." format:@"Key: %@", key]; 228 } 229 } 230 } 231 else 232 { 233 /* loading of files with encoded ordering */ 234 NSArray *order; 235 236 NSLog(@"Loading version 0.3 or later, ordered objects"); 237 order = [dict objectForKey:@"Order"]; 238 for(i = 0; i < [order count]; i++) 239 { 240 key = [order objectAtIndex: i]; 241 objdict = [dict objectForKey: key]; 242 if(!objdict) 243 return NO; 244 245 if([key rangeOfString: @"path"].length) 246 { 247 bzPath = [[GRBezierPath alloc] initFromData: objdict 248 inView: self zoomFactor: zFactor]; 249 [objects addObject: bzPath]; 250 [bzPath release]; 251 edind = [objects count] -1; 252 } 253 else if([key rangeOfString: @"text"].length) 254 { 255 gGRText = [[GRText alloc] initFromData: objdict 256 inView: self zoomFactor: zFactor]; 257 [objects addObject: gGRText]; 258 [gGRText release]; 259 } 260 else if([key rangeOfString: @"box"].length) 261 { 262 box = [[GRBox alloc] initFromData: objdict 263 inView: self zoomFactor: zFactor]; 264 [objects addObject: box]; 265 [box release]; 266 } 267 else if([key rangeOfString: @"image"].length) 268 { 269 image = [[GRImage alloc] initFromData: objdict 270 inView: self zoomFactor: zFactor]; 271 [objects addObject: image]; 272 [image release]; 273 } 274 else if([key rangeOfString: @"circle"].length) 275 { 276 circle = [[GRCircle alloc] initFromData: objdict 277 inView: self zoomFactor: zFactor]; 278 /* 0.5 and prior only had circles, not ovals */ 279 if (version < 0.6) 280 [circle setCircle:YES]; 281 [objects addObject: circle]; 282 [circle release]; 283 } 284 else 285 { 286 [NSException raise:@"Unsupported object in file." format:@"Key: %@", key]; 287 } 288 } 289 } 290 [self setNeedsDisplay:YES]; 291 return YES; 292} 293 294- (void)addPath 295{ 296 GRBezierPath *path; 297 GRPropsEditor *objInspector; 298 299 objInspector = [(Graphos *)[[NSApplication sharedApplication] delegate] objectInspector]; 300 301 path = [[GRBezierPath alloc] initInView: self 302 zoomFactor: zFactor 303 withProperties: [objInspector properties]]; 304 305 [objects addObject: path]; 306 [path release]; 307 edind = [objects count] -1; 308 [[NSNotificationCenter defaultCenter] postNotificationName:@"ObjectSelectionChanged" object:self]; 309} 310 311- (void)addTextAtPoint:(NSPoint)p 312{ 313 GRText *gdtxt; 314 NSInteger i; 315 NSUndoManager *uMgr; 316 GRPropsEditor *objInspector; 317 318 objInspector = [(Graphos *)[[NSApplication sharedApplication] delegate] objectInspector]; 319 320 uMgr = [self undoManager]; 321 /* save the method on the undo stack */ 322 [[uMgr prepareWithInvocationTarget: self] restoreLastObjects]; 323 [uMgr setActionName:@"Add Text"]; 324 325 [self saveCurrentObjects]; 326 327 for(i = 0; i < [objects count]; i++) 328 [[[objects objectAtIndex: i] editor] unselect]; 329 330 gdtxt = [[GRText alloc] initInView: self 331 atPoint: p 332 zoomFactor: zFactor 333 withProperties: [objInspector properties] 334 openEditor: YES]; 335 if (gdtxt) 336 [objects addObject: gdtxt]; 337 [[gdtxt editor] select]; 338 [gdtxt release]; 339 [self setNeedsDisplay: YES]; 340 [[NSNotificationCenter defaultCenter] postNotificationName:@"ObjectSelectionChanged" object:self]; 341} 342 343- (void)addBox 344{ 345 GRBox *box; 346 GRPropsEditor *objInspector; 347 348 objInspector = [(Graphos *)[[NSApplication sharedApplication] delegate] objectInspector]; 349 350 box = [[GRBox alloc] initInView: self 351 zoomFactor: zFactor 352 withProperties: [objInspector properties]]; 353 354 [objects addObject: box]; 355 [[box editor] select]; 356 [box release]; 357 [self setNeedsDisplay: YES]; 358 edind = [objects count] -1; 359 [[NSNotificationCenter defaultCenter] postNotificationName:@"ObjectSelectionChanged" object:self]; 360} 361 362- (void)addCircle 363{ 364 GRCircle *circle; 365 GRPropsEditor *objInspector; 366 367 objInspector = [(Graphos *)[[NSApplication sharedApplication] delegate] objectInspector]; 368 369 circle = [[GRCircle alloc] initInView: self 370 zoomFactor: zFactor 371 withProperties: [objInspector properties]]; 372 373 [objects addObject: circle]; 374 [[circle editor] select]; 375 [circle release]; 376 [self setNeedsDisplay: YES]; 377 [[NSNotificationCenter defaultCenter] postNotificationName:@"ObjectSelectionChanged" object:self]; 378 edind = [objects count] -1; 379} 380 381- (NSArray *)duplicateObjects:(NSArray *)objs andMoveTo:(NSPoint)p 382{ 383 id obj, duplObj; 384 NSMutableArray *duplObjs; 385 NSUInteger i; 386 387 duplObjs = [NSMutableArray arrayWithCapacity: 1]; 388 389 for(i = 0; i < [objs count]; i++) 390 { 391 obj = [objs objectAtIndex: i]; 392 duplObj = [obj copy]; 393 [[obj editor] unselect]; 394 [[duplObj editor] selectAsGroup]; 395 [duplObj moveAddingCoordsOfPoint: p]; 396 [objects addObject: duplObj]; 397 [duplObjs addObject: duplObj]; 398 [duplObj release]; 399 } 400 edind = [objects count] -1; 401 [self setNeedsDisplay: YES]; 402 403 return duplObjs; 404} 405 406- (void)updatePrintInfo: (NSPrintInfo *)pi; 407{ 408 float lm, rm; 409 410 if (pi == nil) 411 { 412 NSLog(@"invalid printer information"); 413 return; 414 } 415 lm = [pi leftMargin]; 416 rm = [pi rightMargin]; 417 if (lm <= 0 || rm <= 0 || [pi paperSize].width <= 0 || [pi paperSize].height <= 0) 418 { 419 NSLog(@"invalid margin / paper size information. %f %f %f %f", lm, rm,[pi paperSize].width, [pi paperSize].height); 420 return; 421 } 422 pageRect = NSMakeRect(0,0,[pi paperSize].width, [pi paperSize].height); 423 424 a4Rect = NSMakeRect([pi leftMargin], [pi bottomMargin], 425 pageRect.size.width-([pi leftMargin]+[pi rightMargin]), 426 pageRect.size.height-([pi topMargin]+[pi bottomMargin])); 427 428 zmdRect = a4Rect; 429 zIndex = STD_ZOOM_INDEX; 430 zFactor = zFactors[zIndex]; 431 432 [self setFrame: pageRect]; 433 [self setNeedsDisplay:YES]; 434} 435 436- (void)deleteSelectedObjects 437{ 438 id obj; 439 NSMutableArray *deleted; 440 NSUInteger i, count; 441 442 deleted = [NSMutableArray arrayWithCapacity: 1]; 443 444 count = [objects count]; 445 for(i = 0; i < count; i++) 446 { 447 obj = [objects objectAtIndex: i]; 448 if([[obj editor] isGroupSelected]) 449 { 450 [deleted addObject: obj]; 451 [objects removeObject: obj]; 452 count--; 453 i--; 454 } 455 } 456 if([deleted count]) 457 { 458 [delObjects addObject: deleted]; 459 } 460 [self setNeedsDisplay: YES]; 461} 462 463- (void)startDrawingAtPoint:(NSPoint)p 464{ 465 NSEvent *nextEvent; 466 GRBezierPath *bzpath; 467 id obj; 468 BOOL isNewEditor = YES; 469 NSUInteger i; 470 NSUndoManager *uMgr; 471 472 uMgr = [self undoManager]; 473 /* save the method on the undo stack */ 474 [[uMgr prepareWithInvocationTarget: self] restoreLastObjects]; 475 [uMgr setActionName:@"Create Path"]; 476 477 [self saveCurrentObjects]; 478 479 for(i = 0; i < [objects count]; i++) 480 { 481 obj = [objects objectAtIndex: i]; 482 if([obj isKindOfClass: [GRBezierPath class]]) 483 if(![[obj editor] isDone]) 484 { 485 isNewEditor = NO; 486 edind = i; 487 } 488 } 489 490 if(isNewEditor) 491 for(i = 0; i < [objects count]; i++) 492 { 493 GRObjectEditor *objEdi; 494 495 objEdi = [[objects objectAtIndex: i] editor]; 496 if (![objEdi isSelected]) 497 [objEdi unselect]; 498 } 499 500 nextEvent = [[self window] nextEventMatchingMask: 501 NSLeftMouseUpMask | NSLeftMouseDraggedMask]; 502 [self verifyModifiersOfEvent: nextEvent]; 503 504 if([nextEvent type] != NSLeftMouseDragged) 505 { 506 if(isNewEditor) 507 { 508 [self addPath]; 509 bzpath = [objects objectAtIndex: edind]; 510 [[bzpath editor] selectForEditing]; 511 [bzpath addControlAtPoint: p]; 512 [self setNeedsDisplay: YES]; 513 return; 514 } 515 else 516 { 517 bzpath = [objects objectAtIndex: edind]; 518 [[bzpath editor] selectForEditing]; 519 if(shiftclick) 520 p = pointApplyingCostrainerToPoint(p, [[bzpath lastPoint] center]); 521 [bzpath addLineToPoint: p]; 522 [self setNeedsDisplay: YES]; 523 return; 524 } 525 } 526 else 527 { 528 if(isNewEditor) 529 { 530 [self addPath]; 531 bzpath = [objects objectAtIndex: edind]; 532 [[bzpath editor] selectForEditing]; 533 [bzpath addControlAtPoint: p]; 534 } 535 else 536 { 537 bzpath = [objects objectAtIndex: edind]; 538 [[bzpath editor] selectForEditing]; 539 if(shiftclick) 540 p = pointApplyingCostrainerToPoint(p, [[bzpath lastPoint] center]); 541 [bzpath addControlAtPoint: p]; 542 } 543 [self setNeedsDisplay: YES]; 544 545 do 546 { 547 p = [nextEvent locationInWindow]; 548 p = [self convertPoint: p fromView: nil]; 549 p = GRpointDeZoom(p, zFactor); 550 551 if(shiftclick) 552 p = pointApplyingCostrainerToPoint(p, [[bzpath lastPoint] center]); 553 554 [bzpath addCurveWithBezierHandlePosition: p]; 555 556 [self setNeedsDisplay: YES]; 557 558 nextEvent = [[self window] nextEventMatchingMask: 559 NSLeftMouseUpMask | NSLeftMouseDraggedMask]; 560 [self verifyModifiersOfEvent: nextEvent]; 561 } 562 while([nextEvent type] != NSLeftMouseUp); 563 564 [bzpath confirmNewCurve]; 565 [self setNeedsDisplay: YES]; 566 } 567} 568 569- (void)startBoxAtPoint:(NSPoint)p 570{ 571 NSEvent *nextEvent; 572 GRBox *box; 573 NSUInteger i; 574 NSUndoManager *uMgr; 575 576 uMgr = [self undoManager]; 577 /* save the method on the undo stack */ 578 [[uMgr prepareWithInvocationTarget: self] restoreLastObjects]; 579 [uMgr setActionName:@"Create Box"]; 580 581 [self saveCurrentObjects]; 582 583 for(i = 0; i < [objects count]; i++) 584 { 585 GRObjectEditor *objEdi; 586 587 objEdi = [[objects objectAtIndex: i] editor]; 588 if (![objEdi isSelected]) 589 [objEdi unselect]; 590 } 591 592 nextEvent = [[self window] nextEventMatchingMask: 593 NSLeftMouseUpMask | NSLeftMouseDraggedMask]; 594 [self verifyModifiersOfEvent: nextEvent]; 595 596 if([nextEvent type] != NSLeftMouseDragged) 597 { 598 NSLog(@"is not left mouse dragged"); 599 600 [self addBox]; 601 box = [objects objectAtIndex: edind]; 602 [[box editor] selectForEditing]; 603 [box setStartAtPoint: p]; 604 [self setNeedsDisplay: YES]; 605 return; 606 } 607 else 608 { 609 NSLog(@"is left mouse dragged"); 610 611 [self addBox]; 612 box = [objects objectAtIndex: edind]; 613 [[box editor] selectForEditing]; 614 [box setStartAtPoint: p]; 615 [box setEndAtPoint: p]; 616 [self setNeedsDisplay: YES]; 617 618 [self moveControlPointOfEditor: (GRBezierPathEditor *)[box editor] toPoint: p]; 619 620 [[box editor] unselect]; 621 [[box editor] selectAsGroup]; 622 } 623} 624 625/* this has a lot in common with startBoxAtPoint */ 626- (void)startCircleAtPoint:(NSPoint)p 627{ 628 NSEvent *nextEvent; 629 GRCircle *circle; 630 NSUInteger i; 631 NSUndoManager *uMgr; 632 633 uMgr = [self undoManager]; 634 /* save the method on the undo stack */ 635 [[uMgr prepareWithInvocationTarget: self] restoreLastObjects]; 636 [uMgr setActionName:@"Create Circle"]; 637 638 [self saveCurrentObjects]; 639 640 641 for(i = 0; i < [objects count]; i++) 642 { 643 GRObjectEditor *objEdi; 644 645 objEdi = [[objects objectAtIndex: i] editor]; 646 if (![objEdi isSelected]) 647 [objEdi unselect]; 648 } 649 650 nextEvent = [[self window] nextEventMatchingMask: 651 NSLeftMouseUpMask | NSLeftMouseDraggedMask]; 652 [self verifyModifiersOfEvent: nextEvent]; 653 654 if([nextEvent type] != NSLeftMouseDragged) 655 { 656 NSLog(@"is not left mouse dragged"); 657 658 [self addBox]; 659 circle = [objects objectAtIndex: edind]; 660 [[circle editor] selectForEditing]; 661 [circle setStartAtPoint: p]; 662 [self setNeedsDisplay: YES]; 663 return; 664 } 665 else 666 { 667 NSLog(@"is left mouse dragged"); 668 669 [self addCircle]; 670 circle = [objects objectAtIndex: edind]; 671 [[circle editor] selectForEditing]; 672 [circle setStartAtPoint: p]; 673 [circle setEndAtPoint: p]; 674 [self setNeedsDisplay: YES]; 675 676 677 [self moveControlPointOfEditor: (GRBezierPathEditor *)[circle editor] toPoint: p]; 678 679 [[circle editor] unselect]; 680 [[circle editor] selectAsGroup]; 681 682 } 683} 684 685 686- (void)selectObjectAtPoint:(NSPoint)p 687{ 688 id obj; 689 NSMutableArray *objs; 690 NSUInteger i; 691 GRDrawableObject *hitObj; 692 693 objs = [NSMutableArray arrayWithCapacity: 1]; 694 695 hitObj = nil; 696 for(i = 0; i < [objects count]; i++) 697 { 698 obj = [objects objectAtIndex: i]; 699 700 if ([obj objectHitForSelection: p]) 701 hitObj = obj; 702 else if ([[obj editor] isSelected]) 703 [objs addObject: obj]; 704 } 705 706 /* with shift we add or remove the hit object from the list*/ 707 if (shiftclick && hitObj) 708 { 709 if ([[hitObj editor] isSelected]) 710 { 711 [[hitObj editor] unselect]; 712 } 713 else 714 { 715 [[hitObj editor] select]; 716 [objs addObject:hitObj]; 717 } 718 } 719 else 720 { 721 /* if not shift, if the object is already selected 722 we essentially don't change the selection. 723 else, we select it and deselect the rest */ 724 if ([[hitObj editor] isSelected]) 725 { 726 [objs addObject:hitObj]; 727 } 728 else 729 { 730 NSEnumerator *e; 731 GRDrawableObject *o; 732 733 e = [objs objectEnumerator]; 734 while ((o = [e nextObject])) 735 { 736 [[o editor] unselect]; 737 } 738 [objs removeAllObjects]; 739 if (hitObj) 740 { 741 [[hitObj editor] select]; 742 [objs addObject: hitObj]; 743 } 744 } 745 } 746 [self setNeedsDisplay: YES]; 747 748 if([objs count]) 749 [self moveSelectedObjects: objs startingPoint: p]; 750 [[NSNotificationCenter defaultCenter] postNotificationName:@"ObjectSelectionChanged" object:self]; 751} 752 753- (void)editPathAtPoint:(NSPoint)p 754{ 755 id obj; 756 NSUInteger i; 757 NSUndoManager *uMgr; 758 759 uMgr = [self undoManager]; 760 /* save the method on the undo stack */ 761 [[uMgr prepareWithInvocationTarget: self] restoreLastObjects]; 762 [uMgr setActionName:@"Edit Path"]; 763 764 [self saveCurrentObjectsDeep]; 765 766 /* we look for a path that is selected and process editing 767 we no longer auto-select the object for editing though, nor automatically unselect the editing of the object */ 768 for(i = 0; i < [objects count]; i++) 769 { 770 obj = [objects objectAtIndex: i]; 771 if([obj isKindOfClass: [GRBezierPath class]] && [[obj editor] isSelected]) 772 { 773 if([obj onControlPoint: p]) 774 { 775 [[obj editor] selectForEditing]; 776 [self moveControlPointOfEditor: (GRBezierPathEditor *)[obj editor] toPoint: p]; 777 return; 778 } 779 else 780 { 781 if([self moveBezierHandleOfEditor: (GRBezierPathEditor *)[obj editor] toPoint: p]) 782 return; 783 } 784 } 785 else if ([[obj editor] isSelected] && ([obj isKindOfClass: [GRBox class]] || [obj isKindOfClass: [GRCircle class]])) 786 { 787 if([obj onControlPoint: p]) 788 { 789 [[obj editor] selectForEditing]; 790 [self moveControlPointOfEditor: (GRBezierPathEditor *)[obj editor] toPoint: p]; 791 return; 792 } 793 } 794 else if([obj isKindOfClass: [GRText class]] && [[obj editor] isSelected]) 795 { 796 /* we have no actions for GRText */ 797 } 798 } 799 [self setNeedsDisplay: YES]; 800} 801 802- (void)editTextAtPoint:(NSPoint)p 803{ 804 id obj; 805 NSUInteger i; 806 NSUndoManager *uMgr; 807 808 uMgr = [self undoManager]; 809 /* save the method on the undo stack */ 810 [[uMgr prepareWithInvocationTarget: self] restoreLastObjects]; 811 [uMgr setActionName:@"Edit Text"]; 812 813 [self saveCurrentObjectsDeep]; 814 815 for(i = 0; i < [objects count]; i++) 816 [[[objects objectAtIndex: i] editor] unselect]; 817 818 for(i = 0; i < [objects count]; i++) 819 { 820 obj = [objects objectAtIndex: i]; 821 if([obj isKindOfClass: [GRText class]]) 822 { 823 if([obj objectHitForSelection: p]) 824 { 825 [[obj editor] select]; 826 [self setNeedsDisplay: YES]; 827 [obj edit]; 828 } 829 } 830 } 831 [self setNeedsDisplay: YES]; 832} 833 834/** for keyboard equivalent */ 835- (void)editSelectedText 836{ 837 id obj; 838 NSUInteger i; 839 840 for(i = 0; i < [objects count]; i++) 841 { 842 obj = [objects objectAtIndex: i]; 843 if([obj isKindOfClass: [GRText class]]) 844 { 845 if([obj isSelect]) 846 [obj edit]; 847 } 848 } 849} 850 851- (void)moveSelectedObjects:(NSArray *)objs startingPoint:(NSPoint)startp 852{ 853 NSEvent *nextEvent; 854 NSArray *moveobjs = nil; 855 id obj; 856 NSPoint p, op, diffp; 857 BOOL dupl = NO; 858 NSUInteger i; 859 NSUndoManager *uMgr; 860 861 uMgr = [self undoManager]; 862 /* save the method on the undo stack */ 863 [[uMgr prepareWithInvocationTarget: self] restoreLastObjects]; 864 [uMgr setActionName:@"Move Object"]; 865 866 [self saveCurrentObjectsDeep]; 867 868 nextEvent = [[self window] nextEventMatchingMask: 869 NSLeftMouseUpMask | NSLeftMouseDraggedMask]; 870 if([nextEvent type] == NSLeftMouseDragged) 871 { 872 [self verifyModifiersOfEvent: nextEvent]; 873 op.x = startp.x; 874 op.y = startp.y; 875 876 do 877 { 878 p = [nextEvent locationInWindow]; 879 p = [self convertPoint: p fromView: nil]; 880 p = GRpointDeZoom(p, zFactor); 881 882 if(shiftclick) 883 p = pointApplyingCostrainerToPoint(p, startp); 884 885 if(altclick && !dupl) 886 { 887 moveobjs = [self duplicateObjects: objs andMoveTo: NSMakePoint(0, 0)]; 888 dupl = YES; 889 } 890 else if(!moveobjs) 891 { 892 moveobjs = [NSArray arrayWithArray: objs]; 893 } 894 895 diffp.x = p.x - op.x; 896 diffp.y = p.y - op.y; 897 for(i = 0; i < [moveobjs count]; i++) 898 { 899 obj = [moveobjs objectAtIndex: i]; 900 [obj moveAddingCoordsOfPoint: diffp]; 901 } 902 op.x = p.x; 903 op.y = p.y; 904 [self setNeedsDisplay: YES]; 905 nextEvent = [[self window] nextEventMatchingMask: 906 NSLeftMouseUpMask | NSLeftMouseDraggedMask]; 907 [self verifyModifiersOfEvent: nextEvent]; 908 } 909 while([nextEvent type] != NSLeftMouseUp); 910 911 if(dupl) 912 { 913 diffp.x = p.x - startp.x; 914 diffp.y = p.y - startp.y; 915 } 916 else 917 { 918 diffp.x = startp.x - p.x; 919 diffp.y = startp.y - p.y; 920 } 921 } 922} 923 924 925/* propagates control point editing down to each editor */ 926- (BOOL)moveControlPointOfEditor:(GRPathEditor *)editor toPoint:(NSPoint)pos 927{ 928 NSPoint p; 929 930 p = [editor moveControlAtPoint: pos]; 931 if(p.x == pos.x && p.y == pos.y) 932 return NO; 933 934 [self setNeedsDisplay: YES]; 935 return YES; 936} 937 938- (BOOL)moveBezierHandleOfEditor:(GRBezierPathEditor *)editor toPoint:(NSPoint)pos 939{ 940 NSPoint p; 941 942 p = [editor moveBezierHandleAtPoint: pos]; 943 if(p.x == pos.x && p.y == pos.y) 944 return NO; 945 946 [self setNeedsDisplay: YES]; 947 return YES; 948} 949 950- (void)changePointsOfCurrentPathToSymmetric:(id)sender 951{ 952 NSUndoManager *uMgr; 953 NSUInteger i; 954 NSArray *points; 955 GRBezierPath *path; 956 957 path = nil; 958 for(i = 0; i < [objects count]; i++) 959 { 960 GRDrawableObject *obj; 961 obj = [objects objectAtIndex: i]; 962 963 if([[obj editor] isSelected] && [obj isKindOfClass:[GRBezierPath class]]) 964 { 965 path = (GRBezierPath *)obj; 966 } 967 } 968 969 if (!path) 970 return; 971 972 points = [(GRBezierPathEditor *)[path editor] selectedControlPoints]; 973 if (!points || [points count] == 0) 974 return; 975 976 uMgr = [self undoManager]; 977 /* save the method on the undo stack, but stack actions */ 978 if ([[uMgr undoActionName] isEqualToString: UNDO_ACTION_CP_SYMMETRIC] == NO) 979 { 980 [self saveCurrentObjectsDeep]; 981 [[uMgr prepareWithInvocationTarget: self] restoreLastObjects]; 982 [uMgr setActionName: UNDO_ACTION_CP_SYMMETRIC]; 983 } 984 985 for (i = 0; i < [points count]; i++) 986 { 987 [(GRBezierControlPoint *)[points objectAtIndex: i] setSymmetricalHandles:YES]; 988 } 989 [path remakePath]; 990 [self setNeedsDisplay: YES]; 991} 992 993- (void)changePointsOfCurrentPathToCusp:(id)sender 994{ 995 NSUndoManager *uMgr; 996 NSUInteger i; 997 NSArray *points; 998 GRBezierPath *path; 999 1000 path = nil; 1001 for(i = 0; i < [objects count]; i++) 1002 { 1003 GRDrawableObject *obj; 1004 obj = [objects objectAtIndex: i]; 1005 1006 if([[obj editor] isSelected] && [obj isKindOfClass:[GRBezierPath class]]) 1007 { 1008 path = (GRBezierPath *)obj; 1009 } 1010 } 1011 1012 if (!path) 1013 return; 1014 1015 points = [(GRBezierPathEditor *)[path editor] selectedControlPoints]; 1016 if (!points || [points count] == 0) 1017 return; 1018 1019 uMgr = [self undoManager]; 1020 /* save the method on the undo stack, but stack actions */ 1021 if ([[uMgr undoActionName] isEqualToString: UNDO_ACTION_CP_CUSP] == NO) 1022 { 1023 [self saveCurrentObjectsDeep]; 1024 [[uMgr prepareWithInvocationTarget: self] restoreLastObjects]; 1025 [uMgr setActionName: UNDO_ACTION_CP_CUSP]; 1026 } 1027 1028 for (i = 0; i < [points count]; i++) 1029 { 1030 [(GRBezierControlPoint *)[points objectAtIndex: i] setSymmetricalHandles:NO]; 1031 } 1032 [path remakePath]; 1033 [self setNeedsDisplay:YES]; 1034} 1035 1036- (void)changePointsOfCurrentPathByOverlap:(id)sender 1037{ 1038 NSUndoManager *uMgr; 1039 NSUInteger i; 1040 NSArray *points; 1041 GRBezierPath *path; 1042 1043 path = nil; 1044 for(i = 0; i < [objects count]; i++) 1045 { 1046 GRDrawableObject *obj; 1047 obj = [objects objectAtIndex: i]; 1048 1049 if([[obj editor] isSelected] && [obj isKindOfClass:[GRBezierPath class]]) 1050 { 1051 path = (GRBezierPath *)obj; 1052 } 1053 } 1054 1055 if (!path) 1056 return; 1057 1058 points = [(GRBezierPathEditor *)[path editor] selectedControlPoints]; 1059 if (!points || [points count] == 0) 1060 return; 1061 1062 uMgr = [self undoManager]; 1063 /* save the method on the undo stack, but stack actions */ 1064 if ([[uMgr undoActionName] isEqualToString: UNDO_ACTION_CP_OVERLAP] == NO) 1065 { 1066 [self saveCurrentObjectsDeep]; 1067 [[uMgr prepareWithInvocationTarget: self] restoreLastObjects]; 1068 [uMgr setActionName: UNDO_ACTION_CP_OVERLAP]; 1069 } 1070 1071 for (i = 0; i < [points count]; i++) 1072 { 1073 [(GRBezierControlPoint *)[points objectAtIndex: i] overlapHandles]; 1074 } 1075 [path remakePath]; 1076 [self setNeedsDisplay: YES]; 1077} 1078 1079- (void)changePointsOfCurrentPathByExtract:(id)sender 1080{ 1081 NSUndoManager *uMgr; 1082 NSUInteger i; 1083 NSArray *points; 1084 GRBezierPath *path; 1085 1086 path = nil; 1087 for(i = 0; i < [objects count]; i++) 1088 { 1089 GRDrawableObject *obj; 1090 obj = [objects objectAtIndex: i]; 1091 1092 if([[obj editor] isSelected] && [obj isKindOfClass:[GRBezierPath class]]) 1093 { 1094 path = (GRBezierPath *)obj; 1095 } 1096 } 1097 1098 if (!path) 1099 return; 1100 1101 points = [(GRBezierPathEditor *)[path editor] selectedControlPoints]; 1102 if (!points || [points count] == 0) 1103 return; 1104 1105 uMgr = [self undoManager]; 1106 /* save the method on the undo stack, but stack actions */ 1107 if ([[uMgr undoActionName] isEqualToString: UNDO_ACTION_CP_EXTRACT] == NO) 1108 { 1109 [self saveCurrentObjectsDeep]; 1110 [[uMgr prepareWithInvocationTarget: self] restoreLastObjects]; 1111 [uMgr setActionName: UNDO_ACTION_CP_EXTRACT]; 1112 } 1113 1114 for (i = 0; i < [points count]; i++) 1115 { 1116 [(GRBezierControlPoint *)[points objectAtIndex: i] extractHandles]; 1117 } 1118 [path remakePath]; 1119 [self setNeedsDisplay: YES]; 1120} 1121 1122- (IBAction)deletePointsOfCurrentPath:(id)sender 1123{ 1124 NSUndoManager *uMgr; 1125 NSUInteger i; 1126 NSArray *points; 1127 GRBezierPath *path; 1128 1129 path = nil; 1130 for(i = 0; i < [objects count]; i++) 1131 { 1132 GRDrawableObject *obj; 1133 obj = [objects objectAtIndex: i]; 1134 1135 if([[obj editor] isSelected] && [obj isKindOfClass:[GRBezierPath class]]) 1136 { 1137 path = (GRBezierPath *)obj; 1138 } 1139 } 1140 1141 if (!path) 1142 return; 1143 1144 points = [(GRBezierPathEditor *)[path editor] selectedControlPoints]; 1145 if (!points || [points count] == 0) 1146 return; 1147 1148 uMgr = [self undoManager]; 1149 /* save the method on the undo stack, but stack actions */ 1150 if ([[uMgr undoActionName] isEqualToString: UNDO_ACTION_CP_DELETE] == NO) 1151 { 1152 [self saveCurrentObjectsDeep]; 1153 [[uMgr prepareWithInvocationTarget: self] restoreLastObjects]; 1154 [uMgr setActionName: UNDO_ACTION_CP_DELETE]; 1155 } 1156 1157 for (i = 0; i < [points count]; i++) 1158 { 1159 [path deletePoint: [points objectAtIndex: i]]; 1160 } 1161 [path remakePath]; 1162 [self setNeedsDisplay: YES]; 1163} 1164 1165 1166- (void)subdividePathAtPoint:(NSPoint)p splitIt:(BOOL)split 1167{ 1168 id obj; 1169 NSUInteger i; 1170 1171 1172 for(i = 0; i < [objects count]; i++) 1173 { 1174 obj = [objects objectAtIndex: i]; 1175 if([obj isKindOfClass: [GRBezierPath class]] && [[obj editor] isSelected]) 1176 { 1177 if([obj onPathBorder: p]) 1178 { 1179 [obj subdividePathAtPoint: p splitIt: split]; 1180 break; 1181 } 1182 } 1183 } 1184 [self setNeedsDisplay:YES]; 1185} 1186 1187- (NSDictionary *)selectionProperties 1188{ 1189 NSMutableDictionary *propDict; 1190 NSUInteger i; 1191 NSUInteger selectedObjects; 1192 NSUInteger circleObjNum; 1193 NSUInteger boxObjNum; 1194 NSUInteger bezObjNum; 1195 NSUInteger pathObjNum; 1196 NSUInteger textObjNum; 1197 NSNumber *num; 1198 1199 if(![objects count]) 1200 return nil; 1201 1202 selectedObjects = 0; 1203 circleObjNum = 0; 1204 boxObjNum = 0; 1205 bezObjNum = 0; 1206 pathObjNum = 0; 1207 textObjNum = 0; 1208 propDict = [NSMutableDictionary dictionaryWithCapacity: 1]; 1209 for(i = 0; i < [objects count]; i++) 1210 { 1211 id obj; 1212 obj = [objects objectAtIndex: i]; 1213 1214 if([[obj editor] isSelected]) 1215 { 1216 selectedObjects++; 1217 1218 num = [NSNumber numberWithBool: [obj isStroked]]; 1219 [propDict setObject: num forKey: @"stroked"]; 1220 [propDict setObject: [obj strokeColor] forKey: @"strokecolor"]; 1221 num = [NSNumber numberWithBool: [obj isFilled]]; 1222 [propDict setObject: num forKey: @"filled"]; 1223 [propDict setObject: [obj fillColor] forKey: @"fillcolor"]; 1224 1225 if([obj isKindOfClass: [GRPathObject class]]) 1226 { 1227 pathObjNum++; 1228 num = [NSNumber numberWithFloat: [obj flatness]]; 1229 [propDict setObject: num forKey: @"flatness"]; 1230 num = [NSNumber numberWithInt: [obj lineJoin]]; 1231 [propDict setObject: num forKey: @"linejoin"]; 1232 num = [NSNumber numberWithInt: [obj lineCap]]; 1233 [propDict setObject: num forKey: @"linecap"]; 1234 num = [NSNumber numberWithFloat: [obj miterLimit]]; 1235 [propDict setObject: num forKey: @"miterlimit"]; 1236 num = [NSNumber numberWithFloat: [obj lineWidth]]; 1237 [propDict setObject: num forKey: @"linewidth"]; 1238 if([obj isKindOfClass: [GRCircle class]]) 1239 { 1240 circleObjNum++; 1241 num = [NSNumber numberWithBool: [obj circle]]; 1242 [propDict setObject: num forKey: @"circle"]; 1243 } 1244 else if([obj isKindOfClass: [GRBox class]]) 1245 { 1246 boxObjNum++; 1247 } 1248 else if([obj isKindOfClass: [GRBezierPath class]]) 1249 { 1250 bezObjNum++; 1251 } 1252 } 1253 else if([obj isKindOfClass: [GRText class]]) 1254 { 1255 textObjNum++; 1256 [propDict setObject: @"text" forKey: @"type"]; 1257 } 1258 } 1259 } 1260 1261 if(selectedObjects == 0) 1262 return nil; 1263 1264 if (textObjNum + pathObjNum != selectedObjects) 1265 { 1266 NSLog(@"Internal error: Help we lost some objects."); 1267 } 1268 1269 /* we check if the selection is homogeneous or not 1270 and in case remove the keys that are not common among all objects */ 1271 if (textObjNum > 0 && pathObjNum > 0) 1272 { 1273 [propDict removeObjectForKey: @"flatness"]; 1274 [propDict removeObjectForKey: @"linejoin"]; 1275 [propDict removeObjectForKey: @"linecap"]; 1276 [propDict removeObjectForKey: @"miterlimit"]; 1277 [propDict removeObjectForKey: @"linewidth"]; 1278 } 1279 1280 return propDict; 1281} 1282 1283- (void)setSelectionProperties: (NSDictionary *)properties; 1284{ 1285 NSUndoManager *uMgr; 1286 id obj; 1287 NSUInteger i; 1288 1289 uMgr = [self undoManager]; 1290 /* save the method on the undo stack, but stack actions */ 1291 if ([[uMgr undoActionName] isEqualToString: UNDO_ACTION_OBJPROPS] == NO) 1292 { 1293 [self saveCurrentObjectsDeep]; 1294 [[uMgr prepareWithInvocationTarget: self] restoreLastObjects]; 1295 [uMgr setActionName: UNDO_ACTION_OBJPROPS]; 1296 } 1297 1298 for(i = 0; i < [objects count]; i++) 1299 { 1300 NSNumber *num; 1301 1302 obj = [objects objectAtIndex: i]; 1303 if([[obj editor] isSelected]) 1304 { 1305 NSColor *newColor; 1306 1307 if([obj isKindOfClass: [GRBezierPath class]] || [obj isKindOfClass: [GRBox class]] || [obj isKindOfClass: [GRCircle class]]) 1308 { 1309 num = [properties objectForKey: @"flatness"]; 1310 if (num) 1311 [obj setFlat: [num floatValue]]; 1312 1313 num = [properties objectForKey: @"linejoin"]; 1314 if (num) 1315 [obj setLineJoin: [num intValue]]; 1316 1317 num = [properties objectForKey: @"linecap"]; 1318 if (num) 1319 [obj setLineCap: [num intValue]]; 1320 1321 num = [properties objectForKey: @"miterlimit"]; 1322 if (num) 1323 [obj setMiterLimit: [num floatValue]]; 1324 1325 num = [properties objectForKey: @"linewidth"]; 1326 if (num) 1327 [obj setLineWidth: [num floatValue]]; 1328 } 1329 num = [properties objectForKey: @"stroked"]; 1330 if (num) 1331 [obj setStroked: [num boolValue]]; 1332 1333 newColor = (NSColor *)[properties objectForKey: @"strokecolor"]; 1334 if (newColor) 1335 [obj setStrokeColor: newColor]; 1336 1337 num = [properties objectForKey: @"filled"]; 1338 if (num) 1339 [obj setFilled: [num boolValue]]; 1340 1341 newColor = (NSColor *)[properties objectForKey: @"fillcolor"]; 1342 if (newColor) 1343 [obj setFillColor: newColor]; 1344 } 1345 } 1346 [self setNeedsDisplay: YES]; 1347} 1348 1349- (void)moveSelectedObjectsToFront:(id)sender 1350{ 1351 id obj = nil; 1352 NSUInteger i; 1353 NSUndoManager *uMgr; 1354 1355 uMgr = [self undoManager]; 1356 /* save the method on the undo stack */ 1357 [[uMgr prepareWithInvocationTarget: self] restoreLastObjects]; 1358 [uMgr setActionName:@"Move to front"]; 1359 1360 [self saveCurrentObjectsDeep]; 1361 1362 for(i = 0; i < [objects count]; i++) 1363 { 1364 if([[[objects objectAtIndex: i] editor] isGroupSelected]) 1365 { 1366 obj = [[objects objectAtIndex: i] retain]; 1367 break; 1368 } 1369 } 1370 if(!obj) 1371 return; 1372 1373 for(i = 0; i < [objects count]; i++) 1374 if([objects objectAtIndex: i] != obj) 1375 [[[objects objectAtIndex: i] editor] unselect]; 1376 1377 for(i = 0; i < [objects count]; i++) 1378 { 1379 if((obj == [objects objectAtIndex: i]) && (i + 1 < [objects count])) 1380 { 1381 [objects removeObjectAtIndex: i]; 1382 [objects insertObject: obj atIndex: i + 1]; 1383 break; 1384 } 1385 } 1386 [obj release]; 1387 [self setNeedsDisplay: YES]; 1388} 1389 1390- (void)moveSelectedObjectsToBack:(id)sender 1391{ 1392 id obj = nil; 1393 NSUInteger i; 1394 NSUndoManager *uMgr; 1395 1396 uMgr = [self undoManager]; 1397 /* save the method on the undo stack */ 1398 [[uMgr prepareWithInvocationTarget: self] restoreLastObjects]; 1399 [uMgr setActionName:@"Move to back"]; 1400 1401 [self saveCurrentObjects]; 1402 1403 for(i = 0; i < [objects count]; i++) 1404 { 1405 if([[[objects objectAtIndex: i] editor] isGroupSelected]) 1406 { 1407 obj = [[objects objectAtIndex: i] retain]; 1408 break; 1409 } 1410 } 1411 if(!obj) 1412 return; 1413 1414 for(i = 0; i < [objects count]; i++) 1415 if([objects objectAtIndex: i] != obj) 1416 [[[objects objectAtIndex: i] editor] unselect]; 1417 1418 for(i = 0; i < [objects count]; i++) 1419 { 1420 if((obj == [objects objectAtIndex: i]) && (i > 0)) 1421 { 1422 [objects removeObjectAtIndex: i]; 1423 [objects insertObject: obj atIndex: i - 1]; 1424 break; 1425 } 1426 } 1427 [obj release]; 1428 [self setNeedsDisplay: YES]; 1429} 1430 1431- (void)unselectOtherObjects:(GRDrawableObject *)anObject 1432{ 1433 id obj; 1434 NSUInteger i; 1435 1436 if(shiftclick) 1437 return; 1438 1439 for(i = 0; i < [objects count]; i++) 1440 { 1441 obj = [objects objectAtIndex: i]; 1442 if(obj != anObject) 1443 [[obj editor] unselect]; 1444 } 1445 1446 [self setNeedsDisplay: YES]; 1447} 1448 1449- (void)zoomOnPoint:(NSPoint)p zoomOut:(BOOL)isout 1450{ 1451 NSUInteger i; 1452 1453 i = zIndex; 1454 if(isout) 1455 { 1456 if (i == 0) 1457 return; 1458 i--; 1459 } 1460 else 1461 { 1462 if (i == ZOOM_FACTORS-1) 1463 return; 1464 i++; 1465 } 1466 1467 [self zoomOnPoint:p withFactor:i]; 1468} 1469 1470 1471- (void)zoomOnPoint:(NSPoint)p withFactor:(int)index 1472{ 1473 CGFloat orx, ory, szx, szy; 1474 NSRect vr; 1475 NSPoint pp; 1476 NSUInteger i; 1477 1478 zIndex = index; 1479 zFactor = zFactors[zIndex]; 1480 1481 orx = a4Rect.origin.x * zFactor; 1482 ory = a4Rect.origin.y * zFactor; 1483 szx = a4Rect.size.width * zFactor; 1484 szy = a4Rect.size.height * zFactor; 1485 zmdRect = NSMakeRect(orx, ory, szx, szy); 1486 szx = pageRect.size.width * zFactor; 1487 szy = pageRect.size.height * zFactor; 1488 1489 pp.x = p.x * ([self frame].origin.x + pageRect.size.width) / [self frame].size.width; 1490 pp.y = p.y * ([self frame].origin.y + pageRect.size.height) / [self frame].size.height; 1491 vr = NSMakeRect(pp.x * zFactor - 200, pp.y * zFactor - 200, 400, 400); 1492 [self setFrame: NSMakeRect(0, 0, szx, szy)]; 1493 [self scrollRectToVisible: vr]; 1494 1495 for(i = 0; i < [objects count]; i++) 1496 [[objects objectAtIndex: i] setZoomFactor: zFactor]; 1497 1498 [[self window] display]; 1499} 1500 1501- (IBAction)zoom50:(id)sender 1502{ 1503 NSUInteger i; 1504 NSPoint p; 1505 NSRect visibleRect; 1506 1507 zFactor = 0.5; 1508 1509 i = ZOOM_FACTORS - 1; 1510 while (i > 0 && zFactor < zFactors[i]) 1511 i--; 1512 1513 visibleRect = [self visibleRect]; 1514 p.x = NSMinX(visibleRect) + NSWidth(visibleRect) / 2; 1515 p.y = NSMinY(visibleRect) + NSHeight(visibleRect) / 2; 1516 1517 [self zoomOnPoint:p withFactor:i]; 1518} 1519 1520- (IBAction)zoom100:(id)sender 1521{ 1522 NSUInteger i; 1523 NSPoint p; 1524 NSRect visibleRect; 1525 1526 zFactor = 1; 1527 1528 i = ZOOM_FACTORS - 1; 1529 while (i > 0 && zFactor < zFactors[i]) 1530 i--; 1531 1532 visibleRect = [self visibleRect]; 1533 p.x = NSMinX(visibleRect) + NSWidth(visibleRect) / 2; 1534 p.y = NSMinY(visibleRect) + NSHeight(visibleRect) / 2; 1535 1536 [self zoomOnPoint:p withFactor:i]; 1537} 1538 1539- (IBAction)zoom200:(id)sender 1540{ 1541 NSUInteger i; 1542 NSPoint p; 1543 NSRect visibleRect; 1544 1545 zFactor = 2; 1546 1547 i = ZOOM_FACTORS - 1; 1548 while (i > 0 && zFactor < zFactors[i]) 1549 i--; 1550 1551 visibleRect = [self visibleRect]; 1552 p.x = NSMinX(visibleRect) + NSWidth(visibleRect) / 2; 1553 p.y = NSMinY(visibleRect) + NSHeight(visibleRect) / 2; 1554 1555 [self zoomOnPoint:p withFactor:i]; 1556} 1557 1558- (IBAction)zoomFitPage:(id)sender 1559{ 1560 NSUInteger i; 1561 NSPoint p; 1562 NSRect visibleRect; 1563 NSRect docVRect; 1564 CGFloat fWidth; 1565 CGFloat fHeight; 1566 1567 fWidth = [self frame].size.width / zFactor; 1568 fHeight = [self frame].size.height / zFactor; 1569 docVRect = [(NSClipView*)[self superview] documentVisibleRect]; 1570 i = ZOOM_FACTORS - 1; 1571 while (i > 0 && ((docVRect.size.width < fWidth * zFactors[i]) || (docVRect.size.height < fHeight * zFactors[i]))) 1572 i--; 1573 1574 visibleRect = [self visibleRect]; 1575 p.x = NSMinX(visibleRect) + NSWidth(visibleRect) / 2; 1576 p.y = NSMinY(visibleRect) + NSHeight(visibleRect) / 2; 1577 1578 [self zoomOnPoint:p withFactor:i]; 1579} 1580 1581- (IBAction)zoomFitWidth:(id)sender 1582{ 1583 NSUInteger i; 1584 NSPoint p; 1585 NSRect visibleRect; 1586 NSRect docVRect; 1587 CGFloat fWidth; 1588 1589 fWidth = [self frame].size.width / zFactor; 1590 docVRect = [(NSClipView*)[self superview] documentVisibleRect]; 1591 i = ZOOM_FACTORS - 1; 1592 while (i > 0 && docVRect.size.width < fWidth * zFactors[i]) 1593 i--; 1594 1595 visibleRect = [self visibleRect]; 1596 p.x = NSMinX(visibleRect) + NSWidth(visibleRect) / 2; 1597 p.y = NSMinY(visibleRect) + NSHeight(visibleRect) / 2; 1598 1599 [self zoomOnPoint:p withFactor:i]; 1600} 1601 1602- (void)movePageFromHandPoint:(NSPoint)handpos 1603{ 1604 NSEvent *nextEvent; 1605 NSPoint p, diffp; 1606 NSRect r; 1607 1608 nextEvent = [[self window] nextEventMatchingMask: 1609 NSLeftMouseUpMask | NSLeftMouseDraggedMask]; 1610 if([nextEvent type] == NSLeftMouseDragged) 1611 { 1612 do 1613 { 1614 p = [nextEvent locationInWindow]; 1615 p = [self convertPoint: p fromView: nil]; 1616 p = GRpointDeZoom(p, zFactor); 1617 1618 diffp.x = p.x - handpos.x; 1619 diffp.y = p.y - handpos.y; 1620 r = [self visibleRect]; 1621 r = NSMakeRect(r.origin.x - diffp.x, r.origin.y - diffp.y, 1622 r.size.width, r.size.height); 1623 [self scrollRectToVisible: r]; 1624 nextEvent = [[self window] nextEventMatchingMask: 1625 NSLeftMouseUpMask | NSLeftMouseDraggedMask]; 1626 } 1627 while([nextEvent type] != NSLeftMouseUp); 1628 [[self window] display]; 1629 } 1630} 1631 1632- (void)delete:(id)sender 1633{ 1634 NSUndoManager *uMgr; 1635 1636 uMgr = [self undoManager]; 1637 /* save the method on the undo stack */ 1638 [[uMgr prepareWithInvocationTarget: self] restoreLastObjects]; 1639 [uMgr setActionName:@"Delete"]; 1640 1641 [self saveCurrentObjects]; 1642 1643 [self deleteSelectedObjects]; 1644} 1645 1646- (void)cut:(id)sender 1647{ 1648 NSUndoManager *uMgr; 1649 1650 uMgr = [self undoManager]; 1651 /* save the method on the undo stack */ 1652 [[uMgr prepareWithInvocationTarget: self] restoreLastObjects]; 1653 [uMgr setActionName:@"Cut"]; 1654 1655 [self saveCurrentObjects]; 1656 [self copy: sender]; 1657 [self deleteSelectedObjects]; 1658} 1659 1660- (void)copy:(id)sender 1661{ 1662 NSMutableArray *types; 1663 NSPasteboard *pboard; 1664 GRDrawableObject *dObj; 1665 NSMutableArray *objsdesc; 1666 NSUInteger i; 1667 1668 dObj = nil; 1669 objsdesc = [NSMutableArray arrayWithCapacity: 1]; 1670 for(i = 0; i < [objects count]; i++) 1671 { 1672 dObj = [objects objectAtIndex: i]; 1673 if([[dObj editor] isGroupSelected]) 1674 [objsdesc addObject: [dObj objectDescription]]; 1675 } 1676 1677 if([objsdesc count]) 1678 { 1679 types = [NSMutableArray arrayWithObjects: @"GRObjectPboardType", nil]; 1680 pboard = [NSPasteboard generalPasteboard]; 1681 [pboard declareTypes: types owner: self]; 1682 [pboard setString:[objsdesc description] forType: @"GRObjectPboardType"]; 1683 1684 /* if we have just a single image selected, also add a standard TIFF image */ 1685 if ([objsdesc count] == 1 && [dObj isKindOfClass:[GRImage class]]) 1686 { 1687 GRImage *grImg; 1688 1689 [types addObject:NSTIFFPboardType]; 1690 grImg = (GRImage *)dObj; 1691 [pboard setData:[[grImg image] TIFFRepresentation] forType:NSTIFFPboardType]; 1692 } 1693 } 1694} 1695 1696- (void)paste:(id)sender 1697{ 1698 NSPasteboard *pboard; 1699 NSArray *grTypes; 1700 NSString *imgType; 1701 NSArray *descriptions; 1702 NSDictionary *objdesc; 1703 id obj; 1704 NSString *str; 1705 NSUInteger i; 1706 NSUndoManager *uMgr; 1707 1708 // FIXME we should push the undo stack only if copy is certain to succeed 1709 uMgr = [self undoManager]; 1710 /* save the method on the undo stack */ 1711 [[uMgr prepareWithInvocationTarget: self] restoreLastObjects]; 1712 [uMgr setActionName:@"Paste"]; 1713 1714 [self saveCurrentObjects]; 1715 1716 pboard = [NSPasteboard generalPasteboard]; 1717 grTypes = [NSArray arrayWithObject: @"GRObjectPboardType"]; 1718 imgType = [pboard availableTypeFromArray:[NSArray arrayWithObjects:NSTIFFPboardType, nil]]; 1719 NSLog(@"%@", [pboard types]); 1720 if([[pboard availableTypeFromArray: grTypes] isEqualToString: @"GRObjectPboardType"]) 1721 { 1722 descriptions = [[pboard stringForType: @"GRObjectPboardType"] propertyList]; 1723 1724 for(i = 0; i < [descriptions count]; i++) 1725 { 1726 objdesc = [descriptions objectAtIndex: i]; 1727 str = [objdesc objectForKey: @"type"]; 1728 1729 obj = nil; 1730 if([str isEqualToString: @"path"]) 1731 obj = [GRBezierPath alloc]; 1732 else if([str isEqualToString: @"text"]) 1733 obj = [GRText alloc]; 1734 else if([str isEqualToString: @"box"]) 1735 obj = [GRBox alloc]; 1736 else if([str isEqualToString: @"circle"]) 1737 obj = [GRCircle alloc]; 1738 else if([str isEqualToString: @"image"]) 1739 obj = [GRImage alloc]; 1740 else 1741 NSLog(@"Unknown object to paste"); 1742 if (obj != nil) 1743 { 1744 obj = [obj initFromData: objdesc 1745 inView: self zoomFactor: zFactor]; 1746 [objects addObject: obj]; 1747 [[obj editor] selectAsGroup]; 1748 [obj release]; 1749 [self setNeedsDisplay: YES]; 1750 } 1751 } 1752 } 1753 else if ([imgType isEqualToString:NSTIFFPboardType]) 1754 { 1755 NSImage *tmpNSImage; 1756 GRImage *tmpGRImage; 1757 NSMutableDictionary *properties; 1758 NSString *str; 1759 NSPoint pos; 1760 NSSize size; 1761 1762 tmpNSImage = [[NSImage alloc] initWithData:[pboard dataForType:NSTIFFPboardType]]; 1763 1764 size = [tmpNSImage size]; 1765 pos = NSMakePoint(50, pageRect.size.height-50); 1766 properties = [[NSMutableDictionary alloc] init]; 1767 [properties autorelease]; 1768 str = [NSString stringWithFormat: @"%.3f", pos.x]; 1769 [properties setObject: str forKey: @"posx"]; 1770 str = [NSString stringWithFormat: @"%.3f", pos.y]; 1771 [properties setObject: str forKey: @"posy"]; 1772 1773 str = [NSString stringWithFormat: @"%.3f", size.width]; 1774 [properties setObject: str forKey: @"width"]; 1775 str = [NSString stringWithFormat: @"%.3f", -size.height]; 1776 [properties setObject: str forKey: @"height"]; 1777 1778 tmpGRImage = [[GRImage alloc] initInView: self zoomFactor:zFactor withProperties:properties]; 1779 [tmpGRImage setImage:tmpNSImage]; 1780 [objects addObject:tmpGRImage]; 1781 [tmpGRImage release]; 1782 [tmpNSImage release]; 1783 [self setNeedsDisplay: YES]; 1784 } 1785} 1786 1787/* ----- Undo Methods ----- */ 1788 1789- (NSMutableArray *)deepCopyObjects: (NSMutableArray *)objArray 1790{ 1791 NSMutableArray *copyArray; 1792 NSEnumerator *e; 1793 NSObject *o; 1794 1795 1796 copyArray = [NSMutableArray arrayWithCapacity:[objArray count]]; 1797 1798 e = [objArray objectEnumerator]; 1799 while ((o = [e nextObject])) 1800 { 1801 [copyArray addObject:[[o copy] autorelease]]; 1802 } 1803 1804 return copyArray; 1805} 1806 1807- (void)saveCurrentObjects 1808{ 1809 if (objects != nil) 1810 { 1811 if (lastObjects != nil) 1812 [lastObjects release]; 1813 lastObjects = [[NSMutableArray arrayWithArray:objects] retain]; 1814 } 1815} 1816 1817- (void)saveCurrentObjectsDeep 1818{ 1819 if (objects != nil) 1820 { 1821 if (lastObjects != nil) 1822 [lastObjects release]; 1823 lastObjects = [[self deepCopyObjects: objects] retain]; 1824 } 1825} 1826 1827 1828- (void)restoreLastObjects 1829{ 1830 NSMutableArray *tempObjects; 1831 1832 /* backup the current status */ 1833 tempObjects = [NSMutableArray arrayWithArray:objects]; 1834 [objects release]; 1835 1836 /* re-register for redo */ 1837 [[[self undoManager] prepareWithInvocationTarget: self] restoreLastObjects]; 1838 1839 /* get the last status */ 1840 objects = [lastObjects retain]; 1841 [lastObjects release]; 1842 1843 /* set the last status to the backup */ 1844 lastObjects = [tempObjects retain]; 1845 [self setNeedsDisplay: YES]; 1846} 1847 1848/* ----- Mouse Methods ----- */ 1849 1850- (void)verifyModifiersOfEvent:(NSEvent *)theEvent 1851{ 1852 if([theEvent type] == NSLeftMouseDown 1853 || [theEvent type] == NSLeftMouseDragged) 1854 { 1855 if([theEvent modifierFlags] & NSShiftKeyMask) 1856 shiftclick = YES; 1857 else 1858 shiftclick = NO; 1859 if([theEvent modifierFlags] & NSAlternateKeyMask) 1860 altclick = YES; 1861 else 1862 altclick = NO; 1863 if([theEvent modifierFlags] & NSControlKeyMask) 1864 ctrlclick = YES; 1865 else 1866 ctrlclick = NO; 1867 } 1868 1869 else if([theEvent type] == NSLeftMouseUp) 1870 { 1871 if(!([theEvent modifierFlags] & NSShiftKeyMask)) 1872 shiftclick = NO; 1873 if(!([theEvent modifierFlags] & NSAlternateKeyMask)) 1874 altclick = NO; 1875 if(!([theEvent modifierFlags] & NSControlKeyMask)) 1876 ctrlclick = NO; 1877 } 1878} 1879 1880- (BOOL)shiftclick 1881{ 1882 return shiftclick; 1883} 1884 1885- (BOOL)altclick 1886{ 1887 return altclick; 1888} 1889 1890- (BOOL)ctrlclick 1891{ 1892 return ctrlclick; 1893} 1894 1895- (void)mouseDown:(NSEvent *)theEvent 1896{ 1897 NSPoint p; 1898 NSUInteger count = [theEvent clickCount]; 1899 1900 [self verifyModifiersOfEvent: theEvent]; 1901 1902 p = [theEvent locationInWindow]; 1903 p = [self convertPoint: p fromView: nil]; 1904 p = GRpointDeZoom(p, zFactor); 1905 1906 if(count == 1) 1907 { 1908 switch([[NSApp delegate] currentToolType]) 1909 { 1910 case blackarrowtool: 1911 [self selectObjectAtPoint: p]; 1912 break; 1913 case whitearrowtool: 1914 [self editPathAtPoint: p]; 1915 break; 1916 case beziertool: 1917 [self startDrawingAtPoint: p]; 1918 break; 1919 case texttool: 1920 [self addTextAtPoint: p]; 1921 break; 1922 case circletool: 1923 [self startCircleAtPoint: p]; 1924 break; 1925 case rectangletool: 1926 [self startBoxAtPoint: p]; 1927 break; 1928 case painttool: 1929 1930 break; 1931 case penciltool: 1932 1933 break; 1934 case rotatetool: 1935 1936 break; 1937 case reducetool: 1938 1939 break; 1940 case reflecttool: 1941 1942 break; 1943 case scissorstool: 1944 if(altclick) 1945 [self subdividePathAtPoint: p splitIt: NO]; 1946 else 1947 [self subdividePathAtPoint: p splitIt: YES]; 1948 break; 1949 case handtool: 1950 [self movePageFromHandPoint: p]; 1951 break; 1952 case magnifytool: 1953 if(altclick) 1954 [self zoomOnPoint: p zoomOut: YES]; 1955 else 1956 [self zoomOnPoint: p zoomOut: NO]; 1957 break; 1958 default: 1959 break; 1960 } 1961 } 1962 else 1963 { 1964 if([[NSApp delegate] currentToolType] == blackarrowtool) 1965 [self editTextAtPoint: p]; 1966 } 1967} 1968 1969- (void)mouseUp:(NSEvent *)theEvent 1970{ 1971 [self verifyModifiersOfEvent: theEvent]; 1972} 1973 1974 1975/** respond to key equivalents which are not bound to menu items */ 1976-(BOOL)performKeyEquivalent: (NSEvent*)theEvent 1977{ 1978 NSString *keyStr; 1979 unichar keyCh; 1980 NSRect vRect, hiddRect; 1981 NSPoint vPoint; 1982 CGFloat hiddRx, hiddRy, hiddRw, hiddRh; 1983 1984#ifdef __APPLE__ 1985 /* Apple is definitively broken here and on all versions tested it returns for the arrow key 1986 also a KeyUp event, which it should not, as the Event is specified to be keyDown */ 1987 if ([theEvent type] == NSKeyUp) 1988 return [super performKeyEquivalent:theEvent]; 1989#endif 1990 1991 keyCh = 0x0; 1992 keyStr = [theEvent characters]; 1993 if ([keyStr length] > 0) 1994 keyCh = [keyStr characterAtIndex:0]; 1995 1996 if (keyCh == NSDeleteFunctionKey || keyCh == NSDeleteCharacter) 1997 { 1998 [self delete:self]; 1999 return YES; 2000 } 2001 else if(keyCh == NSPageUpFunctionKey) 2002 { 2003 vRect = [self visibleRect]; 2004 vPoint = vRect.origin; 2005 hiddRx = vPoint.x; 2006 hiddRy = vPoint.y + vRect.size.height; 2007 hiddRw = vRect.size.width; 2008 hiddRh = vRect.size.height; 2009 hiddRect = NSMakeRect(hiddRx, hiddRy, hiddRw, hiddRh); 2010 [self scrollRectToVisible: hiddRect]; 2011 return YES; 2012 } 2013 else if(keyCh == NSPageDownFunctionKey) 2014 { 2015 vRect = [self visibleRect]; 2016 vPoint = vRect.origin; 2017 hiddRx = vPoint.x; 2018 hiddRy = vPoint.y - vRect.size.height; 2019 hiddRw = vRect.size.width; 2020 hiddRh = vRect.size.height; 2021 hiddRect = NSMakeRect(hiddRx, hiddRy, hiddRw, hiddRh); 2022 [self scrollRectToVisible: hiddRect]; 2023 return YES; 2024 } 2025 else if (keyCh == NSLeftArrowFunctionKey) 2026 { 2027 NSLog(@"arrow left"); 2028 return YES; 2029 } 2030 else if (keyCh == NSUpArrowFunctionKey) 2031 { 2032 NSLog(@"arrow up"); 2033 return YES; 2034 } 2035 else if (keyCh == NSRightArrowFunctionKey) 2036 { 2037 NSLog(@"right left"); 2038 return YES; 2039 } 2040 else if (keyCh == NSDownArrowFunctionKey) 2041 { 2042 NSLog(@"down left"); 2043 return YES; 2044 } 2045 else 2046 NSLog(@"keyCh %x", keyCh); 2047 return [super performKeyEquivalent:theEvent]; 2048} 2049 2050- (BOOL)validateMenuItem:(NSMenuItem *)mi 2051{ 2052 NSUInteger i; 2053 NSUInteger selectedPaths; 2054 NSUInteger selectedObjs; 2055 SEL action; 2056 2057 selectedPaths = 0; 2058 selectedObjs = 0; 2059 2060 if ([[[mi menu] title] isEqualToString:@"Zoom"]) 2061 return YES; 2062 2063 for(i = 0; i < [objects count]; i++) 2064 { 2065 GRDrawableObject *obj; 2066 obj = [objects objectAtIndex: i]; 2067 2068 if([[obj editor] isSelected]) 2069 { 2070 selectedObjs++; 2071 if ([obj isKindOfClass:[GRBezierPath class]]) 2072 selectedPaths++; 2073 } 2074 } 2075 2076 action = [mi action]; 2077 if (sel_isEqual(action, @selector(paste:))) 2078 return YES; 2079 2080 if (sel_isEqual(action, @selector(copy:)) || sel_isEqual(action, @selector(cut:)) || sel_isEqual(action, @selector(delete:))) 2081 { 2082 if (selectedObjs) 2083 return YES; 2084 else 2085 return NO; 2086 } 2087 2088 if (sel_isEqual(action, @selector(changePointsOfCurrentPathToSymmetric:))) 2089 { 2090 if ([[NSApp delegate] currentToolType] == whitearrowtool && (selectedPaths == 1)) 2091 { 2092 return YES; 2093 } 2094 else 2095 return NO; 2096 } 2097 2098 if (sel_isEqual(action, @selector(changePointsOfCurrentPathToCusp:))) 2099 { 2100 if ([[NSApp delegate] currentToolType] == whitearrowtool && (selectedPaths == 1)) 2101 { 2102 return YES; 2103 } 2104 else 2105 return NO; 2106 } 2107 2108 if (sel_isEqual(action, @selector(changePointsOfCurrentPathByOverlap:))) 2109 { 2110 if ([[NSApp delegate] currentToolType] == whitearrowtool && (selectedPaths == 1)) 2111 { 2112 return YES; 2113 } 2114 else 2115 return NO; 2116 } 2117 2118 if (sel_isEqual(action, @selector(changePointsOfCurrentPathByExtract:))) 2119 { 2120 if ([[NSApp delegate] currentToolType] == whitearrowtool && (selectedPaths == 1)) 2121 { 2122 return YES; 2123 } 2124 else 2125 return NO; 2126 } 2127 2128 if (sel_isEqual(action, @selector(deletePointsOfCurrentPath:))) 2129 { 2130 if ([[NSApp delegate] currentToolType] == whitearrowtool && (selectedPaths == 1)) 2131 { 2132 return YES; 2133 } 2134 else 2135 return NO; 2136 } 2137 if (sel_isEqual(action, @selector(moveSelectedObjectsToFront:)) || sel_isEqual(action, @selector(moveSelectedObjectsToBack:))) 2138 { 2139 if (selectedObjs) 2140 return YES; 2141 else 2142 return NO; 2143 } 2144 return NO; 2145} 2146 2147/* override the menu for special context menus 2148 2149 While editing a path, display the handle options 2150 */ 2151- (NSMenu *) menuForEvent: (NSEvent*)theEvent 2152{ 2153 if ([[NSApp delegate] currentToolType] == whitearrowtool) 2154 { 2155 NSUInteger i; 2156 NSUInteger selectedPaths; 2157 2158 selectedPaths = 0; 2159 for(i = 0; i < [objects count]; i++) 2160 { 2161 GRDrawableObject *obj; 2162 obj = [objects objectAtIndex: i]; 2163 2164 if([[obj editor] isSelected] && [obj isKindOfClass:[GRBezierPath class]]) 2165 { 2166 selectedPaths++; 2167 } 2168 } 2169 2170 if (selectedPaths == 1) 2171 { 2172 NSMenu *menu; 2173 NSMenuItem *menuItem; 2174 2175 2176 menu = [[NSMenu alloc] initWithTitle: NSLocalizedString(@"Handles", @"")]; 2177 2178 menuItem = [[NSMenuItem alloc] init]; 2179 [menuItem setTitle: NSLocalizedString(@"Delete", @"")]; 2180 [menuItem setTarget: self]; 2181 [menuItem setAction: @selector(deletePointsOfCurrentPath:)]; 2182 [menu addItem: menuItem]; 2183 [menuItem release]; 2184 2185 menuItem = [[NSMenuItem alloc] init]; 2186 [menuItem setTitle: NSLocalizedString(@"Symmetric", @"")]; 2187 [menuItem setTarget: self]; 2188 [menuItem setAction: @selector(changePointsOfCurrentPathToSymmetric:)]; 2189 [menu addItem: menuItem]; 2190 [menuItem release]; 2191 2192 menuItem = [[NSMenuItem alloc] init]; 2193 [menuItem setTitle: NSLocalizedString(@"Cusp", @"")]; 2194 [menu addItem: menuItem]; 2195 [menuItem setTarget: self]; 2196 [menuItem setAction: @selector(changePointsOfCurrentPathToCusp:)]; 2197 [menuItem release]; 2198 2199 menuItem = [[NSMenuItem alloc] init]; 2200 [menuItem setTitle: NSLocalizedString(@"Overlap to Segment", @"")]; 2201 [menu addItem: menuItem]; 2202 [menuItem setTarget: self]; 2203 [menuItem setAction: @selector(changePointsOfCurrentPathByOverlap:)]; 2204 [menuItem release]; 2205 2206 menuItem = [[NSMenuItem alloc] init]; 2207 [menuItem setTitle: NSLocalizedString(@"Extract to Round", @"")]; 2208 [menu addItem: menuItem]; 2209 [menuItem setTarget: self]; 2210 [menuItem setAction: @selector(changePointsOfCurrentPathByExtract:)]; 2211 [menuItem release]; 2212 2213 [menu autorelease]; 2214 return menu; 2215 } 2216 } 2217 2218 return [super menuForEvent: theEvent]; 2219} 2220 2221 2222- (BOOL)acceptsFirstResponder 2223{ 2224 return YES; 2225} 2226 2227- (BOOL)acceptsFirstMouse:(NSEvent *)theEvent 2228{ 2229 return YES; 2230} 2231 2232- (void)drawRect:(NSRect)rect 2233{ 2234 NSUInteger i; 2235 NSRect frameRect; 2236 NSBezierPath *bzp; 2237 2238 frameRect = [self frame]; 2239 2240 [[NSColor whiteColor] set]; 2241 NSRectFill(rect); 2242 2243 if ([[NSGraphicsContext currentContext] isDrawingToScreen]) 2244 { 2245 [[NSColor lightGrayColor] set]; 2246 2247 bzp = [NSBezierPath bezierPath]; 2248 [bzp moveToPoint:NSMakePoint(0, zmdRect.origin.y)]; 2249 [bzp lineToPoint:NSMakePoint(frameRect.size.width, zmdRect.origin.y)]; 2250 [bzp lineToPoint:NSMakePoint(rect.size.width, zmdRect.origin.y)]; 2251 [bzp moveToPoint:NSMakePoint(0, zmdRect.origin.y + zmdRect.size.height)]; 2252 [bzp lineToPoint:NSMakePoint(frameRect.size.width, zmdRect.origin.y + zmdRect.size.height)]; 2253 [bzp moveToPoint:NSMakePoint(zmdRect.origin.x, 0)]; 2254 [bzp lineToPoint:NSMakePoint(zmdRect.origin.x, frameRect.size.height)]; 2255 [bzp moveToPoint:NSMakePoint(zmdRect.origin.x + zmdRect.size.width, 0)]; 2256 [bzp lineToPoint:NSMakePoint(zmdRect.origin.x + zmdRect.size.width, frameRect.size.height)]; 2257 [bzp stroke]; 2258 } 2259 2260 for(i = 0; i < [objects count]; i++) 2261 [(GRDrawableObject *)[objects objectAtIndex: i] draw]; 2262 2263} 2264 2265/* --- overridden for printing --- */ 2266/** 2267 * override for a custom pagination scheme 2268 */ 2269- (BOOL) knowsPageRange: (NSRangePointer) range 2270{ 2271 /* we simply set one page */ 2272 range->location = 1; 2273 range->length = 1; 2274 2275 return YES; 2276} 2277 2278/** 2279 * override for a custom pagination scheme 2280 */ 2281- (NSRect ) rectForPage: (NSInteger) pageNumber 2282{ 2283 NSRect pageRec; 2284 NSSize pageSize; 2285 NSPrintInfo *pi; 2286 2287 pi = [[[NSDocumentController sharedDocumentController] currentDocument] printInfo]; 2288 2289 pageSize = [pi paperSize]; 2290 pageRec = NSMakeRect(0, 0, pageSize.width, pageSize.height); 2291 NSLog(@"page rect: %f, %f, %f, %f", pageRec.origin.x, pageRec.origin.y, pageRec.size.width, pageRec.size.height); 2292 return pageRec; 2293} 2294 2295@end 2296 2297 2298