|
2 | 2 | class_name DragManager |
3 | 3 | extends Control |
4 | 4 |
|
| 5 | +const Drag = preload("res://addons/block_code/drag_manager/drag.gd") |
| 6 | + |
5 | 7 | signal block_dropped |
6 | 8 | signal block_modified |
7 | 9 |
|
8 | 10 | @export var picker_path: NodePath |
9 | 11 | @export var block_canvas_path: NodePath |
10 | 12 |
|
11 | | -const Constants = preload("res://addons/block_code/ui/constants.gd") |
12 | | - |
13 | | -enum DragAction { NONE, PLACE, REMOVE } |
14 | | - |
15 | | - |
16 | | -class Drag: |
17 | | - extends Control |
18 | | - var _block: Block |
19 | | - var _block_scope: String |
20 | | - var _block_canvas: BlockCanvas |
21 | | - var _preview_block: Control |
22 | | - var _snap_points: Array[Node] |
23 | | - var _delete_areas: Array[Rect2] |
24 | | - var action: DragAction: |
25 | | - get: |
26 | | - return action |
27 | | - set(value): |
28 | | - if action != value: |
29 | | - action = value |
30 | | - _update_action_hint() |
31 | | - |
32 | | - var target_snap_point: SnapPoint: |
33 | | - get: |
34 | | - return target_snap_point |
35 | | - set(value): |
36 | | - if target_snap_point != value: |
37 | | - target_snap_point = value |
38 | | - _update_preview() |
39 | | - |
40 | | - var snap_block: Block: |
41 | | - get: |
42 | | - return target_snap_point.get_parent_block() if target_snap_point else null |
43 | | - |
44 | | - func _init(block: Block, block_scope: String, offset: Vector2, block_canvas: BlockCanvas): |
45 | | - assert(block.get_parent() == null) |
46 | | - |
47 | | - add_child(block) |
48 | | - block.position = -offset |
49 | | - |
50 | | - _block = block |
51 | | - _block_scope = block_scope |
52 | | - _block_canvas = block_canvas |
53 | | - |
54 | | - func set_snap_points(snap_points: Array[Node]): |
55 | | - _snap_points = snap_points.filter(_snaps_to) |
56 | | - |
57 | | - func add_delete_area(delete_area: Rect2): |
58 | | - _delete_areas.append(delete_area) |
59 | | - |
60 | | - func update_drag_state(): |
61 | | - global_position = get_global_mouse_position() |
62 | | - |
63 | | - if _block_canvas.is_mouse_over(): |
64 | | - scale = Vector2(_block_canvas.zoom, _block_canvas.zoom) |
65 | | - else: |
66 | | - scale = Vector2(1, 1) |
67 | | - |
68 | | - for rect in _delete_areas: |
69 | | - if rect.has_point(get_global_mouse_position()): |
70 | | - action = DragAction.REMOVE |
71 | | - target_snap_point = null |
72 | | - return |
73 | | - |
74 | | - action = DragAction.PLACE |
75 | | - |
76 | | - target_snap_point = _find_closest_snap_point() |
77 | | - |
78 | | - func apply_drag() -> Block: |
79 | | - update_drag_state() |
80 | | - |
81 | | - if action == DragAction.PLACE: |
82 | | - _place_block() |
83 | | - return _block |
84 | | - elif action == DragAction.REMOVE: |
85 | | - _remove_block() |
86 | | - return null |
87 | | - else: |
88 | | - return null |
89 | | - |
90 | | - func _remove_block(): |
91 | | - target_snap_point = null |
92 | | - _block.queue_free() |
93 | | - |
94 | | - func _place_block(): |
95 | | - var canvas_rect: Rect2 = _block_canvas.get_global_rect() |
96 | | - |
97 | | - var position = _block.global_position - canvas_rect.position |
98 | | - |
99 | | - remove_child(_block) |
100 | | - |
101 | | - if target_snap_point: |
102 | | - # Snap the block to the point |
103 | | - var orphaned_block = target_snap_point.insert_snapped_block(_block) |
104 | | - if orphaned_block: |
105 | | - # Place the orphan block somewhere outside the snap point |
106 | | - _block_canvas.arrange_block(orphaned_block, snap_block) |
107 | | - else: |
108 | | - # Block goes on screen somewhere |
109 | | - _block_canvas.add_block(_block, position) |
110 | | - |
111 | | - target_snap_point = null |
112 | | - |
113 | | - func _snaps_to(node: Node) -> bool: |
114 | | - var _snap_point: SnapPoint = node as SnapPoint |
115 | | - |
116 | | - if not _snap_point: |
117 | | - push_error("Warning: node %s is not of class SnapPoint." % node) |
118 | | - return false |
119 | | - |
120 | | - if not _block_canvas.is_ancestor_of(_snap_point): |
121 | | - # We only snap to blocks on the canvas: |
122 | | - return false |
123 | | - |
124 | | - if _block.block_type != _snap_point.block_type: |
125 | | - # We only snap to the same block type: |
126 | | - return false |
127 | | - |
128 | | - if _block.block_type == Types.BlockType.VALUE and not Types.can_cast(_block.variant_type, _snap_point.variant_type): |
129 | | - # We only snap Value blocks to snaps that can cast to same variant: |
130 | | - return false |
131 | | - |
132 | | - # Check if any parent node is this node |
133 | | - if _snap_point.is_ancestor_of(_block): |
134 | | - return false |
135 | | - |
136 | | - var top_block = _get_top_block_for_node(_snap_point) |
137 | | - |
138 | | - # Check if scope is valid |
139 | | - if _block_scope != "": |
140 | | - if top_block is EntryBlock: |
141 | | - if _block_scope != top_block.get_entry_statement(): |
142 | | - return false |
143 | | - elif top_block: |
144 | | - var tree_scope := InstructionTree.get_tree_scope(top_block) |
145 | | - if tree_scope != "" and _block_scope != tree_scope: |
146 | | - return false |
147 | | - |
148 | | - return true |
149 | | - |
150 | | - func _find_closest_snap_point() -> Node: |
151 | | - var closest_snap_point: SnapPoint = null |
152 | | - var closest_distance: int |
153 | | - for snap_point in _snap_points: |
154 | | - var distance = _get_distance_to_snap_point(snap_point) |
155 | | - if distance > Constants.MINIMUM_SNAP_DISTANCE * _block_canvas.zoom: |
156 | | - continue |
157 | | - elif closest_snap_point == null or distance < closest_distance: |
158 | | - closest_snap_point = snap_point |
159 | | - closest_distance = distance |
160 | | - return closest_snap_point |
161 | | - |
162 | | - func _get_top_block_for_node(node: Node) -> Block: |
163 | | - for top_block in _block_canvas.get_blocks(): |
164 | | - if top_block.is_ancestor_of(node): |
165 | | - return top_block |
166 | | - return null |
167 | | - |
168 | | - func _get_distance_to_snap_point(snap_point: SnapPoint) -> float: |
169 | | - var from_global: Vector2 = _block.global_position |
170 | | - return from_global.distance_to(snap_point.global_position) |
171 | | - |
172 | | - func _update_action_hint(): |
173 | | - match action: |
174 | | - DragAction.REMOVE: |
175 | | - _block.modulate = Color(1.0, 1.0, 1.0, 0.5) |
176 | | - _: |
177 | | - _block.modulate = Color.WHITE |
178 | | - |
179 | | - func _update_preview(): |
180 | | - if _preview_block: |
181 | | - _preview_block.queue_free() |
182 | | - _preview_block = null |
183 | | - |
184 | | - if target_snap_point: |
185 | | - # Make preview block |
186 | | - _preview_block = Control.new() |
187 | | - _preview_block.set_script(preload("res://addons/block_code/ui/blocks/utilities/background/background.gd")) |
188 | | - |
189 | | - _preview_block.color = Color(1, 1, 1, 0.5) |
190 | | - _preview_block.custom_minimum_size = _block.get_global_rect().size |
191 | | - _preview_block.size_flags_horizontal = Control.SIZE_SHRINK_BEGIN |
192 | | - _preview_block.size_flags_vertical = Control.SIZE_SHRINK_BEGIN |
193 | | - |
194 | | - target_snap_point.add_child(_preview_block) |
195 | | - |
196 | | - |
197 | 13 | var _picker: Picker |
198 | 14 | var _block_canvas: BlockCanvas |
199 | 15 |
|
|
0 commit comments