blob: c9a61842ece0e213421591872c49d94c7054871f [file] [log] [blame]
/*
* Copyright (C) 2005 Apple Computer, Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#import "KWQAssertions.h"
#import "DrawViewPrivate.h"
#import "DrawCanvasItem.h"
#import "DrawDocumentPrivate.h"
#import <kcanvas/KCanvas.h>
#import <kcanvas/KCanvasContainer.h>
#import <kcanvas/device/quartz/KCanvasViewQuartz.h>
#import <kcanvas/device/quartz/KRenderingDeviceQuartz.h>
// This should go in the Prefix header eventually.
#define foreacharray(__variable, __container) \
for (int __variable##__i=0, __variable##__n=[__container count]; \
__variable##__i < __variable##__n && (__variable = [__container objectAtIndex:__variable##__i]); \
++__variable##__i)
#define NSDifferencePoint(a,b) (NSMakePoint(a.x-b.x, a.y-b.y))
#define NSSumPoint(a,b) (NSMakePoint(a.x+b.x, a.y+b.y))
// editing knobs.
#define KNOB_SIZE 6
#define KNOB_HALF_SIZE 3
typedef enum {
DragActionNone = 0,
DragActionPan,
DragActionResize,
DragActionMove,
DragActionSelection
} DrawDragAction;
// this is sorta a hack
@interface DrawDocument (InternalCanvasMethod)
- (KCanvas *)canvas;
@end
@interface DrawViewPrivate : NSObject {
@public
NSArray *selectedItems;
DrawView *drawView; // pointer to "owner"
DrawDocument *document;
NSColor *backgroundColor;
int dragControlPointIndex;
NSPoint dragStartPoint;
NSPoint lastDragPoint;
NSPoint canvasDragAnchorPoint; // used mostly for group resize.
NSPoint canvasDragOriginOffset;
int trackingRectTag;
DrawDragAction currentDragAction;
NSRect selectionRect;
NSSize _maxSize;
// temporary hack, will eventually be stored in scrollview/view
float canvasZoom;
NSPoint canvasvisibleOrigin;
KCanvasViewQuartz *canvasView;
KRenderingDeviceContextQuartz *quartzContext;
}
@end
@implementation DrawViewPrivate
- (id)initWithDrawView:(DrawView *)view
{
if ((self = [super init])) {
drawView = view;
quartzContext = new KRenderingDeviceContextQuartz();
canvasView = new KCanvasViewQuartz();
canvasView->setView(drawView);
canvasView->setContext(quartzContext);
}
return self;
}
- (DrawDocument *)document
{
return document;
}
- (void)setDocument:(DrawDocument *)doc
{
if (doc != document) {
[document unregisterView:drawView];
[document release];
document = [doc retain];
delete canvasView;
canvasView = NULL;
if (document) {
canvasView = new KCanvasViewQuartz();
canvasView->init([document canvas], NULL);
canvasView->setView(drawView);
canvasView->setContext(quartzContext);
}
[document registerView:drawView];
}
}
// c++ enabled drawing code.
- (void)drawRect:(NSRect)dirtyViewRect
{
if (![document canvas] || ![document canvas]->rootContainer() || !canvasView)
return;
// push the drawing context
KRenderingDevice *renderingDevice = [document canvas]->renderingDevice();
ASSERT(renderingDevice);
// Apply the top-level "world transform" for zoom/pan
CGContextRef context = (CGContextRef)[[NSGraphicsContext currentContext] graphicsPort];
quartzContext->setCGContext(context); // should probably just be set once...
renderingDevice->pushContext(quartzContext);
CGContextSaveGState(context);
CGContextConcatCTM(context, CGAffineTransformInvert([drawView transformFromViewToCanvas]));
// do the draw
//[document drawRect:[drawView mapViewRectToCanvas:dirtyViewRect] inCGContext:context];
[document canvas]->rootContainer()->draw(QRect([drawView mapViewRectToCanvas:dirtyViewRect]));
// restore drawing state
CGContextRestoreGState(context);
renderingDevice->popContext();
quartzContext->setCGContext(NULL);
}
- (void)dealloc
{
// If we go away, make sure we clear the view pointer.
[document unregisterView:drawView];
delete canvasView;
delete quartzContext;
[super dealloc];
}
@end
NSArray *DrawViewDragTypes;
@interface DrawView (InternalMethods)
- (void)drawKnobsForRect:(NSRect)rect;
- (void)updateCanvasScale;
- (void)enableMouseMovedEventsIfNeeded;
@end
@implementation DrawView
+ (void)initialize
{
//DrawViewDragTypes = [[NSArray arrayWithObject:NSFilenamesPboardType] retain];
[self setKeys:[NSArray arrayWithObject:@"toolMode"] triggerChangeNotificationsForDependentKey:@"selectedCanvasItems"];
}
+ (void)setFilterSupportEnabled:(BOOL)enabled
{
KRenderingDeviceQuartz::setFiltersEnabled(enabled);
}
+ (BOOL)isFilterSupportEnabled
{
return KRenderingDeviceQuartz::filtersEnabled();
}
+ (void)setHardwareFilterSupportEnabled:(BOOL)enabled
{
KRenderingDeviceQuartz::setHardwareRenderingEnabled(enabled);
}
+ (BOOL)isHardwareFilterSupportEnabled
{
return KRenderingDeviceQuartz::hardwareRenderingEnabled();
}
- (id)initWithFrame:(NSRect)frameRect
{
if ((self = [super initWithFrame:frameRect]) != nil) {
_private = [[DrawViewPrivate alloc] initWithDrawView:self];
}
return self;
}
- (void)dealloc
{
[_private release];
[super dealloc];
}
// Used when the document dellocs
// to avoid recursion.
- (void)_clearDocument
{
_private->document = nil;
delete _private->canvasView;
_private->canvasView = NULL;
}
- (NSRect)selectionCanvasBoundingBox
{
NSRect selectionBoundingBox = NSZeroRect;
DrawCanvasItem *item = nil;
NSArray *selectedItems = [self selectedCanvasItems];
foreacharray(item, selectedItems) {
selectionBoundingBox = NSUnionRect(selectionBoundingBox,[item boundingBox]);
}
return selectionBoundingBox;
}
- (void)_clearAndDrawBackground:(NSRect)dirtyRect
{
[[NSColor lightGrayColor] set];
NSRectFill(dirtyRect);
[[self backgroundColor] set];
NSSize canvasSize = [[self document] canvasSize];
NSRect canvasRect = NSMakeRect(0,0, canvasSize.width, canvasSize.height);
NSRectFill([self mapCanvasRectToView:canvasRect]);
}
- (void)_drawSelectionKnobs
{
if ((_toolMode == DrawViewToolArrow) && [[self selectedCanvasItems] count]) {
NSRect viewSelectionBoundingBox = [self mapCanvasRectToView:[self selectionCanvasBoundingBox]];
[self drawKnobsForRect:viewSelectionBoundingBox];
}
if (_private->currentDragAction == DragActionSelection) {
[[NSColor lightGrayColor] set];
NSFrameRect(_private->selectionRect);
}
}
- (void)drawRect:(NSRect)dirtyRect
{
[self _clearAndDrawBackground:dirtyRect];
[_private drawRect:dirtyRect];
[self _drawSelectionKnobs];
}
- (void)setBackgroundColor:(NSColor *)color
{
id oldColor = _private->backgroundColor ;
_private->backgroundColor = [color retain];
[oldColor release];
}
- (NSColor *)backgroundColor
{
if (!_private->backgroundColor)
_private->backgroundColor = [[NSColor whiteColor] retain];
return _private->backgroundColor;
}
- (BOOL)isOpaque
{
return ![_private->backgroundColor isEqual:[NSColor clearColor]];
}
- (BOOL)isFlipped
{
return YES;
}
- (BOOL)acceptsFirstResponder
{
return YES;
}
- (BOOL)acceptsFirstMouse:(NSEvent *)event
{
return ((_toolMode == DrawViewToolBrowse) || (_toolMode == DrawViewToolArrow));
}
- (NSImageScaling)imageScaling
{
return _scaleRule;
}
- (void)setImageScaling:(NSImageScaling)scaling
{
_scaleRule = scaling;
[self updateCanvasScale];
}
- (void)setFrame:(NSRect)newFrame
{
[self removeTrackingRect:_private->trackingRectTag];
[self setFrameOrigin:newFrame.origin];
[self setFrameSize:newFrame.size];
_private->trackingRectTag =
[self addTrackingRect:[self frame]
owner:self userData:NULL
assumeInside:[self mouse:[NSEvent mouseLocation] inRect:[self bounds]]];
}
- (void)setFrameSize:(NSSize)newSize
{
[super setFrameSize:newSize];
[self updateCanvasScale];
}
- (void)setDocument:(DrawDocument *)document
{
if ([_private document] != document) {
[_private setDocument:document];
[self updateCanvasScale];
[self setNeedsDisplay:YES];
}
}
- (DrawDocument *)document
{
return [_private document];
}
- (KCanvasViewQuartz *)canvasView
{
return _private->canvasView;
}
#pragma mark -
#pragma mark Editing support
- (void)setEditable:(BOOL)editable
{
[self unregisterDraggedTypes];
_isEditable = editable;
if (_isEditable)
[self registerForDraggedTypes:DrawViewDragTypes];
}
- (BOOL)isEditable
{
return _isEditable;
}
- (NSRect)boundsForCanvasItem:(DrawCanvasItem *)canvasItem
{
NSRect itemBBoxInCanvas = [canvasItem boundingBox];
NSRect itemBBoxInView = [self mapCanvasRectToView:itemBBoxInCanvas];
return NSInsetRect(itemBBoxInView, -KNOB_HALF_SIZE, -KNOB_HALF_SIZE);
}
- (NSArray *)selectedCanvasItems
{
// selection only "exists" when using the arrow tool.
// but we sill remember selection between uses.
return _private->selectedItems;
}
- (void)setSelectedCanvasItems:(NSArray *)selectedItems
{
DrawCanvasItem *newSelectedItem = nil;
NSMutableArray *newSelectedItems = [[NSMutableArray alloc] init];
foreacharray(newSelectedItem, selectedItems) {
[newSelectedItems addObject:newSelectedItem];
}
[_private->selectedItems release];
if ([newSelectedItems count])
_private->selectedItems = newSelectedItems;
else
_private->selectedItems = nil;
[self setNeedsDisplay:YES]; // FIXME: just invalidate the whole view for now.
}
- (IBAction)moveSelectionForward:(id)sender
{
DrawCanvasItem *item = nil;
NSArray *selectedItems = [self selectedCanvasItems];
foreacharray(item, selectedItems) {
[item raise];
}
}
- (IBAction)moveSelectionBackward:(id)sender
{
DrawCanvasItem *item = nil;
NSArray *selectedItems = [self selectedCanvasItems];
foreacharray(item, selectedItems) {
[item lower];
}
}
- (NSArray *)canvasControlPointsForSelection
{
NSArray *selectedItems = [self selectedCanvasItems];
if ([selectedItems count] == 1)
return [[selectedItems objectAtIndex:0] controlPoints];
else if ([selectedItems count] > 1)
return [DrawCanvasItem controlPointsForRect:[self selectionCanvasBoundingBox]];
return nil;
}
- (NSPoint)canvasDragAnchorPointForControlPointIndex:(int)controlPointIndex
{
NSArray *selectedItems = [self selectedCanvasItems];
if ([selectedItems count] == 1) {
return [[selectedItems objectAtIndex:0] dragAnchorPointForControlPointIndex:controlPointIndex];
} else if ([selectedItems count] > 1) {
NSArray *controlPoints = [DrawCanvasItem controlPointsForRect:[self selectionCanvasBoundingBox]];
return [DrawCanvasItem dragAnchorPointForControlPointIndex:controlPointIndex fromRectControlPoints:controlPoints];
}
NSLog(@"Error, no selection, you shouldn't ask for drag anchor point!");
return NSZeroPoint;
}
- (int)controlPointIndexForCanvasHitPoint:(NSPoint)canvasPoint
{
NSValue *controlPointValue = nil;
NSArray *controlPoints = [self canvasControlPointsForSelection];
NSSize canvasKnobSize = [self mapViewSizeToCanvas:NSMakeSize(KNOB_SIZE, KNOB_SIZE)];
NSRect controlRect = NSZeroRect;
controlRect.size = canvasKnobSize;
NSSize halfCanvasKnobSize = NSMakeSize(canvasKnobSize.width/2.f, canvasKnobSize.height/2.f);
int index = 0;
foreacharray (controlPointValue, controlPoints) {
NSPoint controlPoint = [controlPointValue pointValue];
controlRect.origin.x = controlPoint.x - halfCanvasKnobSize.width;
controlRect.origin.y = controlPoint.y - halfCanvasKnobSize.height;
if (NSPointInRect(canvasPoint, controlRect))
return index;
index++;
}
return NSNotFound;
}
- (BOOL)createCanvasItemAtPoint:(NSPoint)mousePoint
{
// first map to canvas coords.
mousePoint = [self mapViewPointToCanvas:mousePoint];
DrawCanvasItem *newItem = [[_private document] createItemForTool:_toolMode atPoint:mousePoint];
if (newItem) {
[self setSelectedCanvasItems:[NSArray arrayWithObject:newItem]];
return YES;
}
return NO;
}
- (IBAction)deleteSelection:(id)sender
{
NSArray *oldItems = [[self selectedCanvasItems] retain];
[self setSelectedCanvasItems:nil];
DrawCanvasItem *oldItem = nil;
foreacharray(oldItem, oldItems) {
[[_private document] removeItemFromDOM:oldItem];
}
[oldItems release];
}
- (int)toolMode
{
return _toolMode;
}
- (void)setToolMode:(int)newToolMode
{
_toolMode = (DrawViewTool)newToolMode;
//[[self window] invalidateCursorRectsForView:self];
// Not getting called until the view becomes key...
[[self window] resetCursorRects]; // HACK?
if ([self mouse:[NSEvent mouseLocation] inRect:[self bounds]])
[self enableMouseMovedEventsIfNeeded];
}
- (void)resetCursorRects
{
[super resetCursorRects];
NSCursor *toolCursor = nil;
switch (_toolMode) {
case DrawViewToolBrowse:
toolCursor = [NSCursor pointingHandCursor];
break;
case DrawViewToolPan:
toolCursor = [NSCursor openHandCursor];
break;
case DrawViewToolZoom:
toolCursor = [NSCursor closedHandCursor]; // for now...
break;
case DrawViewToolLine:
case DrawViewToolElipse:
case DrawViewToolRectangle:
case DrawViewToolPolyLine:
case DrawViewToolArc:
toolCursor = [NSCursor crosshairCursor];
break;
default:
break;
}
if (toolCursor)
[self addCursorRect:[self frame] cursor:toolCursor];
}
- (void)drawKnobsForRect:(NSRect)rect
{
[[NSColor blackColor] set];
[NSBezierPath fillRect:NSMakeRect(rect.origin.x - KNOB_HALF_SIZE, rect.origin.y - KNOB_HALF_SIZE, KNOB_SIZE, KNOB_SIZE)];
[NSBezierPath fillRect:NSMakeRect(NSMaxX(rect) - KNOB_HALF_SIZE, rect.origin.y - KNOB_HALF_SIZE, KNOB_SIZE, KNOB_SIZE)];
[NSBezierPath fillRect:NSMakeRect(rect.origin.x - KNOB_HALF_SIZE, NSMaxY(rect) - KNOB_HALF_SIZE, KNOB_SIZE, KNOB_SIZE)];
[NSBezierPath fillRect:NSMakeRect(NSMaxX(rect) - KNOB_HALF_SIZE, NSMaxY(rect) - KNOB_HALF_SIZE, KNOB_SIZE, KNOB_SIZE)];
}
#pragma mark -
#pragma mark Event support
- (void)mouseDown:(NSEvent *)theEvent
{
NSPoint mousePoint = [self convertPoint:[theEvent locationInWindow] fromView:nil];
NSPoint canvasPoint = [self mapViewPointToCanvas:mousePoint];
_private->dragStartPoint = mousePoint;
_private->lastDragPoint = mousePoint;
switch (_toolMode) {
case DrawViewToolBrowse:
{
// send mouse down events to DOM
if (![[_private document] documentListensForMouseDownEvents])
return;
[[_private document] propagateMouseDownEvent:theEvent fromView:self];
break;
}
case DrawViewToolArrow:
{
if ( (_private->dragControlPointIndex = [self controlPointIndexForCanvasHitPoint:canvasPoint]) != NSNotFound) {
_private->canvasDragAnchorPoint = [self canvasDragAnchorPointForControlPointIndex:_private->dragControlPointIndex];
NSLog(@"resize -- dragStartPoint: %@ canvasPoint: %@ controlIndex: %i canvasDragAnchorPoint: %@",
NSStringFromPoint(mousePoint), NSStringFromPoint(canvasPoint),
_private->dragControlPointIndex, NSStringFromPoint(_private->canvasDragAnchorPoint));
_private->currentDragAction = DragActionResize;
} else {
// FIXME: we really should select SVGElements, not canvas items...
DrawCanvasItem *hitItem = [[_private document] canvasItemAtPoint:canvasPoint];
//NSLog(@"move -- dragStartPoint: %@ canvasPoint: %@", NSStringFromPoint(mousePoint), NSStringFromPoint(canvasPoint));
if (hitItem) {
NSArray *hitItems = [NSArray arrayWithObject:hitItem];
[self setSelectedCanvasItems:hitItems];
_private->currentDragAction = DragActionMove;
NSPoint hitOrigin = [hitItem boundingBox].origin;
_private->canvasDragOriginOffset = NSDifferencePoint(hitOrigin, canvasPoint);
} else {
[self setSelectedCanvasItems:nil];
_private->currentDragAction = DragActionSelection;
}
}
break;
}
case DrawViewToolPan:
[[NSCursor closedHandCursor] push];
_private->currentDragAction = DragActionPan;
//NSLog(@"mouseDown: %@", NSStringFromPoint(_private->lastDragPoint));
break;
// creation tools:
case DrawViewToolLine:
case DrawViewToolElipse:
case DrawViewToolTriangle:
case DrawViewToolRectangle:
case DrawViewToolPolyLine:
case DrawViewToolArc:
{
if ([self createCanvasItemAtPoint:mousePoint]) {
_private->currentDragAction = DragActionResize;
_private->canvasDragAnchorPoint = canvasPoint;
_private->dragControlPointIndex = 0;
}
break;
}
default:
break;
}
}
- (void)mouseDragged:(NSEvent *)theEvent
{
NSPoint mousePoint = [self convertPoint:[theEvent locationInWindow] fromView:nil];
switch (_toolMode) {
case DrawViewToolBrowse:
{
// send mouse dragged events to DOM.
break;
}
case DrawViewToolArrow:
{
// move shapes here.
if (_private->currentDragAction == DragActionMove) {
NSSize dragOffset = NSMakeSize(mousePoint.x - _private->lastDragPoint.x, mousePoint.y - _private->lastDragPoint.y);
NSSize canvasDragOffset = [self mapViewSizeToCanvas:dragOffset];
NSLog(@"move: translating selection by: %@", NSStringFromSize(canvasDragOffset));
DrawCanvasItem *item = nil;
NSArray *selectedItems = [self selectedCanvasItems];
foreacharray(item, selectedItems) {
[self setNeedsDisplayInRect:[self boundsForCanvasItem:item]];
[item translateByOffset:canvasDragOffset];
[self setNeedsDisplayInRect:[self boundsForCanvasItem:item]];
}
} else if (_private->currentDragAction == DragActionSelection) {
[self setNeedsDisplayInRect:_private->selectionRect];
_private->selectionRect = NSMakeRect(_private->dragStartPoint.x,
_private->dragStartPoint.y,
mousePoint.x - _private->dragStartPoint.x,
mousePoint.y - _private->dragStartPoint.y);
[self setNeedsDisplayInRect:_private->selectionRect];
}
// fall through for resize code.
}
case DrawViewToolLine:
case DrawViewToolElipse:
case DrawViewToolTriangle:
case DrawViewToolRectangle:
case DrawViewToolPolyLine:
case DrawViewToolArc:
{
if (_private->currentDragAction == DragActionResize) {
NSPoint canvasPoint = [self mapViewPointToCanvas:mousePoint];
DrawCanvasItem *item = nil;
NSArray *selectedItems = [self selectedCanvasItems];
foreacharray(item, selectedItems) {
[self setNeedsDisplayInRect:[self boundsForCanvasItem:item]];
[item resizeWithPoint:canvasPoint usingControlPoint:_private->dragControlPointIndex dragAnchorPoint:_private->canvasDragAnchorPoint];
[self setNeedsDisplayInRect:[self boundsForCanvasItem:item]];
}
}
break;
}
case DrawViewToolPan:
{
NSPoint diff = NSDifferencePoint(mousePoint, _private->lastDragPoint);
NSPoint canvasOrigin = [self canvasVisibleOrigin];
NSPoint newOrigin = NSDifferencePoint(canvasOrigin, diff);
[self setCanvasVisibleOrigin:newOrigin];
// NSLog(@"mouseDragged: %@ diff: %@ old origin: %@ newOrigin: %@",
// NSStringFromPoint(_private->lastDragPoint),
// NSStringFromPoint(diff), NSStringFromPoint(canvasOrigin), NSStringFromPoint(newOrigin));
break;
}
default:
break;
}
// record the last drag point.
_private->lastDragPoint = mousePoint;
}
- (void)mouseUp:(NSEvent *)theEvent
{
//NSPoint mousePoint = [self convertPoint:[theEvent locationInWindow] fromView:nil];
switch (_toolMode) {
case DrawViewToolBrowse:
{
if (![[_private document] documentListensForMouseUpEvents])
return;
[[_private document] propagateMouseUpEvent:theEvent fromView:self];
}
case DrawViewToolPan:
[NSCursor pop];
break;
case DrawViewToolArrow:
if (_private->currentDragAction == DragActionSelection) {
[self setNeedsDisplayInRect:_private->selectionRect];
// figure out what all was in that rect...
_private->selectionRect = NSZeroRect;
}
break;
default:
break;
}
_private->currentDragAction = DragActionNone;
}
- (void)disableMouseMovedEvents
{
if ([[self window] acceptsMouseMovedEvents])
NSLog(@"Mouse move events now OFF");
[[self window] setAcceptsMouseMovedEvents:NO];
}
- (void)enableMouseMovedEventsIfNeeded
{
// FIXME: This could still be more efficient
BOOL needsMouseMoved = (_toolMode == DrawViewToolBrowse)
&& [[_private document] documentListensForMouseMovedEvents];
if (needsMouseMoved != [[self window] acceptsMouseMovedEvents])
NSLog(@"Mouse move events now %@", needsMouseMoved ? @"ON" : @"OFF");
if (needsMouseMoved) {
[[self window] setAcceptsMouseMovedEvents:needsMouseMoved];
}
}
- (void)mouseEntered:(NSEvent *)theEvent
{
[self enableMouseMovedEventsIfNeeded];
}
- (void)mouseExited:(NSEvent *)theEvent
{
[self disableMouseMovedEvents];
}
- (void)mouseMoved:(NSEvent *)theEvent
{
//NSPoint mousePoint = [self convertPoint:[theEvent locationInWindow] fromView:nil];
switch (_toolMode) {
case DrawViewToolBrowse:
{
if (![[_private document] documentListensForMouseMovedEvents])
return;
NSCursor *cursor = [[_private document] cursorAfterPropagatingMouseMovedEvent:theEvent fromView:self];
if (cursor && (cursor != [NSCursor currentCursor])) NSLog(@"Changing cursor: %@ name: %@", cursor, [[cursor image] name]);
[cursor set];
}
default:
break;
}
}
- (void)keyDown:(NSEvent *)theEvent
{
if (_toolMode == DrawViewToolArrow) {
unichar key = [[theEvent charactersIgnoringModifiers] characterAtIndex:0];
int flags = [theEvent modifierFlags] & NSDeviceIndependentModifierFlagsMask;
if (([theEvent keyCode] == NSDeleteFunctionKey) || ((key == NSDeleteCharacter) && (flags == 0)) ) {
[self deleteSelection:nil];
}
} else if (_toolMode == DrawViewToolBrowse) {
// Propagate the key event up through the DOM
}
}
#pragma mark -
#pragma mark Zoom/Pan support
- (IBAction)zoomToFit:(id)sender
{
NSSize canvasSize = [[_private document] canvasSize];
float widthScale = canvasSize.width / [self bounds].size.width;
float heightScale = canvasSize.height / [self bounds].size.height;
float minScale = MAX(widthScale, heightScale);
[self setCanvasZoom:minScale];
}
- (void)updateCanvasScale
{
if (_scaleRule == NSScaleProportionally) {
[self zoomToFit:nil];
} else if (_scaleRule == NSScaleToFit) {
// Not yet supported!
} else if (_scaleRule == NSScaleNone) {
[self setCanvasZoom:1.0];
}
}
- (void)sizeToFitCanvas
{
NSSize canvasSize = [[_private document] canvasSize];
if ((canvasSize.width == 0) || (canvasSize.height == 0))
return; // avoid disappearing.
[self setFrameSize:canvasSize];
}
- (void)sizeToFitViewBox
{
// FIXME: this is broken!
[self sizeToFitCanvas];
}
- (IBAction)zoomIn:(id)sender
{
NSPoint center = [self canvasvisibleCenterPoint];
[self setCanvasZoom:([self canvasZoom] * 0.9)];
[self panToCanvasCenterPoint:center];
}
- (IBAction)zoomOut:(id)sender
{
NSPoint center = [self canvasvisibleCenterPoint];
[self setCanvasZoom:([self canvasZoom] * 1.1)];
[self panToCanvasCenterPoint:center];
}
- (IBAction)zoomOriginal:(id)sender
{
// do these need to call into the canvas or document instead?
[self setCanvasZoom:1.0];
[self setCanvasVisibleOrigin:NSMakePoint(0,0)];
}
- (CGAffineTransform)transformFromViewToCanvas
{
float zoom = [self canvasZoom];
CGAffineTransform transform = CGAffineTransformMakeScale(zoom, zoom);
NSPoint origin = [self canvasVisibleOrigin];
return CGAffineTransformTranslate(transform,origin.x,origin.y);
}
- (NSPoint)mapViewPointToCanvas:(NSPoint)viewPoint
{
CGPoint canvasPoint = CGPointApplyAffineTransform(*(CGPoint *)&viewPoint, [self transformFromViewToCanvas]);
return (*(NSPoint *)&canvasPoint);
}
- (NSRect)mapViewRectToCanvas:(NSRect)viewRect
{
CGRect canvasRect = CGRectApplyAffineTransform(*(CGRect *)&viewRect, [self transformFromViewToCanvas]);
return (*(NSRect *)&canvasRect);
}
- (NSSize)mapViewSizeToCanvas:(NSSize)viewSize
{
CGSize canvasSize = CGSizeApplyAffineTransform(*(CGSize *)&viewSize, [self transformFromViewToCanvas]);
return (*(NSSize *)&canvasSize);
}
- (NSPoint)mapCanvasPointToView:(NSPoint)canvasPoint
{
CGPoint viewPoint = CGPointApplyAffineTransform(*(CGPoint *)&canvasPoint, CGAffineTransformInvert([self transformFromViewToCanvas]));
return (*(NSPoint *)&viewPoint);
}
- (NSRect)mapCanvasRectToView:(NSRect)canvasRect
{
CGRect viewRect = CGRectApplyAffineTransform(*(CGRect *)&canvasRect, CGAffineTransformInvert([self transformFromViewToCanvas]));
return (*(NSRect *)&viewRect);
}
- (NSSize)mapCanvasSizeToView:(NSSize)canavsSize
{
CGSize viewSize = CGSizeApplyAffineTransform(*(CGSize *)&canavsSize, CGAffineTransformInvert([self transformFromViewToCanvas]));
return (*(NSSize *)&viewSize);
}
#pragma mark -
#pragma mark Canvas Zoom/Pan (Hack!)
- (NSPoint)canvasVisibleOrigin
{
return _private->canvasvisibleOrigin;
}
- (void)setCanvasVisibleOrigin:(NSPoint)newOrigin
{
// will eventually move into NSScrollView I figure.
_private->canvasvisibleOrigin = newOrigin;
[self setNeedsDisplay:YES];
}
- (NSPoint)canvasvisibleCenterPoint
{
NSPoint centerPoint = [self canvasVisibleOrigin];
NSSize canvasVisibleSize = [self mapViewSizeToCanvas:[self bounds].size];
centerPoint.x += canvasVisibleSize.width/2.f;
centerPoint.y += canvasVisibleSize.height/2.f;
// NSPoint cvo = [self canvasVisibleOrigin];
// NSLog(@"Visible center: %@ visible origin: %@ visible size: %@ farPoint: %@",
// NSStringFromPoint(centerPoint), NSStringFromPoint(cvo),
// NSStringFromSize(canvasVisibleSize), NSStringFromPoint(NSMakePoint(cvo.x + canvasVisibleSize.width, cvo.y + canvasVisibleSize.height)));
return centerPoint;
}
- (void)panToCanvasCenterPoint:(NSPoint)newCenter
{
NSPoint newVisibleOrigin = newCenter;
NSSize canvasVisibleSize = [self mapViewSizeToCanvas:[self bounds].size];
newVisibleOrigin.x -= canvasVisibleSize.width/2.f;
newVisibleOrigin.y -= canvasVisibleSize.height/2.f;
// NSLog(@"setting new origin: %@ visible size: %@", NSStringFromPoint(newVisibleOrigin), NSStringFromSize(canvasVisibleSize));
[self setCanvasVisibleOrigin:newVisibleOrigin];
}
- (float)canvasZoom
{
return _private->canvasZoom;
//return [self scale].width;
}
- (void)setCanvasZoom:(float)newZoom
{
if (_private->canvasZoom != newZoom) {
_private->canvasZoom = newZoom;
//[self setScale:NSMakeSize(newZoom, newZoom)];
[self setNeedsDisplay:YES];
}
}
@end