@@ -43,6 +43,8 @@ var can_delete: bool = true
43
43
44
44
var _block_extension : BlockExtension
45
45
46
+ var _block_canvas : Node
47
+
46
48
@onready var _context := BlockEditorContext .get_default ()
47
49
48
50
@@ -163,24 +165,58 @@ func _on_block_extension_changed():
163
165
164
166
func _gui_input (event ):
165
167
if event is InputEventKey :
166
- if event .pressed and event .keycode == KEY_DELETE :
167
- # Always accept the Delete key so it doesn't propagate to the
168
- # BlockCode node in the scene tree.
169
- accept_event ()
170
-
171
- if not can_delete :
172
- return
173
-
174
- var dialog := ConfirmationDialog .new ()
175
- var num_blocks = _count_child_blocks (self ) + 1
176
- # FIXME: Maybe this should use block_name or label, but that
177
- # requires one to be both unique and human friendly.
178
- if num_blocks > 1 :
179
- dialog .dialog_text = "Delete %d blocks?" % num_blocks
180
- else :
181
- dialog .dialog_text = "Delete block?"
182
- dialog .confirmed .connect (remove_from_tree )
183
- EditorInterface .popup_dialog_centered (dialog )
168
+ if event .pressed :
169
+ if event .keycode == KEY_DELETE :
170
+ # Always accept the Delete key so it doesn't propagate to the
171
+ # BlockCode node in the scene tree.
172
+ accept_event ()
173
+ confirm_delete ()
174
+ elif event .ctrl_pressed and not event .shift_pressed and not event .alt_pressed and not event .meta_pressed :
175
+ # Should not accept when other keys are pressed
176
+ if event .keycode == KEY_D :
177
+ accept_event ()
178
+ confirm_duplicate ()
179
+
180
+
181
+ func confirm_delete ():
182
+ if not can_delete :
183
+ return
184
+
185
+ var dialog := ConfirmationDialog .new ()
186
+ var num_blocks = _count_child_blocks (self ) + 1
187
+ # FIXME: Maybe this should use block_name or label, but that
188
+ # requires one to be both unique and human friendly.
189
+ if num_blocks > 1 :
190
+ dialog .dialog_text = "Delete %d blocks?" % num_blocks
191
+ else :
192
+ dialog .dialog_text = "Delete block?"
193
+ dialog .confirmed .connect (remove_from_tree )
194
+ EditorInterface .popup_dialog_centered (dialog )
195
+
196
+
197
+ func confirm_duplicate ():
198
+ if not can_delete :
199
+ return
200
+
201
+ var new_block : Block = _context .block_script .instantiate_block (definition )
202
+
203
+ var new_parent : Node = get_parent ()
204
+ while not new_parent .name == "Window" :
205
+ new_parent = new_parent .get_parent ()
206
+
207
+ if not _block_canvas :
208
+ _block_canvas = get_parent ()
209
+ while not _block_canvas .name == "BlockCanvas" :
210
+ _block_canvas = _block_canvas .get_parent ()
211
+
212
+ new_parent .add_child (new_block )
213
+ new_block .global_position = global_position + (Vector2 (100 , 50 ) * new_parent .scale )
214
+
215
+ _copy_snapped_blocks (self , new_block )
216
+
217
+ _block_canvas .reconnect_block .emit (new_block )
218
+
219
+ modified .emit ()
184
220
185
221
186
222
func remove_from_tree ():
@@ -236,6 +272,33 @@ func _count_child_blocks(node: Node) -> int:
236
272
for child in node .get_children ():
237
273
if child is SnapPoint and child .has_snapped_block ():
238
274
count += 1
239
- count += _count_child_blocks (child )
275
+
276
+ if child is Container :
277
+ count += _count_child_blocks (child )
240
278
241
279
return count
280
+
281
+
282
+ func _copy_snapped_blocks (copy_from : Node , copy_to : Node ):
283
+ var copy_to_child : Node
284
+ var child_index := 0
285
+ var maximum_count := copy_to .get_child_count ()
286
+
287
+ for copy_from_child in copy_from .get_children ():
288
+ if child_index + 1 > maximum_count :
289
+ return
290
+
291
+ copy_to_child = copy_to .get_child (child_index )
292
+ child_index += 1
293
+
294
+ if copy_from_child is SnapPoint and copy_from_child .has_snapped_block ():
295
+ copy_to_child .add_child (_context .block_script .instantiate_block (copy_from_child .snapped_block .definition ))
296
+ _block_canvas .reconnect_block .emit (copy_to_child .snapped_block )
297
+ elif copy_from_child .name .begins_with ("ParameterInput" ):
298
+ var raw_input = copy_from_child .get_raw_input ()
299
+
300
+ if not raw_input is Block :
301
+ copy_to_child .set_raw_input (raw_input )
302
+
303
+ if copy_from_child is Container :
304
+ _copy_snapped_blocks (copy_from_child , copy_to_child )
0 commit comments