Skip to content

Commit 7e79f30

Browse files
committed
Add zoom and pan to block canvas
1 parent d82ce7d commit 7e79f30

File tree

2 files changed

+98
-10
lines changed

2 files changed

+98
-10
lines changed

addons/block_code/ui/block_canvas/block_canvas.gd

Lines changed: 59 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,9 @@ extends MarginContainer
44

55
const EXTEND_MARGIN: float = 800
66
const BLOCK_AUTO_PLACE_MARGIN: Vector2 = Vector2(16, 8)
7+
const ZOOM_FACTOR: float = 1.1
78

89
@onready var _window: Control = %Window
9-
@onready var _window_scroll: ScrollContainer = %WindowScroll
1010
@onready var _empty_box: BoxContainer = %EmptyBox
1111

1212
@onready var _selected_node_box: BoxContainer = %SelectedNodeBox
@@ -23,7 +23,11 @@ const BLOCK_AUTO_PLACE_MARGIN: Vector2 = Vector2(16, 8)
2323

2424
@onready var _open_scene_icon = _open_scene_button.get_theme_icon("Load", "EditorIcons")
2525

26+
@onready var _mouse_override: Control = %MouseOverride
27+
@onready var _zoom_label: Label = %ZoomLabel
28+
2629
var _block_scenes_by_class = {}
30+
var _panning := false
2731

2832
signal reconnect_block(block: Block)
2933
signal add_block_code
@@ -48,10 +52,8 @@ func _populate_block_scenes_by_class():
4852

4953

5054
func add_block(block: Block, position: Vector2 = Vector2.ZERO) -> void:
51-
block.position = position
52-
block.position.y += _window_scroll.scroll_vertical
55+
block.position = canvas_to_window(position)
5356
_window.add_child(block)
54-
_window.custom_minimum_size.y = max(block.position.y + EXTEND_MARGIN, _window.custom_minimum_size.y)
5557

5658

5759
func get_blocks() -> Array[Block]:
@@ -79,6 +81,10 @@ func bsd_selected(bsd: BlockScriptData):
7981

8082
var edited_node = EditorInterface.get_inspector().get_edited_object() as Node
8183

84+
_window.position = Vector2(0, 0)
85+
_window.scale = Vector2(1, 1)
86+
_zoom_label.visible = false
87+
8288
_empty_box.visible = false
8389
_selected_node_box.visible = false
8490
_selected_node_with_block_code_box.visible = false
@@ -88,6 +94,7 @@ func bsd_selected(bsd: BlockScriptData):
8894

8995
if bsd != null:
9096
_load_bsd(bsd)
97+
_zoom_label.visible = true
9198
elif edited_node == null:
9299
_empty_box.visible = true
93100
elif BlockCodePlugin.node_has_block_code(edited_node):
@@ -105,7 +112,6 @@ func bsd_selected(bsd: BlockScriptData):
105112
_selected_node_label.text = _selected_node_label_format.format({"node": edited_node.name})
106113
_add_block_code_button.disabled = false
107114

108-
109115
func _load_bsd(bsd: BlockScriptData):
110116
for tree in bsd.block_trees.array:
111117
load_tree(_window, tree)
@@ -207,3 +213,51 @@ func _on_replace_block_code_button_pressed():
207213
_replace_block_code_button.disabled = true
208214

209215
replace_block_code.emit()
216+
217+
218+
func _input(event):
219+
if event is InputEventKey:
220+
if event.keycode == KEY_SHIFT:
221+
if event.pressed:
222+
_mouse_override.mouse_filter = Control.MOUSE_FILTER_PASS
223+
_mouse_override.mouse_default_cursor_shape = Control.CURSOR_MOVE
224+
else:
225+
_mouse_override.mouse_filter = Control.MOUSE_FILTER_IGNORE
226+
_mouse_override.mouse_default_cursor_shape = Control.CURSOR_ARROW
227+
228+
if event is InputEventMouseButton:
229+
if event.button_index == MOUSE_BUTTON_LEFT:
230+
if event.pressed and is_mouse_over():
231+
_panning = true
232+
else:
233+
_panning = false
234+
235+
var relative_mouse_pos := get_global_mouse_position() - get_global_rect().position
236+
237+
if is_mouse_over():
238+
var old_mouse_window_pos := canvas_to_window(relative_mouse_pos)
239+
240+
if event.button_index == MOUSE_BUTTON_WHEEL_UP and _window.scale.x < 2:
241+
_window.scale *= ZOOM_FACTOR
242+
if event.button_index == MOUSE_BUTTON_WHEEL_DOWN and _window.scale.x > 0.2:
243+
_window.scale /= ZOOM_FACTOR
244+
245+
_zoom_label.text = "%.1fx" % _window.scale.x
246+
247+
_window.position -= (old_mouse_window_pos - canvas_to_window(relative_mouse_pos)) * _window.scale.x
248+
249+
if event is InputEventMouseMotion:
250+
if Input.is_key_pressed(KEY_SHIFT) and _panning:
251+
_window.position += event.relative
252+
253+
254+
func canvas_to_window(v: Vector2) -> Vector2:
255+
return _window.get_transform().affine_inverse() * v
256+
257+
258+
func window_to_canvas(v: Vector2) -> Vector2:
259+
return _window.get_transform() * v
260+
261+
262+
func is_mouse_over() -> bool:
263+
return get_global_rect().has_point(get_global_mouse_position())

addons/block_code/ui/block_canvas/block_canvas.tscn

Lines changed: 39 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
[ext_resource type="Script" path="res://addons/block_code/ui/block_canvas/block_canvas.gd" id="1_tk8h2"]
44
[ext_resource type="Texture2D" uid="uid://cmusxj1ppspnp" path="res://addons/block_code/block_code_node/block_code_node.svg" id="2_710vn"]
55

6-
[sub_resource type="Image" id="Image_2jxnn"]
6+
[sub_resource type="Image" id="Image_0g48l"]
77
data = {
88
"data": PackedByteArray(255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 94, 94, 127, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 93, 93, 255, 255, 94, 94, 127, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 94, 94, 127, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 94, 94, 127, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 231, 255, 94, 94, 54, 255, 94, 94, 57, 255, 93, 93, 233, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 231, 255, 94, 94, 54, 255, 94, 94, 57, 255, 93, 93, 233, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 97, 97, 42, 255, 255, 255, 0, 255, 255, 255, 0, 255, 97, 97, 42, 255, 93, 93, 233, 255, 93, 93, 232, 255, 93, 93, 41, 255, 255, 255, 0, 255, 255, 255, 0, 255, 97, 97, 42, 255, 93, 93, 233, 255, 93, 93, 232, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 96, 96, 45, 255, 93, 93, 44, 255, 255, 255, 0, 255, 97, 97, 42, 255, 97, 97, 42, 255, 255, 255, 0, 255, 96, 96, 45, 255, 93, 93, 44, 255, 255, 255, 0, 255, 97, 97, 42, 255, 97, 97, 42, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 96, 96, 45, 255, 93, 93, 235, 255, 94, 94, 234, 255, 95, 95, 43, 255, 255, 255, 0, 255, 255, 255, 0, 255, 96, 96, 45, 255, 93, 93, 235, 255, 94, 94, 234, 255, 95, 95, 43, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 235, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 233, 255, 95, 95, 59, 255, 96, 96, 61, 255, 93, 93, 235, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 233, 255, 95, 95, 59, 255, 96, 96, 61, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0),
99
"format": "RGBA8",
@@ -13,7 +13,7 @@ data = {
1313
}
1414

1515
[sub_resource type="ImageTexture" id="ImageTexture_jgo72"]
16-
image = SubResource("Image_2jxnn")
16+
image = SubResource("Image_0g48l")
1717

1818
[node name="BlockCanvas" type="MarginContainer"]
1919
anchors_preset = 15
@@ -28,16 +28,50 @@ script = ExtResource("1_tk8h2")
2828
[node name="Panel" type="Panel" parent="."]
2929
layout_mode = 2
3030

31-
[node name="WindowScroll" type="ScrollContainer" parent="."]
32-
unique_name_in_owner = true
31+
[node name="WindowContainer" type="MarginContainer" parent="."]
32+
clip_contents = true
3333
layout_mode = 2
3434

35-
[node name="Window" type="Control" parent="WindowScroll"]
35+
[node name="Window" type="Control" parent="WindowContainer"]
3636
unique_name_in_owner = true
3737
layout_mode = 2
3838
size_flags_horizontal = 3
3939
mouse_filter = 1
4040

41+
[node name="Overlay" type="Control" parent="WindowContainer"]
42+
layout_mode = 2
43+
mouse_filter = 2
44+
45+
[node name="MarginContainer" type="MarginContainer" parent="WindowContainer/Overlay"]
46+
layout_mode = 1
47+
anchors_preset = 3
48+
anchor_left = 1.0
49+
anchor_top = 1.0
50+
anchor_right = 1.0
51+
anchor_bottom = 1.0
52+
offset_left = -40.0
53+
offset_top = -40.0
54+
grow_horizontal = 0
55+
grow_vertical = 0
56+
mouse_filter = 2
57+
theme_override_constants/margin_left = 4
58+
theme_override_constants/margin_top = 4
59+
theme_override_constants/margin_right = 4
60+
theme_override_constants/margin_bottom = 4
61+
62+
[node name="ZoomLabel" type="Label" parent="WindowContainer/Overlay/MarginContainer"]
63+
unique_name_in_owner = true
64+
layout_mode = 2
65+
theme_override_colors/font_color = Color(1, 1, 1, 0.196078)
66+
theme_override_font_sizes/font_size = 24
67+
text = "1x"
68+
horizontal_alignment = 2
69+
70+
[node name="MouseOverride" type="MarginContainer" parent="."]
71+
unique_name_in_owner = true
72+
layout_mode = 2
73+
mouse_filter = 2
74+
4175
[node name="EmptyBox" type="VBoxContainer" parent="."]
4276
unique_name_in_owner = true
4377
visible = false

0 commit comments

Comments
 (0)