Drag-N-Drop

kivy_garden.drag_n_drop

Drag and Drop

This adds a drag and drop functionality to layouts and widgets. There are 2 primary and one internal component used to have drag and drop:

Layout

To use DraggableLayoutBehavior with a layout, DraggableLayoutBehavior.compare_pos_to_widget() must be implement for each layout. This determines where in the layout the widget is being previewed and ultimitely dropped. But, it can be further customized for any type of layout by overwriting the default DraggableLayoutBehavior.get_drop_insertion_index_move() and DraggableLayoutBehavior.get_drop_insertion_index_up().

Similarly, handle_drag_release() should be implemented. It handles the actual final drop into the layout. A good default implementation is:

def handle_drag_release(self, index, drag_widget):
    self.add_widget(drag_widget, index)

Dragging Widget

To use DraggableObjectBehavior, one should implement DraggableObjectBehavior.initiate_drag() and/or DraggableObjectBehavior.complete_drag(). Typically, you would want to remove the widget from it’s current layout as it starts to be dragged, with e.g.

def initiate_drag(self):
    self.parent.remove_widget(self)

Describing Which Widgets can be Dropped Into Which Layout

Given some DraggableObjectBehavior and some DraggableLayoutBehavior instances. We can control which widget can be dragged into which layout using their DraggableObjectBehavior.drag_cls and DraggableLayoutBehavior.drag_classes. DraggableObjectBehavior.drag_cls must be listed in DraggableLayoutBehavior.drag_classes for the widget to be draggable into the layout.

Example

Following is an example with kivy.uix.boxlayout.BoxLayout:

from kivy.uix.label import Label
from kivy.uix.boxlayout import BoxLayout

class DraggableBoxLayout(DraggableLayoutBehavior, BoxLayout):

    def compare_pos_to_widget(self, widget, pos):
        if self.orientation == 'vertical':
            return 'before' if pos[1] >= widget.center_y else 'after'
        return 'before' if pos[0] < widget.center_x else 'after'

    def handle_drag_release(self, index, drag_widget):
        self.add_widget(drag_widget, index)

class DragLabel(DraggableObjectBehavior, Label):

    def initiate_drag(self):
        # during a drag, we remove the widget from the original location
        self.parent.remove_widget(self)

And then in kv:

BoxLayout:
    DraggableBoxLayout:
        drag_classes: ['label']
        orientation: 'vertical'
        Label:
            text: 'A'
        Label:
            text: 'A'
        Label:
            text: 'A'
    DraggableBoxLayout:
        drag_classes: ['label']
        orientation: 'vertical'
        DragLabel:
            text: 'A*'
            drag_cls: 'label'
        DragLabel:
            text: 'A*'
            drag_cls: 'label'
class kivy_garden.drag_n_drop.DraggableBoxLayoutBehavior(**kwargs)

Bases: kivy_garden.drag_n_drop.DraggableLayoutBehavior

compare_pos_to_widget(widget, pos)

After we call get_widget_under_drag() to find the widget in children that is currently under the given pos (the current mouse pos that drags a widget), we call this to find whether the mouse pos indicates that the dragged widget needs to be added before or after the widget returned by get_widget_under_drag().

It must return either the string “before”, or “after”.

See get_drop_insertion_index_move() and get_drop_insertion_index_up().

class kivy_garden.drag_n_drop.DraggableController(**kwargs)

Bases: kivy._event.EventDispatcher

The controller that manages the dragging process.

clean_dragging()

Removes the drag widget preview.

drag_distance

Minimum amount of pixel distance a widget needs to be dragged before we start going into drag mode.

drag_down(source, touch)

Called by DraggableObjectBehavior when it got a touch down.

drag_move(source, touch)

Called by DraggableObjectBehavior when it got a touch move.

drag_up(source, touch)

Called by DraggableObjectBehavior when it got a touch up.

dragging

Whether the controller is currently dragging something.

prepare_preview_widget(source_widget)
preview_background_color

The background color of the preview widget as it’s dragged.

Defaults to rgba=0,0,0,1, which means the dragging widget will be placed on a black background. To make the background transparent, set it to (0, 0, 0, 0).

preview_pixels = None
preview_widget = None

The widget shown as preview during a drag, which follows the current mouse position. Defaults to a PreviewWidget. that f

start_widget_pos = (0, 0)
touch_dx = 0
touch_dy = 0
widget_dragged

The DraggableObjectBehavior widget currently being dragged by the controller.

class kivy_garden.drag_n_drop.DraggableGridLayoutBehavior(**kwargs)

Bases: kivy_garden.drag_n_drop.DraggableLayoutBehavior

compare_pos_to_widget(widget, pos)

After we call get_widget_under_drag() to find the widget in children that is currently under the given pos (the current mouse pos that drags a widget), we call this to find whether the mouse pos indicates that the dragged widget needs to be added before or after the widget returned by get_widget_under_drag().

It must return either the string “before”, or “after”.

See get_drop_insertion_index_move() and get_drop_insertion_index_up().

class kivy_garden.drag_n_drop.DraggableLayoutBehavior(**kwargs)

Bases: object

Adds support to a layout such that we can drag widgets into this layout and preview it while dragging.

Only DraggableObjectBehavior widgets whose DraggableObjectBehavior.drag_cls are in drag_classes will be dropable into the layout.

compare_pos_to_widget(widget, pos)

After we call get_widget_under_drag() to find the widget in children that is currently under the given pos (the current mouse pos that drags a widget), we call this to find whether the mouse pos indicates that the dragged widget needs to be added before or after the widget returned by get_widget_under_drag().

It must return either the string “before”, or “after”.

See get_drop_insertion_index_move() and get_drop_insertion_index_up().

drag_append_end

Whether the DraggableObjectBehavior when dragged over the layout’s area should be previewed and return an index that would add it at that location in its children, or if it will only support adding the widget to the end of children.

drag_classes

During a drag, the controller will try to preview and add the dragged DraggableObjectBehavior to this layout widget when it is over the widget’s area. But, it will only do it if the dragged widget’s DraggableObjectBehavior.drag_cls is in the layout’s drag_classes.

This allows selecting which widgets can be dropped where.

get_drop_insertion_index_move(x, y)

During a drag, it is called with when we need to figure out where to display the spacer widget in the layout.

It calls get_widget_under_drag() to find the widget in the layout currently under the mouse pos. Then it uses compare_pos_to_widget() to figure out if it should be added before, or after that widget and returns the index in children where the spacer should be added to represent the potential drop.

If the spacer is under the current pos, or if no widget is under it (get_widget_under_drag() returned None), we return None, otherwise the index.

get_drop_insertion_index_up(x, y)

When dropping a drag, it is called to get the index in children of the layout where the widget was dropped and where it needs to be inserted.

It calls get_widget_under_drag() to find the widget in the layout currently under the mouse pos. Then it uses compare_pos_to_widget() to figure out if it should be added before, or after that widget and returns the index in children where the it should be added to complete the drop.

get_widget_under_drag(x, y)

Returns the widget in children that is under the given position (current mouse pos that drags the widget).

See get_drop_insertion_index_move() and get_drop_insertion_index_up().

handle_drag_release(index, drag_widget)

This is called when a widget is dropped in the layout. index is the index in children where the widget should be added. drag_widget is the DraggableObjectBehavior that was dropped there.

This must be overwritten by the inherited class to actually do the add_widget or something else.

on_touch_move(touch)
on_touch_up(touch)
spacer_props

The properties of spacer_widget, which will be set according to this dict. This enables setting the sizing info for the preview widget in the layout.

spacer_widget

The widget that is added to the layout to show where the dragged widget could be dropped.

Defaults to SpacerWidget if not set.

class kivy_garden.drag_n_drop.DraggableObjectBehavior

Bases: object

A widget that inherits from this class can participate in a drag by someone dragging it with the mouse.

complete_drag()

Called by the DraggableController, when a drag is completed.

drag_cls

A name to determine where we can potentially drop the dragged widget. For each DraggableLayoutBehavior that we hover over, if drag_cls is in that DraggableLayoutBehavior.drag_classes, we will preview and allow the widget to be dropped there.

drag_controller

A (potentially global) DraggableController instance that manages the (potential) drag. If None during the first potential drag, a DraggableController instance will be created and set.

drag_widget

The widget, whose texture will be copied and previewed as the object is dragged. If None, it’s this widget.

initiate_drag()

Called by the DraggableController, when a drag is initiated on the widget (i.e. thw widget is actually being dragged once it exceeds the minimum drag distance).

on_touch_down(touch)
on_touch_move(touch)
on_touch_up(touch)
class kivy_garden.drag_n_drop.PreviewWidget(**kwargs)

Bases: kivy.uix.widget.Widget

The widget that is used to preview the widget being dragged, during a drag. Used internally.

preview_texture

The texture that is previewed when a widget is being dragged.

class kivy_garden.drag_n_drop.SpacerWidget(**kwargs)

Bases: kivy.uix.widget.Widget

Widget inserted at the location where the dragged widget may be dropped to show where it’ll be dropped.