1//  PXCanvasController.m
2//  Pixen
3//
4//  Created by Joe Osborn on Sat Sep 13 2003.
5//  Copyright (c) 2003 Open Sword Group. All rights reserved.
6//
7
8#import "PXCanvasController.h"
9#import "PXCanvas.h"
10#import "PXCanvasView.h"
11#import "PXImage.h"
12#import "PXImageSizePrompter.h"
13#import "PXCanvasResizePrompter.h"
14#import "PXGridSettingsPrompter.h"
15#import "PXTool.h"
16#import "PXToolPaletteController.h"
17#import "PXInfoPanelController.h"
18#import "PXBackgroundController.h"
19#import "PXPreviewController.h"
20#import "PXLayerController.h"
21#import "PXGrid.h"
22#import "PXColorPaletteController.h"
23#import "PXScaleController.h"
24#import "PXDocument.h"
25#import "PXPanelManager.h"
26
27//Taken from a man calling himself "BROCK BRANDENBERG" who is here to save the day.
28#import "SBCenteringClipView.h"
29
30//Taken from a man calling himself "M. Uli Kusterer", who is totally not saving the day adequately (but we love him anyway).
31#import "UKFeedbackProvider.h"
32
33#ifndef __COCOA__
34#include "math.h"
35#import "NSArray_DeepMutableCopy.h"
36#endif
37
38@implementation PXCanvasController
39
40- view
41{
42    return view;
43}
44
45- init
46{
47	[super initWithWindowNibName:@"PXDocument"];
48	prompter = [[PXImageSizePrompter alloc] init];
49	resizePrompter = [[PXCanvasResizePrompter alloc] init];
50	previewController = [PXPreviewController sharedPreviewController];
51	backgroundController = [[PXBackgroundController alloc] init];
52	scaleController = [[PXScaleController alloc] init];
53	[backgroundController setDelegate:self];
54	[[NSNotificationCenter defaultCenter] addObserver:self
55					      selector:@selector(canvasSizeDidChange:)
56					      name:PXCanvasSizeChangedNotificationName
57					      object:nil];
58
59	return self;
60}
61
62- (void)awakeFromNib
63{
64	toolbar = [[NSToolbar alloc] initWithIdentifier:@"PXDocumentToolbar"];
65	[toolbar setDelegate:self];
66	[toolbar setAllowsUserCustomization:YES];
67	[toolbar setAutosavesConfiguration:YES];
68#ifndef __COCOA__
69	[zoomPercentageBox setEditable: YES];
70	[zoomPercentageBox setEnabled:YES];
71	[zoomPercentageBox setUsesDataSource:NO];
72	[zoomPercentageBox setNumberOfVisibleItems:10];
73	[zoomPercentageBox setCompletes:NO];
74#endif
75
76	[[self window] setToolbar:toolbar];
77	[[self window] setAcceptsMouseMovedEvents:YES];
78}
79
80- (void)dealloc
81{
82	[[NSNotificationCenter defaultCenter] removeObserver:self];
83	if([[backgroundController backgroundPanel] isVisible])
84	  {
85	    [[backgroundController backgroundPanel] performClose:self];
86	  }
87	[backgroundController release];
88	if([[prompter window] isVisible])
89	  {
90	    [prompter close];
91	  }
92	[prompter release];
93	[resizePrompter release];
94	[layerController release];
95	[toolbar release];
96	[super dealloc];
97}
98
99- (IBAction)increaseOpacity:sender
100{
101	id switcher = [[PXToolPaletteController sharedToolPaletteController] leftSwitcher];
102	[switcher setColor:[[switcher color] colorWithAlphaComponent:[[switcher color] alphaComponent] + 0.1f]];
103}
104
105- (IBAction)decreaseOpacity:sender
106{
107	id switcher = [[PXToolPaletteController sharedToolPaletteController] leftSwitcher];
108	[switcher setColor:[[switcher color] colorWithAlphaComponent:[[switcher color] alphaComponent] - 0.1f]];
109}
110
111- (IBAction)duplicateDocument:sender
112{
113	id newDocument = [[NSDocumentController sharedDocumentController] makeUntitledDocumentOfType:@"Pixen Image"];
114	id newCanvas = [canvas copy];
115	[newDocument setValue:newCanvas forKey:@"canvas"];
116	[newDocument makeWindowControllers];
117	[[NSDocumentController sharedDocumentController] addDocument:newDocument];
118}
119
120- (NSToolbarItem *)toolbar:(NSToolbar *)toolbar
121     itemForItemIdentifier:(NSString *)itemIdentifier
122 willBeInsertedIntoToolbar:(BOOL)flag
123{
124  NSToolbarItem *item = [[[NSToolbarItem alloc] initWithItemIdentifier:itemIdentifier] autorelease];
125
126  if ([itemIdentifier isEqualToString:@"PXBackgroundConfigurator"])
127    {
128      [item setLabel:NSLocalizedString(@"BACKGROUND_LABEL", @"Background Label")];
129      [item setPaletteLabel:[item label]];
130      [item setToolTip:NSLocalizedString(@"BACKGROUND_TOOLTIP", @"Background Tooltip")];
131      [item setTarget:self];
132      [item setAction:@selector(showBackgroundInfo:)];
133      [item setImage:[NSImage imageNamed:@"bgconf"]];
134    }
135  else if ([itemIdentifier isEqualToString:@"PXLayerDrawer"])
136    {
137      [item setLabel:NSLocalizedString(@"LAYERS_LABEL", @"Layers Label")];
138      [item setPaletteLabel:[item label]];
139      [item setToolTip:NSLocalizedString(@"LAYERS_TOOLTIP", @"Layers Tooltip")];
140      [item setTarget:self];
141      [item setAction:@selector(toggleLayersDrawer:)];
142      [item setImage:[NSImage imageNamed:@"layerdrawer"]];
143    }
144  else if ([itemIdentifier isEqualToString:@"PXPreview"])
145    {
146      [item setLabel:NSLocalizedString(@"PREVIEW_LABEL", @"Preview Label")];
147      [item setPaletteLabel:[item label]];
148      [item setToolTip:NSLocalizedString(@"PREVIEW_TOOLTIP", @"Preview Tooltip")];
149      [item setTarget:self];
150      [item setAction:@selector(togglePreviewWindow:)];
151      [item setImage:[NSImage imageNamed:@"preview"]];
152    }
153  else if ([itemIdentifier isEqualToString:@"PXToolProperties"])
154    {
155      [item setLabel:NSLocalizedString(@"TOOL_PROPERTIES_LABEL", @"Tool Properties Label")];
156      [item setPaletteLabel:[item label]];
157      [item setToolTip:NSLocalizedString(@"TOOL_PROPERTIES_TOOLTIP", @"Tool Properties Tooltip")];
158      [item setTarget:self];
159      [item setAction:@selector(toggleLeftToolProperties:)];
160      [item setImage:[NSImage imageNamed:@"toolproperties"]];
161    }
162  else if ([itemIdentifier isEqualToString:@"PXGrid"])
163    {
164      [item setLabel:NSLocalizedString(@"GRID_LABEL", @"Grid Label")];
165      [item setPaletteLabel:[item label]];
166      [item setToolTip:NSLocalizedString(@"GRID_TOOLTIP", @"Grid Tooltip")];
167      [item setTarget:self];
168      [item setAction:@selector(showGridSettingsPrompter:)];
169      [item setImage:[NSImage imageNamed:@"grid"]];
170    }
171  else if ([itemIdentifier isEqualToString:@"PXColorPalette"])
172    {
173      [item setLabel:NSLocalizedString(@"COLOR_PALETTE_LABEL", @"Color Palette Label")];
174      [item setPaletteLabel:[item label]];
175      [item setToolTip:NSLocalizedString(@"COLOR_PALETTE_TOOLTIP", @"Color Palette Tooltip")];
176      [item setTarget:self];
177      [item setAction:@selector(toggleColorPalette:)];
178      [item setImage:[NSImage imageNamed:@"colorpalette"]];
179    }
180  else if ([itemIdentifier isEqualToString:@"PXZoomFit"])
181    {
182
183      [item setLabel:NSLocalizedString(@"ZOOM_FIT_LABEL", @"Zoom Fit Label")];
184      [item setPaletteLabel:[item label]];
185      [item setToolTip:NSLocalizedString(@"ZOOM_FIT_TOOLTIP", @"Zoom Fit Tooltip")];
186      [item setTarget:self];
187      [item setAction:@selector(zoomToFit:)];
188      [item setImage:[NSImage imageNamed:@"zoomfit"]];
189    }
190  else if ([itemIdentifier isEqualToString:@"PXZoom100"])
191    {
192      [item setLabel:NSLocalizedString(@"ZOOM_ACTUAL_LABEL", @"Zoom Actual Label")];
193      [item setPaletteLabel:[item label]];
194      [item setToolTip:NSLocalizedString(@"ZOOM_ACTUAL_TOOLTIP", @"Zoom Actual Tooltip")];
195      [item setTarget:self];
196      [item setAction:@selector(zoomStandard:)];
197      [item setImage:[NSImage imageNamed:@"zoom100"]];
198    }
199  else if ([itemIdentifier isEqualToString:@"PXScale"])
200    {
201      [item setLabel:NSLocalizedString(@"SCALE_LABEL", @"Scale Label")];
202      [item setPaletteLabel:[item label]];
203      [item setToolTip:NSLocalizedString(@"SCALE_TOOLTIP", @"Scale Tooltip")];
204      [item setTarget:self];
205      [item setAction:@selector(scaleCanvas:)];
206      [item setImage:[NSImage imageNamed:@"scale"]];
207    }
208  else if ([itemIdentifier isEqualToString:@"PXResize"])
209    {
210      [item setLabel:NSLocalizedString(@"RESIZE_LABEL", @"Resize Label")];
211      [item setPaletteLabel:[item label]];
212      [item setToolTip:NSLocalizedString(@"RESIZE_TOOLTIP", @"Resize Tooltip")];
213      [item setTarget:self];
214      [item setAction:@selector(resizeCanvas:)];
215      [item setImage:[NSImage imageNamed:@"resize"]];
216    }
217  else if ([itemIdentifier isEqualToString:@"PXFeedback"])
218    {
219      [item setLabel:NSLocalizedString(@"FEEDBACK_LABEL", @"Feedback Label")];
220      [item setPaletteLabel:[item label]];
221      [item setToolTip:NSLocalizedString(@"FEEDBACK_TOOLTIP", @"Feedback Tooltip")];
222      [item setTarget:self];
223      [item setAction:@selector(sendFeedback:)];
224      [item setImage:[NSImage imageNamed:@"feedback"]];
225    }
226  else if ([itemIdentifier isEqualToString:@"PXZoom"])
227    {
228      [item setLabel:NSLocalizedString(@"ZOOM_LABEL", @"Zoom Label")];
229      [item setPaletteLabel:[item label]];
230      [item setToolTip:NSLocalizedString(@"ZOOM_TOOLTIP", @"Zoom Tooltip")];
231      [item setTarget:self];
232      [item setAction:@selector(togglePreviewWindow:)];
233      [item setView:zoomView];
234      [item setMinSize:NSMakeSize(124,NSHeight([zoomView frame]))];
235      [item setMaxSize:NSMakeSize(0,NSHeight([zoomView frame]))];
236    }
237
238  return item;
239}
240
241- (NSArray *) toolbarAllowedItemIdentifiers:(NSToolbar *) toolbar
242{
243  return [NSArray arrayWithObjects:@"PXBackgroundConfigurator", @"PXLayerDrawer",
244		  @"PXPreview", @"PXZoom",
245		  @"PXZoomFit", @"PXZoom100",
246		  @"PXResize", @"PXScale",
247		  @"PXFeedback", @"PXGrid",
248		  @"PXColorPalette",
249		  NSToolbarCustomizeToolbarItemIdentifier,
250		  NSToolbarSpaceItemIdentifier,
251		  NSToolbarSeparatorItemIdentifier,
252		  NSToolbarFlexibleSpaceItemIdentifier,
253		  nil];
254}
255
256- (NSArray *) toolbarDefaultItemIdentifiers:(NSToolbar *) toolbar
257{
258#ifdef __COCOA__
259	return [NSArray arrayWithObjects:@"PXBackgroundConfigurator", @"PXGrid",
260			NSToolbarSeparatorItemIdentifier, @"PXLayerDrawer",
261			@"PXColorPalette", @"PXPreview",
262			NSToolbarFlexibleSpaceItemIdentifier, @"PXFeedback",
263			@"PXZoom",
264			nil];
265#else
266	//Forget Zoom for GNUstep (TDOO)
267	return [NSArray arrayWithObjects:@"PXBackgroundConfigurator", @"PXGrid",
268			NSToolbarSeparatorItemIdentifier, @"PXLayerDrawer",
269			@"PXColorPalette", @"PXPreview",
270			NSToolbarFlexibleSpaceItemIdentifier,
271			@"PXFeedback",
272			nil];
273#endif
274}
275
276- (IBAction) sendFeedback:(id) sender
277{
278  [[PXPanelManager sharedManager] showFeedback:sender];
279}
280
281- (IBAction) toggleLeftToolProperties:(id) sender
282{
283  [[PXPanelManager sharedManager] toggleLeftToolProperties:sender];
284}
285
286- (IBAction)toggleRightToolProperties:(id) sender
287{
288  [[PXPanelManager sharedManager] toggleRightToolProperties:sender];
289}
290
291- (IBAction)toggleColorPalette:(id) sender
292{
293  [[PXPanelManager sharedManager] toggleColorPalette:sender];
294}
295
296- (IBAction)mergeDown:(id) sender
297{
298  [layerController mergeDown];
299}
300
301- (IBAction)promoteSelection:(id) sender
302{
303  [canvas promoteSelection];
304}
305
306- (IBAction)newLayer:(id) sender
307{
308  [layerController addLayer:sender];
309}
310
311- (IBAction)deleteLayer:sender
312{
313    [layerController removeLayer:sender];
314}
315
316- (void)layerSelectionDidChange:(NSNotification *) aNotification
317{
318  [canvas deselect];
319  [canvas activateLayer:[aNotification userInfo]];
320}
321
322- (void)setMainBackground:(id) aBackground
323{
324  [view setMainBackground:aBackground];
325  [canvas setMainBackgroundName:[aBackground name]];
326}
327
328- (void)setAlternateBackground:(id) aBackground
329{
330  [view setAlternateBackground:aBackground];
331  [canvas setAlternateBackgroundName:[aBackground name]];
332}
333
334- (void)backgroundChanged: (NSNotification *) aNotification
335{
336    [view setNeedsDisplayInRect:[view visibleRect]];
337}
338
339- (IBAction)flipLayerHorizontally:(id) sender
340{
341  [[self undoManager] beginUndoGrouping];
342  [self setLayers:[[canvas layers] deepMutableCopy] fromLayers:[canvas layers]];
343  [[self undoManager] setActionName:@"Flip Layer Horizontally"];
344  [[self undoManager] endUndoGrouping];
345  [[canvas activeLayer] flipHorizontally];
346  [canvas changedInRect:NSMakeRect(0, 0, [canvas size].width, [canvas size].height)];
347}
348
349- (IBAction)flipLayerVertically:(id) sender
350{
351  [[self undoManager] beginUndoGrouping];
352  [self setLayers:[[canvas layers] deepMutableCopy] fromLayers:[canvas layers]];
353  [[self undoManager] setActionName:@"Flip Layer Vertically"];
354  [[self undoManager] endUndoGrouping];
355  [[canvas activeLayer] flipVertically];
356  [canvas changedInRect:NSMakeRect(0, 0, [canvas size].width, [canvas size].height)];
357}
358
359- (IBAction)duplicateLayer:(id) sender
360{
361  [layerController duplicateLayer:sender];
362}
363
364- (IBAction)nextLayer:(id) sender
365{
366  [layerController nextLayer:sender];
367}
368
369- (IBAction)previousLayer:(id) sender
370{
371  [layerController previousLayer:sender];
372}
373
374- (void)promptForImageSize
375{
376  [prompter setDelegate:self];
377  [prompter promptInWindow:[self window]];
378}
379
380//Should be  PXCanvas as returned type ?
381- (id) canvas
382{
383    return canvas;
384}
385//Should be PXCanvas as returned type?
386- (void)setCanvas:(id) aCanvas
387{
388  [[NSNotificationCenter defaultCenter] removeObserver:self name:PXCanvasChangedNotificationName object:canvas];
389
390  canvas = aCanvas;
391  if(NSEqualSizes([canvas size], NSZeroSize))
392    {
393      [self promptForImageSize];
394      [prompter setDefaultSize:NSMakeSize(64,64)];
395    }
396
397  [[NSNotificationCenter defaultCenter] addObserver:self
398					selector:@selector(canvasDidChange:)
399					name:PXCanvasChangedNotificationName
400					object:canvas];
401
402  [view setCanvas:aCanvas];
403  [layerController setCanvas:aCanvas];
404  [[PXColorPaletteController sharedPaletteController] reloadDataForCanvas:canvas];
405
406  [[NSNotificationCenter defaultCenter] postNotificationName:PXCanvasLayersChangedNotificationName
407					object:canvas];
408
409  [canvas changedInRect:NSMakeRect(0, 0, [canvas size].width, [canvas size].height)];
410}
411
412- (void)setColor:(NSColor *) aColor
413{
414  [[PXToolPaletteController sharedToolPaletteController] setColor:aColor];
415}
416
417- (void)canvasDidChange:(NSNotification *) aNotification
418{
419  NSRect rect = [[[aNotification userInfo] objectForKey:@"changedRect"] rectValue];
420  [view setNeedsDisplayInCanvasRect:rect];
421}
422
423- (void)canvasSizeDidChange:(NSNotification *) aNotification
424{
425  [view sizeToCanvas];
426  [self updatePreview];
427  //[self zoomToFit:self];
428}
429
430- (void)updatePreview
431{
432  [previewController setCanvas:canvas];
433  [previewController window];
434}
435
436- (NSUndoManager *) undoManager
437{
438  return [[[NSDocumentController sharedDocumentController] currentDocument] undoManager];
439}
440
441- (void)setLayers:layers fromLayers:oldLayers
442{
443    [[[self undoManager] prepareWithInvocationTarget:self] setLayers:oldLayers fromLayers:layers];
444    [canvas setLayers:layers];
445    //beginHack: it is probably bad to rely on the fact that all layers are the same size for now.  However, it is late and I want this to work and this is unlikely to change, so I will ignore this for now. __joe
446    [canvas setSize:[[layers objectAtIndex:0] size]];
447    //endHack
448    [self canvasSizeDidChange:nil];
449}
450
451- (IBAction)resizeCanvas:(id) sender
452{
453    [[self undoManager] beginUndoGrouping];
454    [self setLayers:[[canvas layers] deepMutableCopy] fromLayers:[canvas layers]];
455    [[self undoManager] setActionName:@"Resize Canvas"];
456    [[self undoManager] endUndoGrouping];
457    [resizePrompter setDelegate:self];
458    NSLog(@"resizePrompter %@",resizePrompter);
459    [resizePrompter promptInWindow:[self window]];
460    [resizePrompter setCurrentSize:[canvas size]];
461
462    NSImage *canvasImage = [[[NSImage alloc] initWithSize:[canvas size]] autorelease];
463    [canvasImage lockFocus];
464    [canvas drawRect:NSMakeRect(0, 0, [canvas size].width, [canvas size].height) fixBug:YES];
465    [canvasImage unlockFocus];
466    [resizePrompter setCachedImage:canvasImage];
467}
468
469- (IBAction)scaleCanvas:(id) sender
470{
471    [[self undoManager] beginUndoGrouping];
472    [self setLayers:[[canvas layers] deepMutableCopy] fromLayers:[canvas layers]];
473    [[self undoManager] setActionName:@"Scale Canvas"];
474    [[self undoManager] endUndoGrouping];
475    [scaleController scaleCanvasFromController:self modalForWindow:[self window]];
476}
477
478- (void)windowDidBecomeMain:(NSNotification *) aNotification
479{
480  if([aNotification object] == [self window])
481    {
482      [self updatePreview];
483      [[PXColorPaletteController sharedPaletteController] reloadDataForCanvas:canvas];
484      [[PXInfoPanelController sharedInfoPanelController] setCanvasSize:[canvas size]];
485    }
486}
487
488- (void)windowDidLoad
489{
490    [view setDelegate:self];
491    [zoomPercentageBox removeAllItems];
492    [zoomPercentageBox addItemsWithObjectValues:[NSArray arrayWithObjects:[NSNumber numberWithInt:3000],
493							 [NSNumber numberWithInt:2000],
494							 [NSNumber numberWithInt:1000],
495							 [NSNumber numberWithInt:800],
496							 [NSNumber numberWithInt:500],
497							 [NSNumber numberWithInt:400],
498							 [NSNumber numberWithInt:200],
499							 [NSNumber numberWithInt:100],
500							 [NSNumber numberWithInt:50], nil]];
501    // If you're looking for randomly hard-coded percentages, they're right here!
502    [zoomPercentageBox selectItemAtIndex:7];
503    [zoomStepper setIntValue:7];
504    NSLog(@"window %@ delegate %@",[self window], [[self window] delegate]);
505    //[window setDelegate: self ]
506    NSLog(@"scrollView %@",NSStringFromRect([[scrollView contentView] frame]));
507
508
509    // Programmatically create our scrollview and canvas view
510    id clip = [[[SBCenteringClipView alloc] initWithFrame:[[scrollView contentView] frame]] autorelease];
511    [clip setBackgroundColor:[NSColor lightGrayColor]];
512    [clip setCopiesOnScroll:NO];
513    NSLog(@"clip^frame %@",NSStringFromRect([clip frame]));
514
515#ifdef __COCOA__
516    [(NSScrollView *)scrollView setContentView:clip];
517#endif
518    [scrollView setDocumentView:view];
519    [view setCanvas:canvas];
520
521    [backgroundController useBackgroundsOf:canvas];
522    //[clip centerDocument];
523    layerController = [[PXLayerController alloc] initWithCanvas:canvas];
524    [[NSNotificationCenter defaultCenter] addObserver:self
525					  selector:@selector(layerSelectionDidChange:)
526					  name:PXLayerSelectionDidChangeName
527					  object:layerController];
528    [layerController setWindow:[self window]];
529    [layerController setNextResponder:self];
530    [[NSNotificationCenter defaultCenter] postNotificationName:PXCanvasLayersChangedNotificationName object:canvas];
531    [self zoomToFit:self];
532    [[PXColorPaletteController sharedPaletteController] reloadDataForCanvas:canvas];
533    [[PXColorPaletteController sharedPaletteController]
534      selectPaletteNamed:NSLocalizedString(@"GENERATED_PALETTE", @"Generated Palette")];
535
536    [[self window] useOptimizedDrawing:YES];
537    [[self window] makeKeyAndOrderFront:self];
538    //[canvas changedInRect:NSMakeRect(0, 0, [canvas size].width, [canvas size].height)];
539    //[self updatePreview];
540}
541
542- (void)updateCanvasSize
543{
544  [[PXInfoPanelController sharedInfoPanelController] setCanvasSize:[canvas size]];
545  [view sizeToCanvas];
546  [self updatePreview];
547  [self zoomToFit:self];
548}
549
550- (void)prompter:aPrompter didFinishWithSize:(NSSize)aSize
551{
552  [canvas setSize:aSize];
553
554  [self updateCanvasSize];
555  [[PXColorPaletteController sharedPaletteController] reloadDataForCanvas:canvas];
556  [[PXColorPaletteController sharedPaletteController] selectDefaultPalette];
557  [(PXImage *)[[[canvas layers] objectAtIndex:0] image] replacePixelsOfColor:nil withColor:[NSColor clearColor]];
558
559}
560
561- (void)prompter:aPrompter didFinishWithSize:(NSSize)aSize position:(NSPoint)position backgroundColor:(NSColor *)color
562{
563    [canvas setSize:aSize withOrigin:position backgroundColor:color];
564	[self updateCanvasSize];
565}
566
567//What is this coding Style ?
568BOOL isTiling;
569- (IBAction) shouldTileToggled: (id) sender
570{
571	isTiling = !isTiling;
572	[sender setState:(isTiling) ? NSOffState : NSOnState];
573	id defaults = [NSUserDefaults standardUserDefaults];
574	[defaults setBool:isTiling forKey:@"PXShouldTile"];
575	[defaults synchronize];
576	[view setShouldTile:isTiling];
577}
578
579- (void)gridSettingsPrompter:aPrompter updatedWithSize:(NSSize)aSize color:color shouldDraw:(BOOL)shouldDraw
580{
581    [[view grid] setUnitSize:aSize];
582    [[view grid] setColor:color];
583    [[view grid] setShouldDraw:shouldDraw];
584    [canvas setGridUnitSize:aSize];
585    [canvas setGridColor:color];
586    [canvas setGridShouldDraw:shouldDraw];
587    [canvas changedInRect:NSMakeRect(0, 0, [canvas size].width, [canvas size].height)];
588}
589
590- (void)mouseDown:event forTool:aTool
591{
592  NSLog(@"mouse Down forTool %@",aTool);
593  if(downEventOccurred) { return; } // avoid the case where the right mouse can be pressed while the left is dragging, and vice-versa. there should really be separate booleans for left-mouse-is-being-used and right-mouse-is-being-used, since right now if the right mouse is pressed and unpressed while the left mouse is pressed, the result will be that the left, too, becomes unpressed. fortunately, there are seemingly no unfortunate side effects from this situation, only the more obvious bug.
594  downEventOccurred = YES;
595  [[NSNotificationCenter defaultCenter] postNotificationName:@"PXLockToolSwitcher" object:aTool];
596  if(! [aTool respondsToSelector:@selector(mouseDownAt:fromCanvasController:)])
597    return;
598
599  initialPoint = [event locationInWindow];
600  NSLog(@"go %@",NSStringFromPoint([view convertFromWindowToCanvasPoint:initialPoint]));
601  [aTool mouseDownAt:[view convertFromWindowToCanvasPoint:initialPoint] fromCanvasController:self];
602}
603
604- (void)mouseDragged:event forTool:aTool
605{
606    if(!downEventOccurred) { return; }
607    if(![aTool respondsToSelector:@selector(mouseDraggedFrom:to:fromCanvasController:)]) { return; }
608    NSPoint endPoint = [event locationInWindow];
609    [aTool mouseDraggedFrom:[view convertFromWindowToCanvasPoint:initialPoint] to:[view convertFromWindowToCanvasPoint:endPoint] fromCanvasController:self];
610    initialPoint = endPoint;
611}
612
613- (void)mouseUp:event forTool:aTool
614{
615  if(!downEventOccurred) { return; }
616  downEventOccurred = NO;
617  [[NSNotificationCenter defaultCenter] postNotificationName:@"PXUnlockToolSwitcher" object:aTool];
618  if(![aTool respondsToSelector:@selector(mouseUpAt:fromCanvasController:)]) { return; }
619  [aTool mouseUpAt:[view convertFromWindowToCanvasPoint:[event locationInWindow]] fromCanvasController:self];
620}
621
622- (void)mouseDown:(NSEvent *)event
623{
624  NSLog(@"mouseDown PXCanvasController");
625  //users expect ctrl-left to == right
626  usingControlKey = (([event modifierFlags] & NSControlKeyMask) == NSControlKeyMask);
627
628  if (usingControlKey)
629    {
630      [self rightMouseDown:event]; return;
631    }
632  [self mouseDown:event forTool:[[PXToolPaletteController sharedToolPaletteController] leftTool]];
633}
634
635- (void)mouseDragged:(NSEvent *) event
636{
637  if (usingControlKey)
638    {
639      [self rightMouseDragged:event]; return;
640    }
641  [self mouseDragged:event forTool:[[PXToolPaletteController sharedToolPaletteController] leftTool]];
642}
643
644- (void)mouseMoved:(NSEvent *) event
645{
646  [view mouseMoved:event];
647}
648
649- (void)mouseUp:(NSEvent *) event
650{
651  if (usingControlKey)
652    {
653      [self rightMouseUp:event]; return;
654    }
655  [self mouseUp:event forTool:[[PXToolPaletteController sharedToolPaletteController] leftTool]];
656}
657
658- (void)rightMouseDown:(NSEvent *) event
659{
660  [self mouseDown:event forTool:[[PXToolPaletteController sharedToolPaletteController] rightTool]];
661}
662
663- (void)rightMouseDragged:(NSEvent *) event
664{
665    [self mouseDragged:event forTool:[[PXToolPaletteController sharedToolPaletteController] rightTool]];
666}
667
668- (void)rightMouseUp:(NSEvent *) event
669{
670    [self mouseUp:event forTool:[[PXToolPaletteController sharedToolPaletteController] rightTool]];
671}
672
673- (void)keyDown:(NSEvent *)event
674{
675  // [FIXME] Should we scroll the view or move the active layer here?  Hmm...
676  if (downEventOccurred) { return; }
677  int scrollAmount = 1;
678  if(([event modifierFlags] & NSShiftKeyMask) == NSShiftKeyMask)
679    {
680      scrollAmount = 10;
681    }
682  if([[event characters] characterAtIndex:0] == NSUpArrowFunctionKey)
683    {
684      [view scrollUpBy:scrollAmount];
685    }
686  else if([[event characters] characterAtIndex:0] == NSRightArrowFunctionKey)
687    {
688      [view scrollRightBy:scrollAmount];
689    }
690  else if([[event characters] characterAtIndex:0] == NSDownArrowFunctionKey)
691    {
692      [view scrollDownBy:scrollAmount];
693    }
694  else if([[event characters] characterAtIndex:0] == NSLeftArrowFunctionKey)
695    {
696      [view scrollLeftBy:scrollAmount];
697    }
698  else if([[event characters] characterAtIndex:0] == NSDeleteFunctionKey)
699    {
700      [[[NSDocumentController sharedDocumentController] currentDocument] delete:self];
701      //[canvas deleteSelection];
702      //[canvas changedInRect:NSMakeRect(0, 0, [canvas size].width, [canvas size].height)];
703    }
704  else
705    {
706      [[PXToolPaletteController sharedToolPaletteController] keyDown:event];
707      [[PXColorPaletteController sharedPaletteController] keyDown:event];
708    }
709}
710
711- (void)flagsChanged:(NSEvent *) event
712{
713  [[PXToolPaletteController sharedToolPaletteController] flagsChanged:event];
714}
715
716- (IBAction)showPreviewWindow:(NSEvent *) sender
717{
718  [previewController showWindow:self];
719}
720
721- (IBAction)togglePreviewWindow: (id) sender
722{
723  if ([[previewController window] isVisible])
724    {
725      [[previewController window] performClose:self];
726    }
727  else
728    {
729      [previewController showWindow:self];
730    }
731}
732
733- (IBAction)showBackgroundInfo:(id) sender
734{
735  NSLog(@"showBackgroundInfo %@",[backgroundController backgroundPanel]);
736  [[backgroundController backgroundPanel] makeKeyAndOrderFront: self];
737}
738
739- (IBAction)showGridSettingsPrompter:(id) sender
740{
741  if (gridSettingsPrompter)
742    [gridSettingsPrompter release];
743
744  gridSettingsPrompter = [[PXGridSettingsPrompter alloc] initWithSize:[[view grid] unitSize]
745							 color:[[view grid] color]
746							 shouldDraw:[[view grid] shouldDraw] ? YES : NO];
747  [gridSettingsPrompter setDelegate:self];
748  [(PXGridSettingsPrompter *)gridSettingsPrompter prompt];
749}
750
751- (void)zoomToIndex:(float)index
752{
753  if(index < 0 || index >= [zoomPercentageBox numberOfItems]) {
754#ifdef __COCOA__
755    NSBeep();
756#endif
757    return;
758  }
759
760  [zoomPercentageBox selectItemAtIndex:index];
761  [zoomStepper setIntValue:index];
762  [view setZoomPercentage:[zoomPercentageBox intValue]];
763}
764
765- (void)zoomToPercentage:(NSNumber *)percentage
766{
767  if( percentage == nil
768      || [percentage isEqual:[NSNumber numberWithInt:0]]
769      || [[[percentage description] lowercaseString] isEqualToString:@"inf"]
770      || [[[percentage description] lowercaseString] isEqualToString:@"nan"])
771    {
772      [self zoomToPercentage:[NSNumber numberWithFloat:100]];
773      return;
774    }
775  // Kind of a HACK, could change if the description changes to display something other than inf or nan on such numbers.
776  //Probably not an issue, but I'll mark it so it's easy to find if it breaks later.
777
778
779  if( ! [[zoomPercentageBox objectValues] containsObject:percentage])
780    {
781      id values = [NSMutableArray arrayWithArray:[zoomPercentageBox objectValues]];
782      [values addObject:percentage];
783      [values sortUsingSelector:@selector(compare:)];
784      [zoomPercentageBox removeAllItems];
785      [zoomPercentageBox addItemsWithObjectValues:[[values reverseObjectEnumerator] allObjects]];
786    }
787
788  [zoomPercentageBox selectItemWithObjectValue:percentage];
789  [self zoomToIndex:[zoomPercentageBox indexOfSelectedItem]];
790}
791
792- (IBAction)zoomIn: (id) sender
793{
794    [self zoomToIndex:[zoomStepper intValue]-1];
795}
796
797- (IBAction)zoomOut: (id) sender
798{
799    [self zoomToIndex:[zoomStepper intValue]+1];
800}
801
802- (IBAction)zoomStandard: (id) sender
803{
804  [self zoomToIndex:[zoomPercentageBox indexOfItemWithObjectValue:[NSNumber numberWithInt:100]]];
805}
806
807- (IBAction)zoomPercentageChanged:sender
808{
809    [self zoomToPercentage:[zoomPercentageBox objectValue]];
810}
811
812- (IBAction)zoomStepperStepped:(id) sender
813{
814  if([zoomStepper intValue] >= [zoomPercentageBox numberOfItems])
815    {
816#ifdef __COCOA__
817      NSBeep();
818#endif
819      [zoomStepper setIntValue:[zoomPercentageBox numberOfItems]-1];
820      return;
821    }
822  [self zoomToIndex:[zoomStepper intValue]];
823}
824
825- (IBAction)zoomToFit:(id) sender
826{
827  float xRatio = [[scrollView contentView] frame].size.width/[canvas size].width;
828  float  yRatio = [[scrollView contentView] frame].size.height/[canvas size].height;
829
830  [self zoomToPercentage:([[scrollView contentView] frame].size.width > [canvas size].width ||
831			  [[scrollView contentView] frame].size.width > [canvas size].width) ?
832	[NSNumber numberWithFloat:(floorf(xRatio < yRatio ? xRatio : yRatio))*100] :
833	  [NSNumber numberWithFloat:100.0f]];
834}
835
836- (void)zoomInOnCanvasPoint:(NSPoint)point
837{
838    [self zoomIn:self];
839    [view centerOn:[view convertFromCanvasToViewPoint:point]];
840}
841
842- (void)zoomOutOnCanvasPoint:(NSPoint)point
843{
844    [self zoomOut:self];
845    [view centerOn:[view convertFromCanvasToViewPoint:point]];
846}
847
848- (IBAction)toggleLayersDrawer:(id) sender
849{
850  [layerController toggle:sender];
851}
852
853@end
854