• Open Menu Close Menu
  • Apple
  • Shopping Bag
  • Apple
  • Mac
  • iPad
  • iPhone
  • Watch
  • TV
  • Music
  • Support
  • Search apple.com
  • Shopping Bag

Lists

Open Menu Close Menu
  • Terms and Conditions
  • Lists hosted on this site
  • Email the Postmaster
  • Tips for posting to public mailing lists
re: allow user to drag controls to make their own interface (EXAMPLE)
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

re: allow user to drag controls to make their own interface (EXAMPLE)


  • Subject: re: allow user to drag controls to make their own interface (EXAMPLE)
  • From: Mark Onyschuk <email@hidden>
  • Date: Thu, 15 Apr 2004 18:08:57 -0400

Here is a quick and dirty example I whipped up of a palette view containing subviews which can be dragged around. A sample project containing this code (and some draggy color wells, sliders, etc :-) can be found at:

http://www.voxsoftware.com/Examples/DraggableViews.zip


Here's the concept:

** Take a view and populate it with subviews in IB.

** On awakeFromNib, this view creates an image of each of its subviews then removes them from the view hierarchy, while keeping a private array of these subviews in the background.

** On mouseDown:, the view consults its private array of views and their frames, and performs a drag if a hit is detected. My example could be extended to initiate a drag-and-drop operation where the view to be dragged is archived with NSArchiver and put on the dragging pasteboard.

** On drawRect:, the view runs through its list of view images and draws them at each view's frame position.

Note that the code I use to image widgets only works for non-compound widgets (ie, widgets which themselves have no subviews). I believe that OmniAppKit has a method which can image a view and all of its subviews into an image...

The code follows:

@implementation PaletteView

- (void)dealloc
{
[subviewObjects release];
[subviewImages release];

[super dealloc];
}

- (void)awakeFromNib
{
int i, count;
subviewObjects = [[self subviews] mutableCopyWithZone:[self zone]];
subviewImages = [[NSMutableArray allocWithZone:[self zone]] init];

// take a snapshot of each
for (i = 0, count = [subviewObjects count]; i < count; i++) {
NSView *view = [subviewObjects objectAtIndex:i];
NSImage *image = [[[NSImage allocWithZone:[self zone]] initWithSize:[view bounds].size] autorelease];

[image setFlipped:[view isFlipped]];

[image lockFocus];
[view drawRect:[view bounds]];
[image unlockFocus];

[subviewImages addObject:image];
}

// remove all subviews (we've retained them above)
[subviewObjects makeObjectsPerformSelector:@selector(removeFromSuperview)];
}


- (NSView *)viewAtPoint:(NSPoint)aPoint
{
int i, count;
for (i = 0, count = [subviewObjects count]; i < count; i++) {
NSView *view = [subviewObjects objectAtIndex:i];
if (NSPointInRect(aPoint, [view frame])) {
return view;
}
}
return nil;
}

- (void)mouseDown:(NSEvent *)theEvent
{
NSView *view = [self viewAtPoint:[self convertPoint:[theEvent locationInWindow] fromView:nil]];

if (view) {
[self dragImageOfView:view withEvent:theEvent];
}
}

- (void)dragImageOfView:(NSView *)aView withEvent:(NSEvent *)theEvent
{
NSPoint location = [self convertPoint:[theEvent locationInWindow] fromView:nil];

while (1) {
NSEvent *nextEvent = [[self window] nextEventMatchingMask:NSLeftMouseUpMask|NSLeftMouseDraggedMask];
NSPoint nextLocation = [self convertPoint:[nextEvent locationInWindow] fromView:nil];

if ([nextEvent type] == NSLeftMouseUp) {
break;
}

float dx = nextLocation.x - location.x;
float dy = nextLocation.y - location.y;

NSRect viewFrame = [aView frame];
viewFrame.origin.x += dx;
viewFrame.origin.y += dy;
[aView setFrame:viewFrame];

[self display];

location = nextLocation;
}
}

- (void)drawRect:(NSRect)aRect
{
int i, count;
for (i = 0, count = [subviewObjects count]; i < count; i++) {
NSView *view = [subviewObjects objectAtIndex:i];
NSImage *image = [subviewImages objectAtIndex:i];

[image drawInRect:[view frame]
fromRect:NSZeroRect
operation:NSCompositeSourceOver
fraction:1];
}
}

@end

Resizing of views is left as an exercise for the reader :-) but it involves re-caching the view image as it is resized (and of course the actual logic of resizing a rect based on user gestures).

The complimentary view - the drag destination - can be coded in a similar way. When users want to go into "run" mode, then images are replaced with their actual object equivalents. In design mode, they're switched back to their images. Using images instead of the real things inside your canvas allows you do do things like draw "knobs" around selected widgets without the hassle of view layering obscuring what you're drawing...

-Mark
_______________________________________________
cocoa-dev mailing list | email@hidden
Help/Unsubscribe/Archives: http://www.lists.apple.com/mailman/listinfo/cocoa-dev
Do not post admin requests to the list. They will be ignored.


  • Prev by Date: Re: accessing newly-created files
  • Next by Date: Re: accessing newly-created files
  • Previous by thread: Re: HotKey contains click
  • Next by thread: Getting PDF and/or EPS data
  • Index(es):
    • Date
    • Thread