@@ -41,9 +41,45 @@ 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 = _icon_pin
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 ()
82
+ @onready var _icon_pin := EditorInterface .get_editor_theme ().get_icon ("Pin" , "EditorIcons" )
47
83
48
84
49
85
func _ready ():
@@ -163,24 +199,62 @@ func _on_block_extension_changed():
163
199
164
200
func _gui_input (event ):
165
201
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 )
202
+ if event .pressed :
203
+ if event .keycode == KEY_DELETE :
204
+ # Always accept the Delete key so it doesn't propagate to the
205
+ # BlockCode node in the scene tree.
206
+ accept_event ()
207
+ confirm_delete ()
208
+ elif event .ctrl_pressed and not event .shift_pressed and not event .alt_pressed and not event .meta_pressed :
209
+ # Should not accept when other keys are pressed
210
+ if event .keycode == KEY_D :
211
+ accept_event ()
212
+ confirm_duplicate ()
213
+ elif event .keycode == KEY_P :
214
+ accept_event ()
215
+ pinned = not pinned
216
+ _pin_snapped_blocks (self , pinned )
217
+
218
+
219
+ func confirm_delete ():
220
+ if not can_delete :
221
+ return
222
+
223
+ var dialog := ConfirmationDialog .new ()
224
+ var num_blocks = _count_child_blocks (self ) + 1
225
+ # FIXME: Maybe this should use block_name or label, but that
226
+ # requires one to be both unique and human friendly.
227
+ if num_blocks > 1 :
228
+ dialog .dialog_text = "Delete %d blocks?" % num_blocks
229
+ else :
230
+ dialog .dialog_text = "Delete block?"
231
+ dialog .confirmed .connect (remove_from_tree )
232
+ EditorInterface .popup_dialog_centered (dialog )
233
+
234
+
235
+ func confirm_duplicate ():
236
+ if not can_delete :
237
+ return
238
+
239
+ var new_block : Block = _context .block_script .instantiate_block (definition )
240
+
241
+ var new_parent : Node = get_parent ()
242
+ while not new_parent .name == "Window" :
243
+ new_parent = new_parent .get_parent ()
244
+
245
+ if not _block_canvas :
246
+ _block_canvas = get_parent ()
247
+ while not _block_canvas .name == "BlockCanvas" :
248
+ _block_canvas = _block_canvas .get_parent ()
249
+
250
+ new_parent .add_child (new_block )
251
+ new_block .global_position = global_position + (Vector2 (100 , 50 ) * new_parent .scale )
252
+
253
+ _copy_snapped_blocks (self , new_block )
254
+
255
+ _block_canvas .reconnect_block .emit (new_block )
256
+
257
+ modified .emit ()
184
258
185
259
186
260
func remove_from_tree ():
@@ -200,7 +274,8 @@ static func get_scene_path():
200
274
201
275
202
276
func _drag_started (offset : Vector2 = Vector2 .ZERO ):
203
- drag_started .emit (self , offset )
277
+ if not pinned :
278
+ drag_started .emit (self , offset )
204
279
205
280
206
281
func disconnect_signals ():
@@ -235,6 +310,42 @@ func _count_child_blocks(node: Node) -> int:
235
310
for child in node .get_children ():
236
311
if child is SnapPoint and child .has_snapped_block ():
237
312
count += 1
238
- count += _count_child_blocks (child )
313
+
314
+ if child is Container :
315
+ count += _count_child_blocks (child )
239
316
240
317
return count
318
+
319
+
320
+ func _copy_snapped_blocks (copy_from : Node , copy_to : Node ):
321
+ var copy_to_child : Node
322
+ var child_index := 0
323
+ var maximum_count := copy_to .get_child_count ()
324
+
325
+ for copy_from_child in copy_from .get_children ():
326
+ if child_index + 1 > maximum_count :
327
+ return
328
+
329
+ copy_to_child = copy_to .get_child (child_index )
330
+ child_index += 1
331
+
332
+ if copy_from_child is SnapPoint and copy_from_child .has_snapped_block ():
333
+ copy_to_child .add_child (_context .block_script .instantiate_block (copy_from_child .snapped_block .definition ))
334
+ _block_canvas .reconnect_block .emit (copy_to_child .snapped_block )
335
+ elif copy_from_child .name .begins_with ("ParameterInput" ):
336
+ var raw_input = copy_from_child .get_raw_input ()
337
+
338
+ if not raw_input is Block :
339
+ copy_to_child .set_raw_input (copy_from_child .get_raw_input ())
340
+
341
+ if copy_from_child is Container :
342
+ _copy_snapped_blocks (copy_from_child , copy_to_child )
343
+
344
+
345
+ func _pin_snapped_blocks (node : Node , _is_pinned : bool ):
346
+ for child in node .get_children ():
347
+ if child is SnapPoint and child .has_snapped_block ():
348
+ child .snapped_block .pinned = _is_pinned
349
+
350
+ if child is Container :
351
+ _pin_snapped_blocks (child , _is_pinned )
0 commit comments