Sophie

Sophie

distrib > Mandriva > 10.0-com > i586 > by-pkgid > af7a4b7f1ee5a4a084c41b9005da5527 > files > 274

libfox1.1_46-devel-1.1.46-1mdk.i586.rpm

<html>
<head>
<link rel="stylesheet" href="page.css" type="text/css">
<title>Documentation: FOX Drag and Drop Facilities</title>
</head>
<body bgcolor=#ffffff link=#990033 vlink=#990033 alink=#990033 text=#000000>

<!---- TOPIC TITLE WITH LOGO--->
<table border=0 cellpadding= cellspacing=2 width=100% ><tr><td><a href='http://www.fox-toolkit.org' target=_top><img src='art/foxlogo_small.jpg' border=0></a></td><td width=100% valign=bottom id="HEADLINE"><b>
Documentation: FOX Drag and Drop Facilities <A href='draganddrop.html' target="_top" align=left><font  size=-2>[Remove Frame]</font></a>
<br><img src='art/line.gif' width=100% height=1></b></td></tr></table>
</p>
<!--- TOPIC TITLE WITH LOGO --->
<ul>
  <p>Drag and Drop refers to the facility in FOX that allows entities to
  be dragged not just from within one part of an application to another,
  but also <I>between applications.</I>&nbsp; The FOX Drag And Drop implementation
  is based on the&nbsp; <A HREF="http://www.newplanetsoftware.com/xdnd/">XDND
  Protocol</A>&nbsp; developed by John Lindal.&nbsp; As FOX provides fairly
  high-level API's to access these features, it is actually fairly easy to
  instrument your programs with a Drag &amp; Drop facility.</p>
  <p>For better understanding of how this works, it is important to define
  some terminology first:</p>
  <UL>
    <LI>A <B><I>Drag Source</I></B> is a FOX Widget capable of sourcing one or more types of drag and drop data or Drag Types.</LI>
    <LI>A <B><I>Drop Target</I></B> is a FOX Widget capable of accepting one or more types of Drag Types.</LI>
    <LI>A <B><I>Drag Type</I></B> is an abstract handle to a type of drag and drop data.</LI>
    <LI>A <B><I>Drag Action </I></B>determines what happens when a drop takes place; examples of drag actions are <I>copy</I>, <I>move</I>, and <I>link</I>.</LI>
  </UL>
  <p>As mentioned before, the Drag Source and the Drop Target may or may not
  be in the same application.&nbsp; In fact, their corresponding applications
  could even be running on different machines.&nbsp; We assume, of course,
  that both drag source and drop target are shown on the same display.</p>

</ul>


<!--- TOPIC TITLE -->
<p>
<table width=100% cellpadding=0 cellspacing=2><tr><td width=100% valign=bottom id=HEADLINE><b>
Registering Drag Types
<br><img src='art/line.gif' width=100% height=1></b></td></tr></table>
</p>
<!--- TOPIC TITLE -->
<ul>
  <p>In order to communicate a particular data structure across applications,
  both partners need to first register a <B>Drag Type</B>.&nbsp; The Drag
  Type is created by calling the function:</p>
<pre>
FXDragType FXApp::<B>registerDragType</B>(const FXString&amp; name) const;
</pre>

  <p>The registerDragType() function registers a new Drag Type "name" with the
  application's display, and returns an abstract handle to the Drag Type.&nbsp;
  The returned handle is used in all subsequent Drag and Drop operations.&nbsp;
  The Drag Type handle is unique for the display, that is, each application
  subsequently registering the same drag type name will receive the same
  handle.&nbsp; Obviously, the display must have been already opened before
  calling this function.</p>
  <p>It is strongly suggested that if your application intends to communicate
  with others, the Drag Type Names you use should be those of the corresponding
  <A HREF="ftp://ftp.isi.edu/in-notes/iana/assignments/media-types/">MIME
  types.</a>
  <BR>This guarantees everybody else's applications can make sense of drag
  data originating in your application [and vice versa].&nbsp; Otherwise,
  Drag Type Names can be any ASCII string sequence.</p>
  <P>A corresponding function:</P>

<pre>
FXString FXApp::<B>getDragTypeName</B>(FXDragType type) const;
</pre>

  <p>Will return the Drag Type Name, given the Drag Type.&nbsp; You may need
  to use this in case your application receives a drop of an unknown type,
  and you need to decide what to do with it.</p>

</ul>

<!--- TOPIC TITLE -->
<p>
<table width=100% cellpadding=0 cellspacing=2><tr><td width=100% valign=bottom id=HEADLINE><b>
Becoming A Drop Target
<br><img src='art/line.gif' width=100% height=1></b></td></tr></table>
</p>
<!--- TOPIC TITLE -->
<ul>
  <p>In order to be able to receive drops, a FOX Widget first needs to make
  itself a Drop Target.&nbsp; It does this by calling:</p>

<pre>
virtual void FXWindow::<B>dropEnable</B>();
</pre>

<p>To cancel drop-ability, use a function:</p>

<pre>
virtual void FXWindow::<B>dropDisable</B>();
</pre>

  <p>A Widget will not receive drag and drop messages unless it has been enabled
  as a drop target with dropEnable(). Note that the Widget may receive drag
  and drop messages with drop-data it does not understand, and thus it should
  only accept drops of the proper type.</p>

</ul>

<!--- TOPIC TITLE -->
<p>
<table width=100% cellpadding=0 cellspacing=2><tr><td width=100% valign=bottom id=HEADLINE><b>
Messages to the Drop Target
<br><img src='art/line.gif' width=100% height=1></b></td></tr></table>
</p>
<!--- TOPIC TITLE -->
<ul>
  <p>FOX Widgets which have have been enabled for Drop Targets may receive
  a number of messages during a drag-and-drop operation.&nbsp; To give a
  user feedback about what is going on, I suggest that the Widget somehow
  change its visual appearance based on receiving these messages.
  <p>For example, a Folder Icon, normally shown in the closed state, may
  be changed to the opened state to indicate that a drop is pending and will
  be accepted if performed.&nbsp; Another method [which is usually performed
  by the Drag Source Widget, see later], is to change the shape of the cursor
  to a STOP sign when the drop will NOT be accepted; one could also use a
  combination of the two methods.</p>
  <p>Drop Target Widgets may receive the following messages:</p>
  <UL>
  <LI>
  <B>SEL_DND_ENTER</B>.&nbsp; This message is received when the cursor first
  enters the Widget.&nbsp; At this point, the Widget may inspect the Drag
  Types available, and determine whether or not to accept a drop.&nbsp; If
  necessary, the Widget could even tentatively request the Drop Data, and
  inspect the data itself.&nbsp; It must be prepared to throw the data away
  again, however.</LI>

  <LI>
  <B>SEL_DND_LEAVE</B>.&nbsp; This message is received when the cursor leaves
  the Widget.&nbsp; If the Widget did not receive a SEL_DND_DROP before this
  message, it must release the data, if it has requested it.</LI>

  <LI>
  <B>SEL_DND_DROP</B>.&nbsp; The Widget receives this message when an actual
  drop takes place.&nbsp; Typically, the Widget requests the Drop Data at
  this point.</LI>

  <LI>
  <B>SEL_DND_MOTION</B>.&nbsp; This message indicates to the Widget the exact
  position of the cursor (and thus the Drop Point).&nbsp; Simple Widgets
  may not care about this, but more complicated Widgets will probably use
  the position to determine the exact action to take.&nbsp; For example,
  depending on position, the Widget may or may not accept certain Drop Types.</LI>
  </UL>

  <p>At any point between receiving SEL_DND_ENTER and SEL_DND_LEAVE /SEL_DND_DROP,
  the Drop Target may call the following functions to inquire about the type
  of the data being dragged, the data itself,&nbsp; and the drag-action being
  performed.&nbsp; Based on this information, it can feed back information
  to the Drag Source to indicate whether or not it will accept the data:</p>

<pre>
void FXWindow::<B>acceptDrop</B>(FXDragAction action=DRAG_ACCEPT);
</pre>

  <p>To accept or reject a drop, the Widget calls <B>acceptDrop</B>()
  with an argument specifying the <B>Drag Action</B> suggested by the Drop
  Target.&nbsp; The Widget can call this any number of times; however, the
  last value will be the one reported to the Drag Source Widget.&nbsp; For
  <B>acceptDrop(),</B> the following values are valid: </p>

  <UL>
  <LI>
  <B>DRAG_REJECT</B>. This indicates that the Drop Target will NOT
  accept any type of Drag Action.</LI>

  <LI>
  <B>DRAG_ACCEPT</B>. The Drop Target chooses to accept the drop, no
  matter what the Drag Action is.&nbsp; The suggested Drag Action is the
  same as the one supplied by the Drag Source.</LI>

  <LI>
  <B>DRAG_COPY</B>. The Drop Target accepts the drop, but suggests
  that the Drag Action be a <B><I>copy</I></B>.</LI>

  <LI>
  <B>DRAG_MOVE</B>. The Drop Target accepts the drop and suggests that
  the Drag Action be a <B><I>move</I></B>.</LI>

  <LI>
  <B>DRAG_LINK</B>. The Drop Target accepts the drop and suggests that the
  Drag Action be a <B><I>link</I></B>.</LI>
  </UL>

  <p>Other Drag Actions may be supported in the future.&nbsp; The Drop Target
  can find out the Drag Action by calling the following function:</p>

<pre>
FXDragAction FXWindow::<B>inquireDNDAction</B>() const;
</pre>

  <p>The Drag Source should change the cursor to reflect the Drag Action
  in effect; if necessary, the cursor should change to reflect the Drag Action
  suggested by the Drop Target.</p>

  <p>Normally, a Widget may get many, many SEL_DND_MOTION messages.&nbsp;
  In order to cut down on the traffic, a Drop Target Widget may indicate
  a rectangle and whether or not it wants further updates while the cursor
  is inside this rectangle by calling:</p>

<pre>
void FXWindow::<B>setDragRectangle</B>(FXint x,FXint y,FXint w,FXint h,FXbool wantupdates=TRUE);
</pre>

  <p>Widgets which do not care where the drop takes place may call setDragRectangle(0,0,width,height,FALSE),
  which will cause the Drag Source to send no further updates while the cursor is inside the Widget.</p>

<pre>
void FXWindow::<B>clearDragRectangle</B>();
</pre>

  <p>Clearly, this is the opposite of setDragRectangle().&nbsp; It is equivalent to setDragRectangle(0,0,0,0,TRUE);</p>

<pre>
FXbool FXWindow::<B>inquireDNDTypes</B>(FXDNDOrigin origin,const FXDragType*&amp; types,FXuint&amp; numtypes);
FXbool FXWindow::<B>offeredDNDType</B>(FXDNDOrigin origin,FXDragType type);</FONT></PRE>
</pre>

  <p>The first call yields an array of Drag Types currently available
  from the Drag Source.&nbsp; The list is <B><I>read-only,</I></B> and should
  NOT be freed.&nbsp; The Widget should <B>NOT</B> keep pointers to this
  list, as the list ceases to exist after SEL_DND_LEAVE.&nbsp; The second
  call tests to see if a certain Drag Type is being offered by the Drag Source.</p>
  <P><A NAME="GETDNDDATA"></A>If the Drag Type information is not enough,
  the Drop Target may have to inquire the actual data from the Drag Source
  and inspect it.&nbsp; It does this by calling:</p>

<pre>
FXbool FXWindow::<B>getDNDData</B>(FXDNDOrigin origin,FXDragType type,FXuchar*&amp; data,FXuint&amp; size);
</pre>

  <p>This call acquires the Drag Type type from the Drag Source.&nbsp; Upon
  return, data points to an array of bytes containing the Drop Data, and
  size is set to the number of bytes in the array.&nbsp; The array is now
  owned by the Drop Target Widget, and should be freed with the FXFREE()
  macro.&nbsp; The corresponding function in the Drag Source is describes
  <A HREF="draganddrop.html#SETDNDDATA">elsewhere</A>.&nbsp;
  The parameter <B><I>origin</I></B> should be set to <B>FROM_DRAGNDROP</B>.<p>

</ul>


<!--- TOPIC TITLE -->
<p>
<table width=100% cellpadding=0 cellspacing=2><tr><td width=100% valign=bottom id=HEADLINE><b>
Becoming a Drag Source
<br><img src='art/line.gif' width=100% height=1></b></td></tr></table>
</p>
<!--- TOPIC TITLE -->
<ul>
  <p>Making a Widget a Drag Source is comparatively easy.&nbsp; The transaction
  begins when the mouse button goes down.&nbsp; The Widget will need to call
  <B>grab()</B>
  to capture the mouse to the Widget, so that all future mouse events will
  be reported to the Widget, even if they occur outside of the Widget.
  Next, the Widget will call:</p>

<pre>
FXbool FXWindow::<B>beginDrag</B>(const FXDragType *types,FXuint numtypes);
</pre>

  <P>to start a drag-operation.&nbsp; The arguments to <B>beginDrag()
  </B>describe the list of types [which must have been registered previously]
  which are being offered.&nbsp; The Drag Source must be willing to furnish
  each of these types when requested by the Drop Target.&nbsp; The <B>beginDrag()</B>
  function returns FALSE if it failed to initiate a drag operation; the application
  should not proceed with dragging in this case.</p>
  <p>Upon each mouse movement, the Drag Source needs to indicate the new
  mouse position to the system; it also notifies the Drop Target of the new
  Drag Action.&nbsp; It does this by calling the function:</p>

<pre>
FXbool FXWindow::<B>handleDrag</B>(FXint x,FXint y,FXDragAction action=DRAG_COPY);
</pre>

  <p>The <B>handleDrag()</B> function determines the Widget under the
  cursor, and issues a SEL_DND_ENTER when it first enters a Widget, a SEL_DND_LEAVE
  when it leaves the Widget, and a SEL_DND_MOTION when the cursor simply
  has moved over the Widget [subject to the drag rectangle set by the Drop
  Target].&nbsp; It will not send any messages if the widget under the cursor
  has not called <B>dropEnable() </B>first to enable drops on it.<p>
  The <B>handleDrag() </B>function may return FALSE if it fails.&nbsp;
  To find out if a Drag Source is in the middle of a drag operation, applications
  may call the following member function:</p>

<pre>
FXbool FXWindow::<B>isDragging</B>() const;
</pre>

  <p>While the Drag Source is dragging, it may want to inquire whether the Drop
  Target's accepted or rejected a drop.&nbsp; It does this by calling:</p>

<pre>
FXDragAction FXWindow::<B>didAccept</B>() const;
</pre>

  <p>The function <B>didAccept()</B> simply returns DRAG_REJECT when the Drop
  Target would NOT accept the drop, and returns DRAG_COPY, DRAG_MOVE, DRAG_LINK
  if it did; the Drag Source should reflect the Drag Action returned by changing
  its cursor.
  For safety's sake, <B>didAccept() </B>will also returns DRAG_REJECT
  if the Drop Target has not called <B>dropEnable(),</B> or if the Drop Target
  fails to respond to any drag-and-drop messages.</p>

  <p>Applications may choose to change the cursor shape based on what didAccept()
  returned, as illustrated by the following code fragment:</p>

<pre>
handleDrag(event->root_x,event->root_y);

if(didAccept()!=DRAG_REJECT){
  setDragCursor(drop_ok_cursor);
  }
else{
  setDragCursor(drop_not_ok_cursor);
  }
</pre>

  <p>The rationale is that even though Drop Targets may give a visual cue when
  a drop is OK, not all applications running on your system may be drag-and-drop
  aware;&nbsp; changing the cursor also will give an additional clue.</p>
  <p>When the user releases the mouse button, the Widget needs to call ungrab()
  to release the mouse capture, and then calls:</p>

<pre>
  FXbool FXWindow::<B>endDrag</B>(FXbool drop=TRUE);
</pre>

  <p>This will cause a SEL_DND_DROP message to be sent to the Drop Target, if and only if:</p>

  <UL>
  <LI>The flag drop is TRUE.</LI>
  <LI>The Drop Target has previously called acceptDrop().</LI>
  <LI>The Drag Source has received status messages back from the Drop Target.</LI>
  </UL>

  <p>Passing a flag drop allows the Drag Source to deny a drop even though the
  Drop Target may have accepted a drop.&nbsp; The endDrag() function returns
  TRUE if a drop operation has actually taken place.</p>
</ul>

<!--- TOPIC TITLE -->
<p>
<table width=100% cellpadding=0 cellspacing=2><tr><td width=100% valign=bottom id=HEADLINE><b>
Messages to the Drag Source
<br><img src='art/line.gif' width=100% height=1></b></td></tr></table>
</p>
<!--- TOPIC TITLE -->
<ul>
  <p><A NAME="SETDNDDATA"></A>During a drag operation, a drag source may
  receive one or more requests for the drag data. These requests take
  the form of a SEL_DND_REQUEST message sent to the owner of the drag
  data. When a drag source receives a request for its data, it
  should first inspect the requested drag type, which is found in the FXEvent's
  <B><I>target</I></B> member variable. If the drag source can supply its
  data in the requested drag type, it should then allocate an array (using
  the FXMALLOC macro) and stuff the data into it.</p>

  <p>The drag source then calls</p>

<pre>
  FXbool FXWindow::<B>setDNDData</B>(FXDNDOrigin origin,FXDragType type,FXuchar* data,FXuint size);
</pre>

  <p>To hand the array over to the system. At this point, ownership of the
  array passes to the system, and the drag source should <B>not</B> attempt
  to make any further references to this array. The <b><i>origin</i></b> parameter
  should be set to FROM_DRAGNDROP.</p>
  <p>The drop target may make a request for the drag data from the drag
  source by calling getDNDData(), described <A HREF="draganddrop.html#GETDNDDATA">above</A>.</p>

</ul>


<!--- TOPIC TITLE -->
<p>
<table width=100% cellpadding=0 cellspacing=2><tr><td width=100% valign=bottom id=HEADLINE><b>
Drag and Drop of FOX Objects
<br><img src='art/line.gif' width=100% height=1></b></td></tr></table>
</p>
<!--- TOPIC TITLE -->
<ul>
  <p>The data exchange described above takes place using raw bytes.&nbsp;
  In more realistic cases,&nbsp; complicated data structures may have to
  be exchanges.&nbsp; It is important to realize that:</p>
  <UL>
  <LI>The Drag Source and Drop Target may be different programs.&nbsp; Thus, it is usually meaningless to exchange pointers to data structures.</LI>
  <LI>The Drop Target and Drag Source may not only be different programs, but also may be programs running on different machines with different byte orders and different word lengths.</LI>
  </UL>

  <P>FOX takes care of some of the latter troubles by furnishing special
  FOX primitive types, such as FXchar, FXshort, FXint and so on.&nbsp; A
  FOX implementation will ALWAYS make sure these types have the same size,
  although byte order may still be reversed on some machines.</p>
  <P>More sophisticated data transfers can be accomplished using the FOX <B>FXMemoryStream</B>
  class.&nbsp; The FXMemoryStream is a subclass of FXStream that serializes/deserializes
  data to/from a <B>memory-buffer.</B>&nbsp; The FXStream classes also support
  <I>byte swapping </I>on the reader side, making it very convenient to exchange
  data between hererogeneous machines; moreover, the FOX Stream classes support
  serialization of FOX Objects.</p>
  <p>Thus, entire networks of objects may be serialized, transmitted to
  the drop site, and then deserialized.</p>

  <P><B><U>Example</U></B>:
<P>Serialize into a buffer, then give the buffer to the DND system:
<BR>&nbsp;
<BLOCKQUOTE><FONT FACE="Courier New,Courier">FXMemoryStream str;</FONT>
<BR><FONT FACE="Courier New,Courier">FXuchar *buffer;</FONT>
<BR><FONT FACE="Courier New,Courier">FXuint size;</FONT>
<BR><FONT FACE="Courier New,Courier">FXObject *myobjectptr;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
// Pointer to the FXObject-derived object we wish to transfer</FONT>
<BR><FONT FACE="Courier New,Courier">FXuchar endianness;</FONT>
<P><FONT FACE="Courier New,Courier">endianness=FXStream::isLittleEndian();</FONT>
<P><FONT FACE="Courier New,Courier">str.open(NULL,FXStreamSave);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
// The FXMemoryStream will create its own buffer</FONT>
<BR><FONT FACE="Courier New,Courier">str &lt;&lt; endianness;</FONT>
<BR><FONT FACE="Courier New,Courier">str &lt;&lt; myobjectptr;</FONT>
<BR><FONT FACE="Courier New,Courier">str.takeBuffer(buffer,size);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
// Take ownership of the buffer away from the FXMemoryStream</FONT>
<BR><FONT FACE="Courier New,Courier">str.close();</FONT>
<BR><FONT FACE="Courier New,Courier">setDNDData(dndtype,buffer,size);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
// Give the buffer to the DND system</FONT></BLOCKQUOTE>

<P><BR>Take data from the DND system, then give the buffer to the Stream
and deserialize from it:
<BR>
<BR>
<BLOCKQUOTE><FONT FACE="Courier New,Courier">FXMemoryStream str;</FONT>
<BR><FONT FACE="Courier New,Courier">FXuchar *buffer;</FONT>
<BR><FONT FACE="Courier New,Courier">FXuint size;</FONT>
<BR><FONT FACE="Courier New,Courier">FXObject *myobjectptr;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
// When done, this points to an FXObject-derived object</FONT>
<BR><FONT FACE="Courier New,Courier">FXuchar endianness;</FONT>
<P><FONT FACE="Courier New,Courier">getDNDData(dndtype,buffer,size);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
// Take possesion of the buffer from the DND system</FONT>
<P><FONT FACE="Courier New,Courier">str.open(buffer,size,FXStreamLoad);</FONT>
<BR><FONT FACE="Courier New,Courier">str >> endianness;</FONT>
<BR><FONT FACE="Courier New,Courier">str.swapBytes(endianness!=FXStream::isLittleEndian());&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
// Swap bytes in the receiver if necessary!!</FONT>
<BR><FONT FACE="Courier New,Courier">str >> myobjectptr;</FONT>
<BR><FONT FACE="Courier New,Courier">str.close();</FONT>
<BR><FONT FACE="Courier New,Courier">FXFREE(&amp;buffer);</FONT>
<BR>&nbsp;</BLOCKQUOTE>
As you see, this is a mighty fine way to transfer arbitrary objects between
applications.&nbsp; All you have to do is derive certain objects from the
FXObject base class, then properly inplement the <B>load()</B> and <B>save()</B>
member functions for that class, so that all object member data may be
properly serialized or deserialized.&nbsp; For more info, see the chapter
on Serialization.



</ul>
<!--- TOPIC TITLE -->
<p>
<table width=100% cellpadding=0 cellspacing=2><tr><td width=100% valign=bottom id=HEADLINE><b>
Tips and Hints: Moving Data Between Applications
<br><img src='art/line.gif' width=100% height=1></b></td></tr></table>
</p>
<!--- TOPIC TITLE -->
<ul>
  <P>When data is being moved between applications, the Drop Target should
  perform the following sequence of operations:</p>
  <P>Acquire the dropped data, using <B>getDNDData(</B>), exactly the same
  as what it would do for a Copy Drag Action;</p>
  <P>Then do a <B>getDNDData(</B>) with the Drag Type DELETE, which must
  have been previously registered with <B>registerDragType("DELETE")</B>.</p>
  <P>The Drag Source will not supply any data when a request for the DELETE
  drag type is received; instead, knowing the data has been properly received
  by the Drop Target, it will delete the data instead.</p>
  <P>Thus, the getDNDData() call with Drag Type DELETE will yield a NULL
  data array pointer.</p>

</ul>


<!--- TOPIC TITLE -->
<p>
<table width=100% cellpadding=0 cellspacing=2><tr><td width=100% valign=bottom id=HEADLINE><b>
Tips and Hints: When to Copy and When to Move
<br><img src='art/line.gif' width=100% height=1></b></td></tr></table>
</p>
<!--- TOPIC TITLE -->
<ul>
  <p>This is no hard and fast rule, but generally speaking when data are
  being dragged <B>within</B> the same window, the default Drag Action should
  default to DRAG_MOVE, whereas when dragging <B>between</B> windows, the
  Drag Action should default to DRAG_COPY.&nbsp; These defaults can be overridden
  by holding down the Control-Key, which should force a DRAG_COPY, or the
  Shift-Key, which should force a DRAG_MOVE.&nbsp; Holding down the Alt-Key
  should probably force a DRAG_LINK.</p>
</ul>


<!--- TOPIC TITLE -->
<p>
<table width=100% cellpadding=0 cellspacing=2><tr><td width=100% valign=bottom id=HEADLINE><b>
Tips and Hints: When to Auto-Scroll
<br><img src='art/line.gif' width=100% height=1></b></td></tr></table>
</p>
<!--- TOPIC TITLE -->
<ul>
  <p>When dragging from within scrollable windows, no scrolling should take
  place while <B><I>outside</I></B> the window; instead, scrolling should
  happen <B><I>only</I></B> when the cursor is being moved very close to
  the window border.</p>
</ul>

<!--- TOPIC TITLE -->
<p>
<table width=100% cellpadding=0 cellspacing=2><tr><td width=100% valign=bottom id=HEADLINE><b>
Tips and Hints: Let Cursor Reflect the Action
<br><img src='art/line.gif' width=100% height=1></b></td></tr></table>
</p>
<!--- TOPIC TITLE -->
<ul>
  <p>There are two major schools of thought; some people prefer to let animate
  or highlight the drop-site to indicate an impending accept or reject of
  a drop, whereas others change the cursor instead.&nbsp; Apart from psychology,
  my take on this is do both:</p>
  <UL>
  <LI>Changing the cursor has the advantage that there is some feedback while moving over inert backgrounds.</LI>
  <LI>Changing the drop site has the advantage that it is very clear where the
  dropped data will wind up, especially if drop sites may be very small on
  the screen.</LI>
  </UL>

  <P>This reflects my view that in the software world, we can make our
  own rules;&nbsp; we can diverge from the physical model of ``manipulating
  rigid objects'' if this is appropriate or gives the user a better handle
  on things.</p>
</ul>

<!--- COPYRIGHT -->
<p>
<table width=100% cellpadding=0 cellspacing=0><tr><td width=100% valign=top id=HEADLINE align=right>
<img src='art/line.gif' width=100% height=1>
<font size=-1>Copyright &copy; 1997-2004 Jeroen van der Zijp</font>
</td></tr></table>
</p>
<!--- COPYRIGHT -->


</body>
</html>