@@ -41,8 +41,43 @@ signal modified
41
41
## Whether the block can be deleted by the Delete key.
42
42
var can_delete : bool = true
43
43
44
+ # FIXME: Variable pinned should be saved with the scene
45
+ ## Whether the block is pinned
46
+ var pinned : bool :
47
+ set (value ):
48
+ if not can_delete :
49
+ return
50
+
51
+ pinned = value
52
+
53
+ if pinned :
54
+ block_pinned_container = Container .new ()
55
+ block_pinned_container .mouse_filter = Control .MOUSE_FILTER_IGNORE
56
+
57
+ var block_pinned_panel := Panel .new ()
58
+ block_pinned_panel .custom_minimum_size = Vector2 (16 , 16 )
59
+ block_pinned_panel .grow_horizontal = 2
60
+ block_pinned_panel .grow_vertical = 2
61
+ block_pinned_panel .self_modulate = Color (1 , 1 , 1 , 0.75 )
62
+
63
+ var block_pinned_icon := TextureRect .new ()
64
+ block_pinned_icon .texture = EditorInterface .get_editor_theme ().get_icon ("Pin" , "EditorIcons" )
65
+
66
+ block_pinned_panel .add_child (block_pinned_icon )
67
+ block_pinned_container .add_child (block_pinned_panel )
68
+ add_child (block_pinned_container )
69
+ else :
70
+ remove_child (block_pinned_container )
71
+ block_pinned_container .queue_free ()
72
+
73
+ block_pinned_container .visible = pinned
74
+
75
+ var block_pinned_container : Container
76
+
44
77
var _block_extension : BlockExtension
45
78
79
+ var _block_canvas : Node
80
+
46
81
@onready var _context := BlockEditorContext .get_default ()
47
82
48
83
@@ -163,24 +198,62 @@ func _on_block_extension_changed():
163
198
164
199
func _gui_input (event ):
165
200
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 )
201
+ if event .pressed :
202
+ if event .keycode == KEY_DELETE :
203
+ # Always accept the Delete key so it doesn't propagate to the
204
+ # BlockCode node in the scene tree.
205
+ accept_event ()
206
+ confirm_delete ()
207
+ elif event .ctrl_pressed and not event .shift_pressed and not event .alt_pressed and not event .meta_pressed :
208
+ # Should not accept when other keys are pressed
209
+ if event .keycode == KEY_D :
210
+ accept_event ()
211
+ confirm_duplicate ()
212
+ elif event .keycode == KEY_P :
213
+ accept_event ()
214
+ pinned = not pinned
215
+ _pin_snapped_blocks (self , pinned )
216
+
217
+
218
+ func confirm_delete ():
219
+ if not can_delete :
220
+ return
221
+
222
+ var dialog := ConfirmationDialog .new ()
223
+ var num_blocks = _count_child_blocks (self ) + 1
224
+ # FIXME: Maybe this should use block_name or label, but that
225
+ # requires one to be both unique and human friendly.
226
+ if num_blocks > 1 :
227
+ dialog .dialog_text = "Delete %d blocks?" % num_blocks
228
+ else :
229
+ dialog .dialog_text = "Delete block?"
230
+ dialog .confirmed .connect (remove_from_tree )
231
+ EditorInterface .popup_dialog_centered (dialog )
232
+
233
+
234
+ func confirm_duplicate ():
235
+ if not can_delete :
236
+ return
237
+
238
+ var new_block : Block = _context .block_script .instantiate_block (definition )
239
+
240
+ var new_parent : Node = get_parent ()
241
+ while not new_parent .name == "Window" :
242
+ new_parent = new_parent .get_parent ()
243
+
244
+ if not _block_canvas :
245
+ _block_canvas = get_parent ()
246
+ while not _block_canvas .name == "BlockCanvas" :
247
+ _block_canvas = _block_canvas .get_parent ()
248
+
249
+ new_parent .add_child (new_block )
250
+ new_block .global_position = global_position + (Vector2 (100 , 50 ) * new_parent .scale )
251
+
252
+ _copy_snapped_blocks (self , new_block )
253
+
254
+ _block_canvas .reconnect_block .emit (new_block )
255
+
256
+ modified .emit ()
184
257
185
258
186
259
func remove_from_tree ():
@@ -200,7 +273,8 @@ static func get_scene_path():
200
273
201
274
202
275
func _drag_started (offset : Vector2 = Vector2 .ZERO ):
203
- drag_started .emit (self , offset )
276
+ if not pinned :
277
+ drag_started .emit (self , offset )
204
278
205
279
206
280
func disconnect_signals ():
@@ -235,6 +309,42 @@ func _count_child_blocks(node: Node) -> int:
235
309
for child in node .get_children ():
236
310
if child is SnapPoint and child .has_snapped_block ():
237
311
count += 1
238
- count += _count_child_blocks (child )
312
+
313
+ if child is Container :
314
+ count += _count_child_blocks (child )
239
315
240
316
return count
317
+
318
+
319
+ func _copy_snapped_blocks (copy_from : Node , copy_to : Node ):
320
+ var copy_to_child : Node
321
+ var child_index := 0
322
+ var maximum_count := copy_to .get_child_count ()
323
+
324
+ for copy_from_child in copy_from .get_children ():
325
+ if child_index + 1 > maximum_count :
326
+ return
327
+
328
+ copy_to_child = copy_to .get_child (child_index )
329
+ child_index += 1
330
+
331
+ if copy_from_child is SnapPoint and copy_from_child .has_snapped_block ():
332
+ copy_to_child .add_child (_context .block_script .instantiate_block (copy_from_child .snapped_block .definition ))
333
+ _block_canvas .reconnect_block .emit (copy_to_child .snapped_block )
334
+ elif copy_from_child .name .begins_with ("ParameterInput" ):
335
+ var raw_input = copy_from_child .get_raw_input ()
336
+
337
+ if not raw_input is Block :
338
+ copy_to_child .set_raw_input (raw_input )
339
+
340
+ if copy_from_child is Container :
341
+ _copy_snapped_blocks (copy_from_child , copy_to_child )
342
+
343
+
344
+ func _pin_snapped_blocks (node : Node , _is_pinned : bool ):
345
+ for child in node .get_children ():
346
+ if child is SnapPoint and child .has_snapped_block ():
347
+ child .snapped_block .pinned = _is_pinned
348
+
349
+ if child is Container :
350
+ _pin_snapped_blocks (child , _is_pinned )
0 commit comments