canvas_2d.gd 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485
  1. extends Node2D
  2. signal element_selected(index: int)
  3. signal element_property_changed(index: int, position: Vector2, rotation: float, scale: Vector2, skew: float)
  4. signal element_action(index: int, action: String, data: Dictionary)
  5. signal asset_drop(asset_name: String, position: Vector2)
  6. @onready var camera = $Camera2D
  7. @onready var root: Sprite2D = $Root
  8. @onready var canvas_layer: CanvasLayer = $CanvasLayer
  9. @onready var free_transform: Sprite2D = $FreeTransform
  10. @onready var xaxis: Line2D = $Xaxis
  11. @onready var yaxis: Line2D = $Yaxis
  12. @onready var canvas_container: Control = $CanvasLayer/CanvasRoot/HBoxContainer/VBoxContainer/HBoxContainer2/CanvasContainer
  13. @onready var corner: Panel = $CanvasLayer/CanvasRoot/HBoxContainer/VBoxContainer/HBoxContainer/Corner1
  14. @onready var h_ruler: Panel = $CanvasLayer/CanvasRoot/HBoxContainer/VBoxContainer/HBoxContainer/HRuler
  15. @onready var v_ruler: Panel = $CanvasLayer/CanvasRoot/HBoxContainer/VBoxContainer/HBoxContainer2/VRuler
  16. @onready var tool_bar_panel: Panel = $CanvasLayer/CanvasRoot/HBoxContainer/VBoxContainer/HBoxContainer2/CanvasContainer/ToolBarPanel
  17. @onready var button_0: Button = $CanvasLayer/CanvasRoot/HBoxContainer/VBoxContainer/HBoxContainer2/CanvasContainer/ToolBarPanel/VBoxContainer/Panel/HBoxContainer/Button0
  18. @onready var button_1: Button = $CanvasLayer/CanvasRoot/HBoxContainer/VBoxContainer/HBoxContainer2/CanvasContainer/ToolBarPanel/VBoxContainer/Panel/HBoxContainer/Button1
  19. @onready var button_2: Button = $CanvasLayer/CanvasRoot/HBoxContainer/VBoxContainer/HBoxContainer2/CanvasContainer/ToolBarPanel/VBoxContainer/Panel/HBoxContainer/Button2
  20. @onready var button_3: Button = $CanvasLayer/CanvasRoot/HBoxContainer/VBoxContainer/HBoxContainer2/CanvasContainer/ToolBarPanel/VBoxContainer/Panel/HBoxContainer/Button3
  21. @onready var button_4: Button = $CanvasLayer/CanvasRoot/HBoxContainer/VBoxContainer/HBoxContainer2/CanvasContainer/ToolBarPanel/VBoxContainer/Panel/HBoxContainer/Button4
  22. @onready var asset_listview: Tree = $CanvasLayer/CanvasRoot/HBoxContainer/VBoxContainer/HBoxContainer2/CanvasContainer/ToolBarPanel/VBoxContainer/AssetListview
  23. @onready var v_scroll = $CanvasLayer/CanvasRoot/HBoxContainer/VBoxContainer2/VScrollBar
  24. @onready var h_scroll = $CanvasLayer/CanvasRoot/HBoxContainer/VBoxContainer/HBoxContainer3/HScrollBar
  25. @onready var zoom_line_edit: LineEdit = $CanvasLayer/CanvasRoot/HBoxContainer/VBoxContainer/HBoxContainer3/PanelContainer/HBoxContainer/ZoomLineEdit
  26. @onready var mouse_position_label: LineEdit = $CanvasLayer/CanvasRoot/HBoxContainer/VBoxContainer/HBoxContainer3/PanelContainer/HBoxContainer/MousePositionLabel
  27. var texture_up: Texture2D = preload("res://Resources/UI/Up.png")
  28. var texture_down: Texture2D = preload("res://Resources/UI/Down.png")
  29. var texture_delete: Texture2D = preload("res://Resources/UI/Trash.png")
  30. # 相机控制参数
  31. var min_zoom: int = 5
  32. var max_zoom: int = 1600
  33. var current_zoom: int = 25
  34. var allow_viewport: Rect2
  35. # 拖动相关变量
  36. var is_ready_dragging = false
  37. var is_dragging = false
  38. var camera_start_position = Vector2.ZERO
  39. var mouse_start_screen_position
  40. # element
  41. var sprites = {}
  42. var sprites_names = []
  43. var current_element: SpriteElement
  44. #
  45. var bg_buttons:Array[Button] = []
  46. var editable = false
  47. var mouse_in_canvas = false
  48. # use in all canvas
  49. static var bg_color;
  50. static var current_bg_button_index = -1;
  51. func _ready():
  52. current_element = null
  53. init_gui()
  54. RenderingServer.set_default_clear_color(Color(0.098, 0.098, 0.098))
  55. set_background(Vector2(2048, 2048), 0)
  56. zoom_camera(current_zoom)
  57. func _is_visible_in_tree():
  58. var parent_visible = true
  59. var p = get_parent()
  60. while p != null:
  61. if p is Control and p.visible == false:
  62. parent_visible = false
  63. break
  64. p = p.get_parent()
  65. return parent_visible
  66. func _input(event):
  67. if not _is_visible_in_tree():
  68. return
  69. if event is InputEventMouseButton:
  70. # 滚轮放大
  71. if event.button_index == MOUSE_BUTTON_WHEEL_UP and event.pressed:
  72. _zoom_camera_by_mouse_wheel(true)
  73. # 滚轮缩小
  74. elif event.button_index == MOUSE_BUTTON_WHEEL_DOWN and event.pressed:
  75. _zoom_camera_by_mouse_wheel(false)
  76. # 双击确认变换
  77. elif event.button_index == MOUSE_BUTTON_LEFT and event.double_click:
  78. if asset_listview.get_column_at_position(asset_listview.get_local_mouse_position()) == -1:
  79. cancle_free_transform()
  80. else:
  81. get_viewport().set_input_as_handled()
  82. # 右键拖拽画布
  83. elif event.button_index == MOUSE_BUTTON_RIGHT:
  84. if event.pressed:
  85. # 开始拖动
  86. is_dragging = true
  87. camera_start_position = camera.position
  88. mouse_start_screen_position = get_viewport().get_mouse_position()
  89. get_viewport().set_input_as_handled()
  90. else:
  91. # 结束拖动
  92. is_dragging = false
  93. # 空格+左键拖拽画布
  94. elif event.button_index == MOUSE_BUTTON_LEFT and Input.is_key_pressed(KEY_SPACE):
  95. # 检查空格键是否同时被按下
  96. if event.pressed:
  97. # 开始拖动
  98. is_dragging = true
  99. camera_start_position = camera.position
  100. mouse_start_screen_position = get_viewport().get_mouse_position()
  101. get_viewport().set_input_as_handled()
  102. else:
  103. # 结束拖动
  104. is_dragging = false
  105. # 鼠标拖动
  106. elif event is InputEventMouseMotion:
  107. var pos = get_global_mouse_position()
  108. mouse_position_label.text = "%d, %d" %[int(pos.x), int(pos.y)]
  109. if is_dragging:
  110. var current_screen_mouse = get_viewport().get_mouse_position()
  111. var screen_offset = mouse_start_screen_position - current_screen_mouse
  112. var world_offset = screen_offset / camera.zoom
  113. var new_position = camera_start_position + world_offset
  114. new_position.x = clamp(new_position.x, allow_viewport.position.x, allow_viewport.end.x)
  115. new_position.y = clamp(new_position.y, allow_viewport.position.y, allow_viewport.end.y)
  116. camera.position = new_position
  117. _update_scrollbars()
  118. get_viewport().set_input_as_handled()
  119. elif event is InputEventKey:
  120. if event.pressed and not event.echo:
  121. if event.ctrl_pressed and Input.is_key_pressed(KEY_KP_0):
  122. zoom_fit()
  123. elif event.ctrl_pressed and Input.is_key_pressed(KEY_KP_1):
  124. zoom_100()
  125. get_viewport().set_input_as_handled()
  126. elif Input.is_key_pressed(KEY_ENTER) or Input.is_key_pressed(KEY_KP_ENTER):
  127. cancle_free_transform()
  128. func _process(_delta: float) -> void:
  129. if not _is_visible_in_tree():
  130. return
  131. _update_ruler()
  132. var need_update_cursor = false
  133. if free_transform.is_dragging == true:
  134. need_update_cursor = true
  135. elif mouse_in_canvas:
  136. var subviewport_container = get_parent().get_parent()
  137. if subviewport_container is SubViewportContainer:
  138. var pos = subviewport_container.get_local_mouse_position()
  139. var rect = tool_bar_panel.get_rect()
  140. rect = Rect2(corner.size.x + rect.position.x, corner.size.y, rect.size.x, rect.size.y)
  141. if rect.has_point(pos):
  142. need_update_cursor = false
  143. else:
  144. rect = subviewport_container.get_rect()
  145. rect = Rect2(corner.size.x, corner.size.y, rect.size.x - corner.size.x * 2, rect.size.y - corner.size.y * 2)
  146. if rect.has_point(pos):
  147. need_update_cursor = true
  148. free_transform.update_free_transform(need_update_cursor)
  149. func init_gui():
  150. canvas_container.set_drag_forwarding(Callable(), _on_canvas_can_drop_data, _on_canvas_drop_data)
  151. free_transform.value_change.connect(_on_free_transform_value_change)
  152. # asset_listview
  153. asset_listview.columns = 5
  154. asset_listview.hide_root = true
  155. asset_listview.set_column_title(0, "ID")
  156. asset_listview.set_column_title(1, "Name")
  157. asset_listview.set_column_custom_minimum_width(0, 40)
  158. asset_listview.set_column_custom_minimum_width(2, 16)
  159. asset_listview.set_column_custom_minimum_width(3, 16)
  160. asset_listview.set_column_custom_minimum_width(4, 16)
  161. asset_listview.set_column_expand(0, false)
  162. asset_listview.set_column_expand(1, true)
  163. asset_listview.set_column_expand(2, false)
  164. asset_listview.set_column_expand(3, false)
  165. asset_listview.set_column_expand(4, false)
  166. asset_listview.item_selected.connect(_on_asset_listview_item_selected)
  167. asset_listview.nothing_selected.connect(_on_asset_listview_nothing_selected)
  168. # bg button
  169. bg_buttons.append(button_0)
  170. bg_buttons.append(button_1)
  171. bg_buttons.append(button_2)
  172. bg_buttons.append(button_3)
  173. bg_buttons.append(button_4)
  174. var button_group = ButtonGroup.new()
  175. for i in range(bg_buttons.size()):
  176. var btn = bg_buttons[i]
  177. btn.button_group = button_group
  178. btn.pressed.connect(_on_bg_button_pressed.bind(i))
  179. button_0.button_pressed = true
  180. # 连接滚动条信号
  181. v_scroll.value_changed.connect(_on_v_scroll_value_changed)
  182. h_scroll.value_changed.connect(_on_h_scroll_value_changed)
  183. zoom_line_edit.text_submitted.connect(_on_zoom_line_edit_text_submitted)
  184. func _on_bg_button_pressed(index):
  185. current_bg_button_index = index
  186. bg_buttons[index].button_pressed = true
  187. set_background(root.texture.get_size(), index)
  188. func _on_v_scroll_value_changed(value):
  189. camera.position.y = value
  190. _update_scrollbars()
  191. func _on_h_scroll_value_changed(value):
  192. camera.position.x = value
  193. _update_scrollbars()
  194. func _on_canvas_can_drop_data(at_position, data):
  195. return data is Dictionary and data.get("type") == "asset_panel_drag"
  196. func _on_canvas_drop_data(at_position, data):
  197. asset_drop.emit(data["data"]["asset_name"], get_global_mouse_position())
  198. func _on_asset_listview_item_selected():
  199. if asset_listview.get_selected() == null:
  200. current_element = null
  201. free_transform.set_target(null, -1)
  202. return
  203. var selected_item = asset_listview.get_selected()
  204. var index = selected_item.get_index()
  205. var column = asset_listview.get_column_at_position(asset_listview.get_local_mouse_position())
  206. match column:
  207. 2: element_action.emit(index, "UP", {})
  208. 3: element_action.emit(index, "DOWN", {})
  209. 4: element_action.emit(index, "REMOVE", {})
  210. _:
  211. current_element = sprites[int(selected_item.get_text(0))]
  212. if selected_item.get_text(1) != "__blank__":
  213. free_transform.set_target(current_element, index, editable)
  214. else:
  215. free_transform.set_target(current_element, index, false)
  216. element_selected.emit(index)
  217. func _on_asset_listview_nothing_selected():
  218. cancle_free_transform()
  219. func _on_zoom_line_edit_text_submitted(new_text: String):
  220. var new_zoom = new_text.replace(" ", "").replace("%", "")
  221. if new_zoom.is_valid_int():
  222. zoom_camera(int(new_zoom))
  223. elif new_zoom.is_valid_float():
  224. zoom_camera(int(float(new_zoom)))
  225. else:
  226. zoom_camera(current_zoom)
  227. zoom_line_edit.release_focus()
  228. func _on_free_transform_value_change(_index: int, _position: Vector2, _rotation: float, _scale: Vector2, _skew: float):
  229. var deg = fposmod(rad_to_deg(_rotation), 360)
  230. element_property_changed.emit(_index, _position, deg, _scale, _skew)
  231. func _zoom_camera_by_mouse_wheel(zoom_up: bool):
  232. var zoom_step = 0;
  233. if current_zoom < 100: zoom_step = 5
  234. elif current_zoom < 300: zoom_step = 20
  235. elif current_zoom < 500: zoom_step = 25
  236. elif current_zoom < 800: zoom_step = 50
  237. elif current_zoom <= 1600: zoom_step = 100
  238. if zoom_up: zoom_camera(current_zoom + zoom_step)
  239. else: zoom_camera(current_zoom - zoom_step)
  240. func _update_scrollbars():
  241. var bar_size = 0.4 * (allow_viewport.end.x - allow_viewport.position.x)
  242. h_scroll.min_value = allow_viewport.position.x
  243. h_scroll.max_value = allow_viewport.end.x + bar_size
  244. h_scroll.page = bar_size
  245. h_scroll.set_value_no_signal(camera.position.x)
  246. bar_size = 0.4 * (allow_viewport.end.y - allow_viewport.position.y)
  247. v_scroll.min_value = allow_viewport.position.y
  248. v_scroll.max_value = allow_viewport.end.y + bar_size
  249. v_scroll.page = bar_size
  250. v_scroll.set_value_no_signal(camera.position.y)
  251. _update_ruler()
  252. func _update_ruler():
  253. var viewport_size = get_viewport().get_visible_rect().size
  254. var corner_cover_size = corner.size / camera.zoom
  255. var visible_rect = viewport_size / camera.zoom
  256. var viewport_rect = Rect2(camera.position - visible_rect / 2 + corner_cover_size, visible_rect - 2.0 * corner_cover_size)
  257. var ruler_range = Vector4(viewport_rect.position.x, viewport_rect.position.y, viewport_rect.end.x, viewport_rect.end.y)
  258. var root_rect = root.get_rect()
  259. var highlight_range = Vector4(root_rect.position.x, root_rect.position.y, root_rect.end.x, root_rect.end.y)
  260. var mousr_pos = get_local_mouse_position()
  261. h_ruler.material.set_shader_parameter("ruler_size", h_ruler.size)
  262. h_ruler.material.set_shader_parameter("ruler_range", ruler_range)
  263. h_ruler.material.set_shader_parameter("highlight_range", highlight_range)
  264. h_ruler.material.set_shader_parameter("mouse_pos", mousr_pos)
  265. v_ruler.material.set_shader_parameter("ruler_size", v_ruler.size)
  266. v_ruler.material.set_shader_parameter("ruler_range", ruler_range)
  267. v_ruler.material.set_shader_parameter("highlight_range", highlight_range)
  268. v_ruler.material.set_shader_parameter("mouse_pos", mousr_pos)
  269. func zoom_camera(new_zoom: int):
  270. current_zoom = clamp(new_zoom, min_zoom, max_zoom)
  271. zoom_line_edit.text = "%d%%" % (current_zoom)
  272. var zoom = current_zoom / 100.0
  273. camera.zoom = Vector2(zoom, zoom)
  274. free_transform.zoom = zoom
  275. var visible_size = get_viewport().get_visible_rect().size / camera.zoom
  276. var sprite_size = root.texture.get_size()
  277. var corner_cover_size = corner.size / camera.zoom
  278. xaxis.width = 2.0 / zoom
  279. yaxis.width = 2.0 / zoom
  280. allow_viewport.position.x = min(-sprite_size.x, sprite_size.x - visible_size.x) / 2 + corner_cover_size.x
  281. allow_viewport.end.x = max(sprite_size.x, -sprite_size.x + visible_size.x) / 2 - corner_cover_size.x
  282. allow_viewport.position.y = min(-sprite_size.y, sprite_size.y - visible_size.y) / 2 + corner_cover_size.y
  283. allow_viewport.end.y = max(sprite_size.y, -sprite_size.y + visible_size.y) / 2 - corner_cover_size.y
  284. _update_scrollbars()
  285. set_background(root.texture.get_size())
  286. func zoom_fit():
  287. var visible_size = get_viewport().get_visible_rect().size
  288. var sprite_size = root.texture.get_size()
  289. var zoom = 0.8 * min(visible_size.x, visible_size.y) / max(sprite_size.x, sprite_size.y)
  290. zoom_camera(zoom * 100)
  291. camera.position = Vector2.ZERO
  292. func zoom_100():
  293. zoom_camera(100)
  294. camera.position = Vector2.ZERO
  295. func clear_all_sprites() -> void:
  296. sprites.clear()
  297. sprites_names.clear()
  298. for child in root.get_children():
  299. if child is Sprite2D:
  300. child.queue_free()
  301. asset_listview.clear()
  302. asset_listview.create_item() # root
  303. free_transform.set_target(null, -1)
  304. current_element = null
  305. func load_elements(elements_data, selected_index = -1):
  306. clear_all_sprites()
  307. var selected_item = null
  308. asset_listview.set_block_signals(true)
  309. for i in range(elements_data.size()):
  310. var element = elements_data[i]
  311. var sprite = SpriteElement.new()
  312. var asset_id = int(element["AssetId"])
  313. sprite.texture = AvatarDollDataMgr.get_asset(asset_id)
  314. var asset_name = AvatarDollDataMgr.get_asset_name(asset_id)
  315. root.add_child(sprite)
  316. sprite.position = Vector2(element["PositionX"], element["PositionY"])
  317. sprite.rotation = deg_to_rad(element["Rotation"])
  318. sprite.scale = Vector2(element["ScaleX"], element["ScaleY"])
  319. sprite.set_shader_param({})
  320. var item = asset_listview.create_item()
  321. item.set_cell_mode(2, TreeItem.CELL_MODE_ICON)
  322. item.set_cell_mode(3, TreeItem.CELL_MODE_ICON)
  323. item.set_cell_mode(4, TreeItem.CELL_MODE_ICON)
  324. item.set_text(0, str(i))
  325. item.set_text(1, asset_name)
  326. if editable:
  327. item.set_icon(2, texture_up)
  328. item.set_icon(3, texture_down)
  329. item.set_icon(4, texture_delete)
  330. if i == selected_index:
  331. selected_item = item
  332. sprites[i] = sprite
  333. sprites_names.append(asset_name)
  334. if selected_item:
  335. asset_listview.set_selected(selected_item, 0)
  336. current_element = sprites[int(selected_item.get_text(0))]
  337. if selected_item.get_text(1) != "__blank__":
  338. free_transform.set_target(current_element, selected_index, editable)
  339. else:
  340. free_transform.set_target(current_element, selected_index, false)
  341. asset_listview.set_block_signals(false)
  342. func update_element(index, element):
  343. var sprite = sprites[index]
  344. sprite.position = Vector2(element["PositionX"], element["PositionY"])
  345. sprite.rotation = deg_to_rad(element["Rotation"])
  346. sprite.scale = Vector2(element["ScaleX"], element["ScaleY"])
  347. free_transform.position = sprite.position
  348. free_transform.rotation = sprite.rotation
  349. free_transform.scale = sprite.scale
  350. func load_icon(icon_asset_id):
  351. clear_all_sprites()
  352. var asset_id = int(icon_asset_id)
  353. var asset_name = AvatarDollDataMgr.get_asset_name(asset_id)
  354. var item = asset_listview.create_item()
  355. item.set_cell_mode(2, TreeItem.CELL_MODE_ICON)
  356. item.set_cell_mode(3, TreeItem.CELL_MODE_ICON)
  357. item.set_cell_mode(4, TreeItem.CELL_MODE_ICON)
  358. item.set_text(0, "0")
  359. item.set_text(1, asset_name)
  360. if editable:
  361. item.set_icon(2, texture_up)
  362. item.set_icon(3, texture_down)
  363. item.set_icon(4, texture_delete)
  364. var sprite = SpriteElement.new()
  365. sprite.texture = AvatarDollDataMgr.get_asset(asset_id)
  366. sprites[0] = sprite
  367. root.add_child(sprite)
  368. func update_palette(element_index, palettes):
  369. if element_index >= 0 and element_index < sprites.size():
  370. var sprite = sprites[element_index]
  371. sprite.set_shader_param(palettes)
  372. func sync_background():
  373. if current_bg_button_index != -1:
  374. bg_buttons[current_bg_button_index].button_pressed = true
  375. func set_background(size: Vector2, background_type: int = -1):
  376. if root.texture == null or root.texture.get_size() != size:
  377. var image = Image.create(int(size.x), int(size.y), false, Image.FORMAT_RGBA8)
  378. image.fill(Color(0, 0, 0, 0))
  379. root.texture = ImageTexture.create_from_image(image)
  380. if background_type == 0: bg_color = Color.TRANSPARENT
  381. elif background_type == 1: bg_color = Color.WHITE
  382. elif background_type == 2: bg_color = Color(0.5, 0.5, 0.5, 1.0)
  383. elif background_type == 3: bg_color = Color(0.25, 0.25, 0.25, 1.0)
  384. elif background_type == 4: bg_color = Color.BLACK
  385. root.material.set_shader_parameter("bg_color", bg_color)
  386. root.material.set_shader_parameter("zoom", current_zoom / 100.0)
  387. func set_editable(_editable: bool):
  388. editable = _editable
  389. if editable == false:
  390. free_transform.set_target(null, -1)
  391. func set_selected(index):
  392. asset_listview.deselect_all()
  393. if index >= 0:
  394. current_element = sprites[index]
  395. asset_listview.set_selected(asset_listview.get_root().get_child(index), 0)
  396. func cancle_free_transform():
  397. asset_listview.deselect_all()
  398. free_transform.set_target(null, -1)
  399. current_element = null
  400. element_selected.emit(-1)
  401. func update_mouse_in_canvas(b: bool):
  402. mouse_in_canvas = b