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).
->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)
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.
->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.