Path: utzoo!attcan!uunet!aplcen!uakari.primate.wisc.edu!sdd.hp.com!ucsd!ucbvax!agate!shelby!portia.stanford.edu!jessica.stanford.edu!duggie From: duggie@jessica.stanford.edu (Doug Felt) Newsgroups: comp.sys.next Subject: Re: dragging an image from a button Message-ID: <1990Jul2.233503.7154@portia.Stanford.EDU> Date: 2 Jul 90 23:35:03 GMT References: <3645@calvin.cs.mcgill.ca> Sender: news@portia.Stanford.EDU (USENET News System) Organization: Academic Information Resources Lines: 178 In article <3645@calvin.cs.mcgill.ca> pegasus@quiche.cs.mcgill.ca (PROVOST philippe) writes: > >greetings, > >does anyone know how to "drag an image from a button" , ie, when you select >the button with a mouse, how to move the "picture" representing the object (being >created) from the button to the document. For instance, IB do this operation >when you select a button, window....in the Palettes Window and drag that tool to >the document you define. > >Help greatly appreciated. What you do is create a window where the object was, make it look like the object, and drag that. When you release the window, you create a new object where the window was released. Many months ago, playing around with this, I wrote a View subclass which does this for its subviews. That is, when you click in this view, it hit tests against its subviews to see whether one was hit. If one was, it creates a window of the same size and in the same (screen) position as the view, clones the view and installs it in the window, then calls the window method dragFrom::eventNum: to let the user drag the window. After the window is released, it checks to see what window and view it was on top of, and whether the view understands what to do with a new view. If it does then it sends the receiving view a message with the cloned view as a parameter. The receiving view cleans up. The nice thing about this technique is that the views that get dragged don't have to be subclasses of anything in particular, and the receiving view just has to understand the message used to pass it a new view. There are some caveats. I don't use a window delegate to receive notification when the dragFrom::eventNum: method returns, because, unfortunately, a windowDidMove: message never gets sent if the user never actually moves the window. Fortunately, dragFrom::eventNum: is modal and won't return until the window is dropped. If the window gets 'dropped' over the deskTop, PSfindwindow will return the majik number 14, which you need to check for because NXConvertGlobalToWinNum will gag on this. So this may not be compatible with future releases. Have fun. Doug Felt Following is the (slightly messy) relevant code: --------------------------- ( view that receives ) ----------------------- - acceptNewView: aView { [self addSubview: aView]; [aView display]; [window flushWindow]; NXPing(); return self; } ------------- ( view that allows its subviews to be dragged ) ------------ /* * we want the hitTest: message */ - (BOOL)acceptsFirstMouse { return YES; } /* * override default so subviews don't get a chance to respond */ - hitTest:(NXPoint *)pt { if (NXPointInRect(pt,&frame)) return self; return nil; } /* * point is in window coordinates. return the view to clone, or nil. */ - getSelectedView:(const NXPoint *)pt { int i; NXPoint loc; NXRect r; View *v; loc = *pt; [self convertPoint: &loc fromView: nil]; for (i=[subviews count]; i--;) { v = [subviews objectAt: i]; [v getFrame: &r]; if (NXPointInRect(&loc,&r)) return v; } return nil; } /* * clone this view and return the clone */ - cloneView: aView { char * buf; int length; View *newView; buf = NXWriteRootObjectToBuffer(aView,&length); newView = NXReadObjectFromBuffer(buf,length); NXFreeObjectBuffer(buf,length); return newView; } - mouseDown:(NXEvent *)event { DragView *dv; int found; int gwnum; NXPoint loc; NXRect r; NXSize siz; SwallowView *sv; View *tv; View *v; Window *w; Window *wf; unsigned int wnum; if (event->data.mouse.click > 1) return self; v = [self getSelectedView: &event->location]; if (v == nil) return self; [v getBounds: &r]; [v convertRect: &r toView:nil]; [window convertBaseToScreen: (NXPoint *)&r]; w = [Window newContent: &r style: NX_PLAINSTYLE backing: NX_RETAINED buttonMask: 0 defer: NO]; dv = [self cloneView: v]; [[w setContentView: dv] free]; [w display]; [w orderFront: self]; loc = event->location; [window convertBaseToScreen: &loc]; [w convertScreenToBase: &loc]; [w dragFrom: loc.x : loc.y eventNum: event->data.mouse.eventNum]; PScurrentwindowbounds([w windowNum],&loc.x,&loc.y,&siz.width,&siz.height); PSfindwindow(loc.x,loc.y,NX_BELOW,event->window,&loc.x,&loc.y,&gwnum,&found); if (found && (gwnum != 14)) { /* ugly */ NXConvertGlobalToWinNum(gwnum,&wnum); wf = [NXApp findWindow: wnum]; if (wf != nil) { sv = [[wf contentView] hitTest: &loc]; if ([sv respondsTo: @selector(acceptNewView:)]) { [sv convertPoint: &loc fromView: nil]; [w setContentView: nil]; [dv moveTo: loc.x : loc.y]; [sv acceptNewView: dv]; } } } [w free]; return self; }