Ren'Py includes drag and drop displayables that allow things to be moved around the screen with the mouse. Some of the uses of dragging are:
The drag and drop displayables make it possible to implement these and other uses of drag and drop. There are two classes involved here. The Drag class represents either something that can be dragged around the screen, something that can have a draggable dropped onto it, or something that can do both. The DragGroup class represents a group of Drags - for a drag and drop to occur, both Drags must be part of the same drag group.
The drag and drop system can be used either through the Screen Language or directly as displayables. It makes sense to use the screen language when you don't need to refer to the Drags that you create after they've been created. This might be the case if the draggable represents a window that the user places on the scren. If you need to refer to the drags after they've been created, then it's often better to create Drags directly, and add them to a DragGroup.
A displayable that represents an object that can be dragged around its enclosing area. A Drag can also represent an area that other Drags can be dropped on.
A Drag can be moved around inside is parent. Generally, its parent should be either a Fixed() or DragGroup.
A Drag has one child. The child's state reflects the status of the drag and drop operation:
The drag handle is a rectangle inside the child. The mouse must be over a non-transparent pixel inside the drag handle for dragging or clicking to occur.
A newly-created draggable is added to the default DragGroup. A draggable can only be in a single DragGroup - if it's added to a second group, it's removed from the first.
When a Drag is first rendered, if it's position cannot be determined from the DragGroup it is in, the position of its upper-left corner is computed using the standard layout algorithm. Once that position
A callback (or list of callbacks) that is called when this Drag is dropped onto. It is called with two arguments. The first is the Drag being dropped onto. The second is a list of Drags that are being dragged. If the callback returns a value other than None, that value is returned as the result of the interaction.
When a dragged and dropped callback are triggered for the same event, the dropped callback is only called if dragged returns None.
Except for d, all of the parameters are available as fields (with the same name) on the Drag object. In addition, after the drag has been rendered, the following fields become available:
Changes the child of this drag to d.
Changes the position of the drag. If the drag is not showing, then the position change is instantaneous. Otherwise, the position change takes delay seconds, and is animated as a linear move.
Raises this displayable to the top of its drag_group.
Represents a group of Drags. A Drag is limited to the boundary of its DragGroup. Dropping only works between Drags that are in the same DragGroup. Drags may only be raised when they are inside a DragGroup.
A DragGroup is laid out like a Fixed().
All positional parameters to the DragGroup constructor should be Drags, that are added to the DragGroup.
Adds child, which must be a Drag, to this DragGroup.
Returns the first child of this DragGroup that has a drag_name of name.
Removes child from this DragGroup.
An example of a say screen that allows the user to choose the location of the window by dragging it around the screen.:
screen say:
drag:
drag_name "say"
yalign 1.0
drag_handle (0, 0, 1.0, 30)
xalign 0.5
window id "window":
# Ensure that the window is smaller than the screen.
xmaximum 600
has vbox
if who:
text who id "who"
text what id "what"
Here's a more complicated example, one that shows how dragging can be used to influence gameplay. It shows how dragging can be used to send a character to a location:
init python:
def detective_dragged(drags, drop):
if not drop:
return
store.detective = drags[0].drag_name
store.city = drop.drag_name
return True
screen send_detective_screen:
# A map as background.
add "europe.jpg"
# A drag group ensures that the detectives and the cities.
drag_group:
# Our detectives.
drag:
drag_name "Ivy"
child "ivy.png"
droppable False
dragged detective_dragged
xpos 100 ypos 100
drag:
drag_name "Zack"
child "zack.png"
droppable False
dragged detective_dragged
xpos 150 ypos 100
# The cities they can go to.
drag:
drag_name "London"
child "london.png"
draggable False
xpos 450 ypos 140
drag:
drag_name "Paris"
draggable False
child "paris.png"
xpos 500 ypos 280
label send_detective:
"We need to investigate! Who should we send, and where should they go?"
call screen send_detective_screen
"Okay, we'll send %(detective)s to %(city)s."
More complicated systems take significant programming skill to get right. The Ren'Py cardgame framework is both an example of how to use drag and drop in a complex system, and useful for making card games in its own right.