Skip to main content
Engineering LibreTexts

11.7: Drag-and-Drop

  • Page ID
  • \( \newcommand{\vecs}[1]{\overset { \scriptstyle \rightharpoonup} {\mathbf{#1}} } \) \( \newcommand{\vecd}[1]{\overset{-\!-\!\rightharpoonup}{\vphantom{a}\smash {#1}}} \)\(\newcommand{\id}{\mathrm{id}}\) \( \newcommand{\Span}{\mathrm{span}}\) \( \newcommand{\kernel}{\mathrm{null}\,}\) \( \newcommand{\range}{\mathrm{range}\,}\) \( \newcommand{\RealPart}{\mathrm{Re}}\) \( \newcommand{\ImaginaryPart}{\mathrm{Im}}\) \( \newcommand{\Argument}{\mathrm{Arg}}\) \( \newcommand{\norm}[1]{\| #1 \|}\) \( \newcommand{\inner}[2]{\langle #1, #2 \rangle}\) \( \newcommand{\Span}{\mathrm{span}}\) \(\newcommand{\id}{\mathrm{id}}\) \( \newcommand{\Span}{\mathrm{span}}\) \( \newcommand{\kernel}{\mathrm{null}\,}\) \( \newcommand{\range}{\mathrm{range}\,}\) \( \newcommand{\RealPart}{\mathrm{Re}}\) \( \newcommand{\ImaginaryPart}{\mathrm{Im}}\) \( \newcommand{\Argument}{\mathrm{Arg}}\) \( \newcommand{\norm}[1]{\| #1 \|}\) \( \newcommand{\inner}[2]{\langle #1, #2 \rangle}\) \( \newcommand{\Span}{\mathrm{span}}\)

    Morphic also supports drag-and-drop. Let’s examine a simple example with two morphs, a receiver morph and a dropped morph. The receiver will accept a morph only if the dropped morph matches a given condition: in our example, the morph should be blue. If it is rejected, the dropped morph decides what to do.

    \(\bigstar\) Let’s first define the receiver morph:

    Code \(\PageIndex{1}\) (Squeak): Defining a Morph on Which We Can Drop Other Morphs

    Morph subclass: #ReceiverMorph
        instanceVariableNames: ''
        classVariableNames: ''
        poolDictionaries: ''
        category: 'SBE-Morphic'

    \(\bigstar\) Now define the initialization method in the usual way:

    Code \(\PageIndex{2}\) (Squeak): Initializing ReceiverMorph

        super initialize.
        color := Color red.
        bounds := 0 @ 0 extent: 200 @ 200

    How do we decide if the receiver morph will accept or repel the dropped morph? In general, both of the morphs will have to agree to the interaction. The receiver does this by responding to wantsDroppedMorph:event:; the first argument is the dropped morph, and the second the mouse event, so that the receiver can, for example, see if any modifier keys were held down at the time of the drop. The dropped morph is also given the opportunity to check and see if it likes the morph onto which it is being dropped; it is sent the message wantsToBeDroppedInto:. The default implementation of this method (in class Morph) answers true.

    Code \(\PageIndex{3}\) (Squeak): Accept Dropped Morphs Based on Their Color

    ReceiverMorph»wantsDroppedMorph: aMorph event: anEvent
        ↑ aMorph color = Color blue

    What happens to the dropped morph if the receiving morph doesn’t want it? The default behaviour is for it to do nothing, that is, to sit on top of the receiving morph, but without interacting with it. A more intuitive behavior is for the dropped morph to go back to its original position. This can be achieved by the receiver answering true to the message repelsMorph:event: when it doesn’t want the dropped morph:

    Code \(\PageIndex{4}\) (Squeak): Changing the Behaviour of the Dropped Morph When It Is Rejected

    ReceiverMorph»repelsMorph: aMorph event: ev
        ↑ (self wantsDroppedMorph: aMorph event: ev) not

    That’s all we need as far as the receiver is concerned.

    \(\bigstar\) Create instances of ReceiverMorph and EllipseMorph in a workspace:

    ReceiverMorph new openInWorld.
    EllipseMorph new openInWorld.

    Try to drag-and-drop the yellow EllipseMorph onto the receiver. It will be rejected and sent back to its initial position.

    \(\bigstar\) To change this behaviour, change the color of the ellipse morph to Color blue using an inspector. Blue morphs should be accepted by the ReceiverMorph.

    Let’s create a specific subclass of Morph, named DroppedMorph, so we can experiment a bit more:

    Code \(\PageIndex{5}\) (Squeak): Defining a Morph We Can Drag-and-Drop onto ReceiverMorph

    Morph subclass: #DroppedMorph
        instanceVariableNames: ''
        classVariableNames: ''
        poolDictionaries: ''
        category: 'SBE-Morphic'

    Code \(\PageIndex{6}\) (Squeak): Initializing DroppedMorph

        super initialize.
        color := Color blue.
        self position: 250@100

    Now we can specify what the dropped morph should do when it is rejected by the receiver; here it will stay attached to the mouse pointer:

    Code \(\PageIndex{7}\) (Squeak): Reacting When the Morph Was Dropped but Rejected

    DroppedMorph»rejectDropMorphEvent: anEvent
        h := anEvent hand.
            addDeferredUIMessage: [h grabMorph: self].
        anEvent wasHandled: true

    Sending the hand message to an event answers the hand, an instance of HandMorph that represents the mouse pointer and whatever it holds. Here we tell the World that the hand should grab self, the rejected morph.

    \(\bigstar\) Create two instances of DroppedMorph, and then drag-and-drop them onto the receiver.

    ReceiverMorph new openInWorld.
    (DroppedMorph new color: Color blue) openInWorld.
    (DroppedMorph new color: Color green) openInWorld.

    The green morph is rejected and therefore stays attached to the mouse pointer.

    This page titled 11.7: Drag-and-Drop is shared under a CC BY-SA 3.0 license and was authored, remixed, and/or curated by Andrew P. Black, Stéphane Ducasse, Oscar Nierstrasz, Damien Pollet via source content that was edited to the style and standards of the LibreTexts platform; a detailed edit history is available upon request.