Search code examples
drag-and-dropsmalltalksqueakmorphic

Which methods must I override to enable drag&drop in Squeak?


I have a big morph with dozens of submorphs. The submorphs are of two kinds: pieces and squares.

I have googled a lot and read quite a bit of Morphic documentation, but somehow I can’t get it to work. I have not yet found a document that clearly explains what to do.

Currently, the pieces won’t be dragged (except when I Alt-click on them). The squares have implemented the mouseEnterDragging and mouseLeaveDragging methods and they are being called (they change the color of the squares, so it’s easy to spot). But it’s like something invisible is being dragged.

What I want: the pieces should be draggable, just by holding down the left mouse button and moving the mouse, not by using Alt-click to bring up the halo. The squares should not be draggable. The pieces should be droppable on squares, but not on pieces.

Which methods should I implement/override?


Solution

  • Starting with a mouseDown: event, the hand can then observe the following mouseMove: or mouseUp: events to give the interested morph a callback about click, double-click, or start-drag.

    So, your to-be-dragged morph should implement handlesMouseDown: and mouseDown: and in the latter send waitForClicksOrDrag:event: to the hand, which is in the event you get as argument in mouseDown:.

    You may refine the callback via waitForClicksOrDrag:event:selectors:threshold: but the default callbacks are click:, doubleClick:, doubleClickTimeout:, and startDrag:.

    A simple way to implement a startDrag: (or similar) is event hand grabMorph: self.

    Then, for the dropping, there is a simple handshake via wantsDroppedMorph:event: and wantsToBeDroppedInto: and finally acceptDroppingMorph:event:. Those are simply configured via dropEnabled. You can but you don't have to use (i.e., drag-and-drop) the surrogate TransferMorph.

    You can read more about the mechanism by reading the following source code (and other senders/implementors) in the image:

    • HandMorph >> #waitForClicksOrDrag:event:
    • Morph >> #startDrag:
    • Morph >> #handleDropMorph:

    Besides implementing stuff in a subclass of Morph, you can also script it from the outside via eventHandler:

    m := Morph new.
    m eventHandler: EventHandler new.
    m eventHandler handlesClickOrDrag: true.
    m on: #startDrag send: #value:value: to: [:event :source |
        Transcript showln: 'drag start'.
        event hand grabMorph: source].
    m openInHand.
    

    This will free you from having to bother with waitForClicksOrDrag:event:.

    Hope this helps! Happy Squeaking. :-)