Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
94 changes: 76 additions & 18 deletions addons/block_code/ui/blocks/block/block.gd
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,8 @@ var can_delete: bool = true

var _block_extension: BlockExtension

var _block_canvas: Node

@onready var _context := BlockEditorContext.get_default()


Expand Down Expand Up @@ -163,24 +165,30 @@ func _on_block_extension_changed():

func _gui_input(event):
if event is InputEventKey:
if event.pressed and event.keycode == KEY_DELETE:
# Always accept the Delete key so it doesn't propagate to the
# BlockCode node in the scene tree.
accept_event()

if not can_delete:
return

var dialog := ConfirmationDialog.new()
var num_blocks = _count_child_blocks(self) + 1
# FIXME: Maybe this should use block_name or label, but that
# requires one to be both unique and human friendly.
if num_blocks > 1:
dialog.dialog_text = "Delete %d blocks?" % num_blocks
else:
dialog.dialog_text = "Delete block?"
dialog.confirmed.connect(remove_from_tree)
EditorInterface.popup_dialog_centered(dialog)
if event.pressed:
if event.keycode == KEY_DELETE:
# Always accept the Delete key so it doesn't propagate to the
# BlockCode node in the scene tree.
accept_event()

if not can_delete:
return

var dialog := ConfirmationDialog.new()
var num_blocks = _count_child_blocks(self) + 1
# FIXME: Maybe this should use block_name or label, but that
# requires one to be both unique and human friendly.
if num_blocks > 1:
dialog.dialog_text = "Delete %d blocks?" % num_blocks
else:
dialog.dialog_text = "Delete block?"
dialog.confirmed.connect(remove_from_tree)
EditorInterface.popup_dialog_centered(dialog)
elif event.ctrl_pressed and not event.shift_pressed and not event.alt_pressed and not event.meta_pressed:
if event.keycode == KEY_D:
# Handle duplicate key
accept_event()
confirm_duplicate()


func remove_from_tree():
Expand All @@ -191,6 +199,31 @@ func remove_from_tree():
modified.emit()


func confirm_duplicate():
if not can_delete:
return

var new_block: Block = _context.block_script.instantiate_block(definition)

var new_parent: Node = get_parent()
while not new_parent.name == "Window":
new_parent = new_parent.get_parent()

if not _block_canvas:
_block_canvas = get_parent()
while not _block_canvas.name == "BlockCanvas":
_block_canvas = _block_canvas.get_parent()

new_parent.add_child(new_block)
new_block.global_position = global_position + (Vector2(100, 50) * new_parent.scale)

_copy_snapped_blocks(self, new_block)

_block_canvas.reconnect_block.emit(new_block)

modified.emit()


static func get_block_class():
push_error("Unimplemented.")

Expand Down Expand Up @@ -239,3 +272,28 @@ func _count_child_blocks(node: Node) -> int:
count += _count_child_blocks(child)

return count


func _copy_snapped_blocks(copy_from: Node, copy_to: Node):
var copy_to_child: Node
var child_index := 0
var maximum_count := copy_to.get_child_count()

for copy_from_child in copy_from.get_children():
if child_index + 1 > maximum_count:
return

copy_to_child = copy_to.get_child(child_index)
child_index += 1

if copy_from_child is SnapPoint and copy_from_child.has_snapped_block():
copy_to_child.add_child(_context.block_script.instantiate_block(copy_from_child.snapped_block.definition))
_block_canvas.reconnect_block.emit(copy_to_child.snapped_block)
elif copy_from_child.name.begins_with("ParameterInput"):
var raw_input = copy_from_child.get_raw_input()

if not raw_input is Block:
copy_to_child.set_raw_input(raw_input)

if copy_from_child is Container:
_copy_snapped_blocks(copy_from_child, copy_to_child)
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
extends Control

const Constants = preload("res://addons/block_code/ui/constants.gd")
const BlockTreeUtil = preload("res://addons/block_code/ui/block_tree_util.gd")

signal drag_started(offset: Vector2)

Expand All @@ -16,6 +17,7 @@ signal drag_started(offset: Vector2)
@export var drag_outside: bool = false

var _drag_start_position: Vector2 = Vector2.INF
var parent_block: Block


func _gui_input(event: InputEvent) -> void:
Expand All @@ -27,6 +29,20 @@ func _gui_input(event: InputEvent) -> void:

var button_event: InputEventMouseButton = event as InputEventMouseButton

if button_event.button_index == MOUSE_BUTTON_RIGHT and button_event.pressed:
if not parent_block:
parent_block = BlockTreeUtil.get_parent_block(self)
if parent_block and parent_block.can_delete:
accept_event()
var _context_menu := PopupMenu.new()
_context_menu.add_icon_item(EditorInterface.get_editor_theme().get_icon("Duplicate", "EditorIcons"), "Duplicate")
_context_menu.add_icon_item(EditorInterface.get_editor_theme().get_icon("Remove", "EditorIcons"), "Delete")
_context_menu.popup_hide.connect(_cleanup)
_context_menu.id_pressed.connect(_menu_pressed.bind(_context_menu))
_context_menu.position = DisplayServer.mouse_get_position()
add_child(_context_menu)
_context_menu.show()

if button_event.button_index != MOUSE_BUTTON_LEFT:
return

Expand Down Expand Up @@ -64,3 +80,18 @@ func _input(event: InputEvent) -> void:
get_viewport().set_input_as_handled()
drag_started.emit(_drag_start_position - motion_event.global_position)
_drag_start_position = Vector2.INF


func _menu_pressed(_index: int, _context_menu: PopupMenu):
var _pressed_label: String = _context_menu.get_item_text(_index)

if _pressed_label == "Duplicate":
parent_block.confirm_duplicate()
elif _pressed_label == "Delete":
parent_block.confirm_delete()


func _cleanup():
for child in get_children():
remove_child(child)
child.queue_free()
Loading