[Drawkit] tool to create object of pre-set size then click to place?
Allan Daly
allandaly at me.com
Thu Dec 31 10:26:42 PST 2009
I figured something out -- here's my approach in case it's useful to
anyone. I'd be glad to hear any other/better ideas on this.
I created a new "stamp tool" that is a subclass of
DKObjectCreationTool. It sets the cursor with an image based on the
prototype object so that when the tool is clicked the cursor changes
to an image of the object that will be "stamped." On a mouse down
event the prototype object is added to the target layer. If "sticky
tools" are set ( [DKToolController
setAutomaticallyRevertsToSelectionTool:NO]) then you can stamp/insert
many of the same object over and over again.
I gave this subclass a "cursorImage" method so that it can draw itself
for the cursor, but also so it can draw itself to set a tool palette
icon. When initializing a tool palette then this code can set the
image for that tool.
if ([[DKDrawingTool drawingToolWithName:[cell title]]
respondsToSelector:@selector(cursorImage)])
{
[cell setImage:[[DKDrawingTool drawingToolWithName:[cell title]]
cursorImage]];
}
The tool is initialized at some point in the application with code
along the lines of the following.
// register the "center mark" tool, which is not one of the DK
standard tools
DKDrawableShape * shape = [[DKDrawableShape alloc] init];
[shape setPath:[DKShapeFactory centerMark]];
DKDrawingTool * dt = [[BBStampTool alloc]
initWithPrototypeObject:shape];
[(BBStampTool *)dt setCursorDimension:48.0];
[DKDrawingTool registerDrawingTool:dt withName:@"Center Mark"];
Here's the implementation of the stamp tool.
// ---------- BBStampTool.h --------------
#import <Cocoa/Cocoa.h>
#import <GCDrawKit/DKDrawkit.h>
@interface BBStampTool : DKObjectCreationTool
{
float _cursorDim;
}
@property float cursorDimension;
- (NSImage *) cursorImage;
@end
// ---------- BBStampTool.m --------------
#import "BBStampTool.h"
@implementation BBStampTool
@synthesize cursorDimension = _cursorDim;
#pragma mark -
#pragma mark - As a BBStampTool
- (NSImage *) cursorImage
{
// create a size based on the ivar _cursorDim
NSSize cursorSize = NSMakeSize(_cursorDim, _cursorDim);
// create and configure shape in order to create the cursor image
DKDrawableShape * s = [self objectFromPrototype];
[s setSize: cursorSize];
[s setStyle:[DKStyle defaultStyle]];
// create and return the cursor image based on the tool's shape
NSImage * i = [s swatchImageWithSize:cursorSize];
return i;
}
#pragma mark -
#pragma mark - As part of DKDrawingTool Protocol
+ (BOOL) toolPerformsUndoableAction
{
return YES;
}
- (NSString *) actionName
{
return @"object stamp";
}
- (NSCursor*) cursor
{
NSCursor * c = [[NSCursor alloc] initWithImage:[self cursorImage]
hotSpot:NSMakePoint(_cursorDim/2, _cursorDim/2)];
return c;
}
- (int) mouseDownAtPoint:(NSPoint) p targetObject:(DKDrawableObject*)
obj layer:(DKLayer*) layer event:(NSEvent*) event delegate:(id) aDel
{
// condition point p based on drawing snap settings
BOOL controlKey = ([event modifierFlags] & NSControlKeyMask) != 0;
p = [[layer drawing] snapToGrid:p withControlFlag:controlKey];
// create a size based on the ivar _cursorDim
NSSize objectSize = NSMakeSize(_cursorDim, _cursorDim);
// create and configure the tool's object
DKDrawableObject * objToInsert = [self objectFromPrototype];
[objToInsert setSize:objectSize];
[objToInsert setLocation:p];
// turn off recording of undo until we commit the object
[[layer undoManager] disableUndoRegistration];
// add the pending object
[(DKObjectOwnerLayer*)layer addObjectPendingCreation:objToInsert];
// if the object created is not valid, the pending add to the layer
needs to be
// aborted. Otherwise the object is committed to the layer
if (![objToInsert objectIsValid])
{
[(DKObjectOwnerLayer*)layer removePendingObject];
// turn undo back on
[[layer undoManager] enableUndoRegistration];
}
else
{
// a valid object was made, so commit it to the layer and select it
// turn undo back on and commit the object
[[layer undoManager] enableUndoRegistration];
[aDel toolWillPerformUndoableAction:self];
[(DKObjectDrawingLayer*)layer commitPendingObjectWithUndoActionName:
[self actionName]];
[(DKObjectDrawingLayer*)layer replaceSelectionWithObject:objToInsert];
}
// return value is the partcode of the target that was hit
// this tool does not operate on a target so return 0 (no object)
return 0;
}
- (void) mouseDraggedToPoint:(NSPoint) p partCode:(int) pc layer:
(DKLayer*) layer event:(NSEvent*) event delegate:(id) aDel
{
// dragging not supported by the stamp tool, so this method does
nothing
}
- (BOOL) mouseUpAtPoint:(NSPoint) p partCode:(int) pc layer:(DKLayer*)
layer event:(NSEvent*) event delegate:(id) aDel
{
// return value tells app if the tool did something undoable
return YES;
}
#pragma mark -
#pragma mark - As a DKObjectCreationTool
- (id) initWithPrototypeObject:(id <NSObject>) aPrototype
{
self = [super initWithPrototypeObject:aPrototype];
if (self != nil )
{
// set a default value for _cursorDim
[self setCursorDimension:50.0];
}
return self;
}
@end
Finally, for kicks and completeness here's the category on
DKShapeFactory that makes this "center mark" shape.
#import "DKShapeFactory+NewShapes.h"
@implementation DKShapeFactory (NewShapes)
+ (NSBezierPath *) centerMark
{
float radius = 0.25;
NSBezierPath * path = [NSBezierPath bezierPath];
[path setWindingRule: NSEvenOddWindingRule];
NSPoint pMiddle = NSMakePoint( 0.0, 0.0);
NSPoint pRight = NSMakePoint( radius, 0.0);
NSPoint pLeft = NSMakePoint(-radius, 0.0);
// add the cross
[path moveToPoint: NSMakePoint( 0, -0.5 )];
[path lineToPoint: NSMakePoint( 0, 0.5 )];
[path moveToPoint: NSMakePoint( -0.5, 0 )];
[path lineToPoint: NSMakePoint( 0.5, 0 )];
// add the circle
[path appendBezierPathWithArcWithCenter:pMiddle radius:radius
startAngle:0 endAngle:360 clockwise:NO];
// top right quadrant "hole"
[path moveToPoint: pMiddle];
[path lineToPoint: pRight];
[path appendBezierPathWithArcWithCenter: pMiddle radius: radius
startAngle: 0.0 endAngle: 90.0 ];
[path lineToPoint: pMiddle];
// bottom left quadrant "hole"
[path lineToPoint: pLeft];
[path appendBezierPathWithArcWithCenter: pMiddle radius: radius
startAngle: 180.0 endAngle: 270.0];
[path closePath];
return path;
}
@end
Have fun with it, and happy 2010 everyone.
-Allan
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.apptree.net/pipermail/drawkit-apptree.net/attachments/20091231/bc53091a/attachment-0001.htm>
More information about the Drawkit
mailing list