<html>
<head>
  <title>Drag and Drop</title>
</head>
<body bgcolor="white" text="black">
<h1 align="center">Drag and Drop</h1>

<p>Most of the work here is based on the Acorn application note 241, which starts like this:</p>

<p><dfn>&quot;The goal of this protocol is to allow the user to copy and move data, both within and between applications, by direct manipulation. This means that the user should be able to make a selection in a document, pick the selected objects up with the mouse, drag them to their destination and release the mouse button. To facilitate precise positioning of the dragged objects, provision is made for the receiving task to display a ghost caret, which tracks the mouse pointer in the target window and indicates exactly where the data will be inserted. For text, the ghost caret should look similar to the normal Wimp caret, and as its follows the mouse pointer it should 'snap' to the nearest inter-character gap. The appearance of a ghost caret for non-textual selections will vary, but might typically be the bounding box of the dragged data, scaled according to the destination window's zoom factors.&quot;</dfn></p>

<p>The DragDrop protocol requires that you put <code>EMsg_Dragging</code> and <code>EMsg_DragClaim</code> in the list of messages accepted by your application. Even if your application don't do any dragging of data, it is still a good idea to support these messages as the task framework will change the pointer shape when another application drags data over the application to signal that any dropped data will be refused.</p>

<h2 align="left">Quick description of the DragDrop protocol</h2>

<p>You should really read app note 241 for the full details but basically let just say that the dragging task is just sending <code>EMsg_Dragging</code> messages to the window above which the pointer is standing with some info on the data such as possibly the size of the bounding box of the data in 1/72000 inches (sprites, drawfiles) and the filetypes in which the data can be provided.</p>

<p>The task under the pointer will then act on it and reply with a <code>EMsg_DragClaim</code> message. Why? The first reason is that the receiving task may change the pointer shape or ask the dragging task to hide the dragged box/sprite while it is showing a ghost caret. The second reason is to specify which of the proposed filetypes it supports and in what order of preference. But more important, if a window event handler will do things like showing a ghost caret in the window how does it know when it is time to remove it? Indeed, if the dragging task is just sending <code>EMsg_Dragging</code> messages to the window above which the pointer is standing we would get into trouble as soon as the pointer moves to another task. What actually occurs is that once a task replies a <code>EMsg_DragClaim</code> message the dragging task continues sending all its following <code>EMsg_Dragging</code> messages to that task until no <code>EMsg_DragClaim</code> message is replied. This way, the receiving task just checks if the <code>EMsg_Dragging</code> message still concerns it. In that case it updates its ghost caret and replies with a <code>EMsg_DragClaim</code> message. In the other case it removes its ghost caret and doesn't send a reply. Note that in the last case the dragging task may need to restore the pointer shape and its dragged box/sprite.</p>

<h2 align="left">Responding to <code>EMsg_Dragging</code> messages</h2>

<p>When the task framework receives such a message if will look over the usual chain of registered events handler (task preprocessing handlers, window handlers, task postprocessing handlers) until one reports that it as processed the event. If no handler processed the message the task framework will handle it itself by changing the mouse pointer to warn the user that we don't accept the data and by replying with a <code>EMsg_DragClaim</code> message warning the dragging task about that pointer change.</p>

<p>The problem with setting up a window event handler to process <code>EMsg_Dragging</code> messages is similar to when moving the pointer to another task, when the user moves the pointer to another window the task framework will just call the window handlers of that window and the ghost caret would remain visible in the old window. To go around this once the window claims the drag the framework needs to be notified to intercept the following <code>EMsg_Dragging</code> messages until one of them doesn't concern that window anymore, and that precisely what <code>DragDrop_SetOnDraggingCallback</code> does for you.</p>

<p>In your window event handler, you will add a section like the following one to the messages handling part:<p>

<pre><code>
case EMsg_Dragging: /* Drag &amp; drop Message_Dragging */
{
  /* If we accept the message, it notifies the framework that from now on
   * our callback handles the following EMsg_Dragging messages before the
   * normal event processing.
   */
  return DragDrop_SetOnDraggingCallback(prcv, MyDraggingCallback, pData);
}
break;
</code></pre>

<p>where prcv is the message received, pData a pointer to data relevant to this window and MyDraggingCallback a callback function that will typically look like this:</p>

<pre><code>
bool MyDraggingCallback(const Msg_Dragging* prcv, void* handle)
{
  CMyStruct*    pData = handle;
  bool          bMove;

  /* First check if we should claim the drag:
   * is the pointer still on our window?
   * is the message not to be claimed?
   *    (sent in case of dragging abort so that we can hide the gost caret)
   * are we able to load any of the proposed filetypes?
   *    (if not we let the task framework deal with the message)
   */
  if ((prcv-&gt;pos.w != pData-&gt;mywindow)
  ||  (prcv-&gt;flags &amp; Drag_DoNotClaim)
  ||  (DragDrop_GetFileType(prcv-&gt;types, SupportedFileTypes) == -1))
  {
    /* Drag not claimed, Hide ghost caret */
    ...
    return false;
  }

  /* Move or copy data?
   * If the user is dragging data from this window Move, otherwise Copy.
   * The framework make us specify a user handle (like pData) for dragging
   * so that we can identify the origin of the data dragged around.
   * For a drag from another task it will return NULL.
   */
  bMove = (DragDrop_GetUserHandle() == pData);

  /* Test the shift key to invert Move and Copy. */
  bMove ^= Keyboard_PollShift();

  if (bMove)
    Desktop_SetPointer(&quot;ptr_move&quot;);
  else
    Desktop_SetPointer(&quot;ptr_copy&quot;);

  /* Show ghost caret */
  ...

  /* Scroll window if pointer is near the window borders */
  Window_ScrollIfMouseOnBorder(pData-&gt;mywindow, x scroll step, y scroll step);

  /* Reply to message */
  flags = Claim_PointerChange | Claim_RemoveDragBox;
  if (bMove) flags |= Claim_DeleteSource;

  DragDrop_ReplyToDragging(prcv, flags, SupportedFileTypes);

  return true;
}
</code></pre>

<p>The callback will be called a first time from within <code>DragDrop_SetOnDraggingCallback</code> and then anytime the task framework calls <code>DragDrop_CallDraggingCallback</code> until the callback returns false in which case the framework reverts to it's usual event processing.</p>

<p>As you can see from the above code, the dragging task will send you an <code>EMsg_Dragging</code> message with the flag <code>Drag_DoNotClaim</code> if the drag is aborted so that you can remove your ghost caret. But what occurs when the drag succeeds? Well, the dragging task will send a <code>EMsg_DataSave</code> message with the reference of your last <code>EMsg_DragClaim</code> message and the task framework will call the callback with a fake <code>EMsg_Dragging</code> message using the flag <code>Drag_DoNotClaim</code> so that the ghost caret can be removed, then it will process the <code>EMsg_DataSave</code> message normally.</p>

<p>The library comes with 4 sprites to help you handle dragging:</p>

<ul>
  <li>'ptr_drag' is the default pointer to use during dragging when the task below the pointer doesn't respond to the DragDrop protocol. The pointer shows dragging arrows and a '?' because dropping the data onto that task will accept or not the data.</li>
  <li>'ptr_nodrop' is the default pointer showed by the task framework to signal that the data will not be accepted if dropped on the application.</li>
  <li>'ptr_copy' and 'ptr_move' should be showed to signal that the data will be accepted if dropped and whether the data will be just copied or moved.</li>
</ul>

<h2 align="left">Dragging data around, other forms of dragging</h2>

<p>The most complex form of dragging is the one handled by the Drag and Drop protocol, dragging of data between applications, but that doesn't mean that it is the only one nor the most common. How often do you drag the caret to select text, a rubber box to select files or drag a slider?</p>

<p>All these drags share a common process of starting the drag, polling the wimp and releasing/aborting the drag which is handled by a single but complex core function <code>DragDrop_DragLoop</code> which serves as building stone for every dragging function offered by the library and for any extra dragging function that a task could require.</p>

<p>The library offers the more common forms drags regrouped in 3 categories:</p>

<ul>
  <li>Draggings of data that use Dragging/DragClaim messages to provide feedback to the user:
    <ul>
      <li>DragDrop_DragFile to drag a filetype icon around the desktop.</li>
    </ul>
  </li>
  <li>Internal draggings that use Dragging/DragClaim messages to provide feedback to the user ('ptr_nodrop' is shown when the pointer stands above other tasks):
    <ul>
      <li>ActiveDrag_DragPoint, drags an invisible point around the desktop.</li>
      <li>ActiveDrag_DragSprite, drags a sprite around the desktop.</li>
    </ul>
  </li>
  <li>Draggings that just call a function on wimp poll null events, like when making a selection or using a slider:
    <ul>
      <li>Drag_DragPoint to drag an invisible point within a given bounding box. The function of type DragDrop_NullEvent passed as parameter is called regularely during wimp poll null events..</li>
    </ul>
  </li>
</ul>

<p>The functions of the last dragging category only returns true on exit unless the dragging was aborted (the user pressed the 'Esc' key) while the other returns the every information necessary for a data transfer in the form of the following data structure:</p>

<pre><code>
typedef struct DragDrop_Info
{
	HTask			task;
	int			msg_ref;
	DragDrop_ClaimFlags	flags;
	file_type		type;
} DragDrop_Info;
</code></pre>

<p>The structure should be checked as follow:</p>
<ul>
  <li>The dragging was aborted:
    <br>task = 0
  </li>
  <li>The last EMsg_Dragging message wasn't claimed:
    <br>task = your task id
    <br>msgref = 0
    <br>flags = 0
    <br>type = the first file type in your list
    <br>This case doesn't mean that the task below the pointer will refuse the data, only that the task isn't aware of the protocol and you should initiate the usual data transfer protocol with a EMsg_DataSave message sent to the window under the pointer.
  </li>
  <li>The last EMsg_Dragging message was claimed:
    <br>task = the claimant's task id
    <br>msg_ref = the claimant's EMsg_DragClaim message id
    <br>flags = the claimant flags (only Drag_DeleteSource is useful)
    <br>type = the first file type supported by the claimant and you (if none, the first file type in your list)
    <br>This case means that the claimant below the pointer expects you to initiate the data transfer protocol with a EMsg_DataSave message sent to it using msg_ref as a reference (if you fail to do so the claimant will not know that he may remove its ghost caret).
  </li>
</ul>

<p>If you wishes to call <code>XFer_Send</code> on exit of such draggings, the function <code>DragDrop_Send</code> will perform all the necessary checks on these structure and call <code>XFer_Send</code> for you.</p>
</body>
</html>