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