Programming in XPCE/Prolog: Section 11.8

## 11.8 Drag and drop interface

XPCE's drag-and-drop interface allows the user to drag-and-drop graphical objects and dict_item objects. Drag-and-drop is a common GUI technique to specify operations that require two objects in a specific order. Moving files to another directory by dragging them to the icon of the target directory is a common example.

It may also be used to specify operations on a single object, where the operation is represented by an icon. Dragging files to a trash-bin is the most commonly found example.

For the drag-and-drop interface to work, the programmer must connect a drag_and_drop_gesture to the object to be dragged.12Attach a drag_and_drop_dict_item_gesture to a list_browser to enable dragging the items in the dictionary. A Drop-zone defines the method `->`drop and (not strictly obligatory) `->`preview_drop. `->`drop is called to actually perform the associated operation, while `->`preview_drop may be used to indicate what will happen if the object is dropped now.

Below is a complete example that allows the user to drag objects for moving and copying on another window.

Class drop_picture defines a graphical window that imports graphical objects when they are dropped onto it. The feedback is a dotted rectangle indicating the area of the graphical to be imported. See `graphical `->`preview_drop' for a description of the arguments.

    :- pce_begin_class(drop_picture, picture).

    preview_drop(P, Gr:graphical*, Pos:[point]) :->
            (   Gr == @nil                  % pointer leaves area
            ->  (   get(P, attribute, drop_outline, OL)
                ->  send(OL, free),
                    send(P, delete_attribute, drop_outline)
                ;   true
                )
            ;   (   get(P, attribute, drop_outline, OL)
                ->  send(OL, position, Pos)
                ;   get(Gr?area, size, size(W, H)),
                    new(OL, box(W, H)),
                    send(OL, texture, dotted),
                    send(P, display, OL, Pos),
                    send(P, attribute, drop_outline, OL)
                )
            ).

The method `->`drop. If the graphical originates from the same picture just move it. Otherwise `<-`clone the graphical and display the clone.

    drop(P, Gr:graphical, Pos:point) :->
            (   get(Gr, device, P)
            ->  send(Gr, position, Pos)
            ;   get(Gr, clone, Gr2),
                send(P, display, Gr2, Pos)
            ).

    :- pce_end_class.

Class dragbox defines a simple subclass of class box that can be resized and dragged.

    :- pce_begin_class(dragbox, box).

    :- pce_autoload(drag_and_drop_gesture, library(dragdrop)).
    :- pce_global(@dragbox_recogniser, make_dragbox_recogniser).

    make_dragbox_recogniser(G) :-
            new(G, handler_group(resize_gesture(left),
                                 drag_and_drop_gesture(left))).

    event(B, Ev:event) :->
            (   send(B, send_super, event, Ev)
            ;   send(@dragbox_recogniser, event, Ev)
            ).

    :- pce_end_class.

The toplevel predicate creates two drop_pictures in one frame (note that drag-and-drop-gestures work accross frames, but not accross multiple XPCE processes at the moment). It displays one dragbox in one of the windows. Dragging it inside a picture moves the box, dragging it to the other windows makes a copy of the box.

    dragdropdemo :-
            new(F, frame('Drag and Drop Demo')),
            send(F, append, new(P1, drop_picture)),
            send(new(drop_picture), right, P1),
            send(P1, display, dragbox(100, 50), point(20,20)),
            send(F, open).

### 11.8.1 Related methods

drag_and_drop_gesture ->initialise: Button, Modifier, Warp, GetSource
  Initialises a new drag_and_drop_gesture. Button is the name of the pointer-button the gesture should be connected to (left, middle or right). Modifier is a modifier description (see class modifier). Warp is for compatibility with older releases of this library. GetSource is a function used to fetch the object dragged from the graphical representing it. Suppose the graphical to which the gesture is attached represents a database record. In this case it is much more natural to pass the identifier for the database record to the `->`drop and `->`preview_drop methods than to pass the icon representing it. GetSource is a function that is evaluated with @arg1 bound to the graphical when the gesture is activated. An example could be:

      drag_and_drop_gesture(left,
                            get_source :=
                                   @arg1?db_record)

graphical ->drop: Object:<Type> [, Pos:point]
  This method may be defined on any graphical object that is a drop-zone. It will only be activated if the drag_and_drop_gesture can locate the method and make the necessary type transformations. Thus, if the type is specified as `file`, this method will only be activated if the dragged object can be converted to a file object. See also the discussion about the get_source argument above.

  If the method accepts a point for the second argument, a point will be passed that represents the location of the pointer in the coordinate system of the drop-zone, subtracted by the distance between the top-left corner of the dragged graphical to the pointer at the moment the button was depressed. To get the position of the pointer itself, just ask for the position of @event relative to the drop-zone.

graphical ->preview_drop: Object:<Type>* [, Pos:[point]]
  Sent by the drag_and_drop_gesture to allow the drop-zone providing feedback. The arguments and semantics are the same as for `->`drop, but the first argument can be @nil, indicating that the mouse has left the drop-zone. Under this condition, the position argument is @default.

  If a position argument is available, the drag_and_drop_gesture will be activated on each `drag` event. Otherwise it is only activated if the pointer enters the area of the drop-zone.