Skip to content

Instantly share code, notes, and snippets.

@PrestonKnopp
Created June 8, 2019 00:04
Show Gist options
  • Save PrestonKnopp/b53752f08b5446ff248c8cfa58105c2b to your computer and use it in GitHub Desktop.
Save PrestonKnopp/b53752f08b5446ff248c8cfa58105c2b to your computer and use it in GitHub Desktop.
Examples of Godot's Control drag and drop functionality. Test it out by downloading this tscn and adding it to a Godot project. It is entirely self contained in one scene.
[gd_scene load_steps=6 format=2]
[sub_resource type="GDScript" id=1]
script/source = "extends Control
class DragDataColor:
var sender: Object
var color: Color"
[sub_resource type="GDScript" id=3]
script/source = "extends Control
export(bool) var is_accepting_drop_data = true
# This control will accept drop data from a color source, such as:
# source_red, source_blue, or source_green.
# The following two functions are virtual, meaning you the programmer must implement it.
# Then the two functions will be called by the engine.
# The can drop data will take a position local within self's local coordinate system.
# The position (0,0) is the top left corner.
#
# The data will be from other controls that have implemented `get_drag_data()`.
#
# You can perform any logic in this function. You must return a `true` when you want
# to accept the `data` and `false` when you reject the data. You can use the `position`
# to determine if you want to accept or reject the `data`. Additionally, this method should be
# fast as it is called every mouse move event.
#
# Some examples of ways to check if can drop data usually include checking if the data
# contains a specific property or is of a certain type. You could also only consider data
# when a certain condition or state is met.
#
# In this example we will be using a simple state called `is_accepting_drop_data` and then
# a type check to see if `data` is of a `DragDataColor` type.
#
# We only check for type `DragDataColor` here because that is the only requirement for this example.
func can_drop_data(position: Vector2, data) -> bool:
print('can drop data')
# The following return statement is the condensed form, but logically equivalent of:
# if not is_accepting_drop_data: return false
# if data is DragDataColor: return true
# else: return false
#
# The following line reads nicely as:
# When self is accepting drop data and the drop data is of type DragDataColor then
# accept the drop data.
return is_accepting_drop_data and data is get_parent().DragDataColor
func drop_data(position: Vector2, data) -> void:
print('accepting drop data')
# Here we will actually use the data.
# In this example we want to take the position and add a new source in that position.
# We know that data is DragDataColor which has the sender property:
# Let's make it simple and duplicate that source, then add it as a child.
var new_source = data.sender.duplicate()
new_source.rect_position = position
add_child(new_source)"
[sub_resource type="GDScript" id=2]
script/source = "extends ColorRect
# get_drag_data() is a virtual function that you, the programmer, implement.
# The engine will call this method, if defined, on your behalf.
# As any function, you can perform any logic you want inside of it.
#
# You want to return the data (or metadata) that this control represents.
# In this example, this control just represents a color. We want other color controls to accept
# this control's source color.
func get_drag_data(position: Vector2) -> Object:
# For this example to be contained in one scene,
# the DragDataColor class is on scene root.
var DragDataColor = get_node('../..').DragDataColor
# First create the data to be passed:
var data = DragDataColor.new()
data.sender = self
data.color = color
# Then create a preview for that data:
# In this case we can just duplicate self
set_drag_preview(self.duplicate())
return data"
[sub_resource type="GDScript" id=4]
script/source = "extends ColorRect
# This control will take other source colors and mix it with itself.
# It can also be dragged and dropped as well.
func can_drop_data(position: Vector2, data) -> bool:
return data is get_node('../..').DragDataColor
func drop_data(position: Vector2, data) -> void:
var c = data.color
c.a = 0.5
color = color.blend(c)
func get_drag_data(position: Vector2) -> Object:
var data = get_node('../..').DragDataColor.new()
data.sender = self
data.color = color
set_drag_preview(duplicate())
return data"
[sub_resource type="GDScript" id=5]
script/source = "extends ColorRect
# This control will remove itself after being picked up.
func get_drag_data(position: Vector2) -> Object:
var data = get_node('../..').DragDataColor.new()
data.sender = duplicate() # note: this will be leaked, but for simplicities sake, I'm still using this.
data.color = color
set_drag_preview(duplicate())
queue_free()
return data"
[node name="test_drag_and_drop" type="Control"]
anchor_right = 1.0
anchor_bottom = 1.0
script = SubResource( 1 )
[node name="destination_large" type="Control" parent="."]
anchor_right = 1.0
anchor_bottom = 1.0
script = SubResource( 3 )
[node name="source_red" type="ColorRect" parent="destination_large"]
margin_left = 51.632
margin_top = 69.1674
margin_right = 91.632
margin_bottom = 109.167
color = Color( 0.843137, 0.364706, 0.364706, 1 )
script = SubResource( 2 )
[node name="source_blue" type="ColorRect" parent="destination_large"]
margin_left = 104.238
margin_top = 69.1673
margin_right = 144.238
margin_bottom = 109.167
color = Color( 0.364706, 0.462745, 0.843137, 1 )
script = SubResource( 2 )
[node name="source_green" type="ColorRect" parent="destination_large"]
margin_left = 155.87
margin_top = 69.1674
margin_right = 195.87
margin_bottom = 109.167
color = Color( 0.364706, 0.843137, 0.384314, 1 )
script = SubResource( 2 )
[node name="source_and_destination_mix" type="ColorRect" parent="destination_large"]
margin_left = 106.186
margin_top = 123.722
margin_right = 146.186
margin_bottom = 163.722
script = SubResource( 4 )
[node name="pickup_source" type="ColorRect" parent="destination_large"]
margin_right = 40.0
margin_bottom = 40.0
script = SubResource( 5 )
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment