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.