Skip to main content
Engineering LibreTexts

13.7: Drag-and-Drop

  • Page ID
    43176
    \( \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}}\)\(\newcommand{\AA}{\unicode[.8,0]{x212B}}\)

    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.

    Let’s first define the receiver morph:

    Morph subclass: #ReceiverMorph
        instanceVariableNames: ''
        classVariableNames: ''
        package: 'PBE-Morphic'
    

    Now define the initialization method in the usual way:

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

    How do we decide if the receiver morph will accept or reject the dropped morph? In general, both of the morphs will have to agree to the interaction.

    A ReceiverMorph and an EllipseMorph.
    Figure \(\PageIndex{1}\): A ReceiverMorph and an EllipseMorph.

    The receiver does this by responding to wantsDroppedMorph:event:. Its 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, by responding to the message wantsToBeDroppedInto:. The default implementation of this method (in class Morph) answers true.

    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:

    ReceiverMorph >> repelsMorph: aMorph event: anEvent
        ^ (self wantsDroppedMorph: aMorph event: anEvent) not
    

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

    Create instances of ReceiverMorph and EllipseMorph in a playground:

    ReceiverMorph new openInWorld;
        bounds: (100@100 corner: 200@200).
    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.

    To change this behaviour, change the color of the ellipse morph to the color blue (by sending it the message color: Color blue; right after new). 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:

    Morph subclass: #DroppedMorph
        instanceVariableNames: ''
        classVariableNames: ''
        package: 'PBE-Morphic'
    
    DroppedMorph >> initialize
        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:

    DroppedMorph >> rejectDropMorphEvent: anEvent
        |h|
        h := anEvent hand.
        WorldState 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.

    Create two instances of DroppedMorph, and then drag and drop them onto the receiver.

    ReceiverMorph new openInWorld.
        morph := (DroppedMorph new color: Color blue) openInWorld.
        morph position: (morph position + (70@0)).
        (DroppedMorph new color: Color green) openInWorld.
    
    Creation of DroppedMorph and ReceiverMorph.
    Figure \(\PageIndex{2}\): Creation of DroppedMorph and ReceiverMorph.

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


    This page titled 13.7: Drag-and-Drop is shared under a CC BY-SA 3.0 license and was authored, remixed, and/or curated by via source content that was edited to the style and standards of the LibreTexts platform; a detailed edit history is available upon request.