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.