| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485 |
- extends Node2D
- signal element_selected(index: int)
- signal element_property_changed(index: int, position: Vector2, rotation: float, scale: Vector2, skew: float)
- signal element_action(index: int, action: String, data: Dictionary)
- signal asset_drop(asset_name: String, position: Vector2)
- @onready var camera = $Camera2D
- @onready var root: Sprite2D = $Root
- @onready var canvas_layer: CanvasLayer = $CanvasLayer
- @onready var free_transform: Sprite2D = $FreeTransform
- @onready var xaxis: Line2D = $Xaxis
- @onready var yaxis: Line2D = $Yaxis
- @onready var canvas_container: Control = $CanvasLayer/CanvasRoot/HBoxContainer/VBoxContainer/HBoxContainer2/CanvasContainer
- @onready var corner: Panel = $CanvasLayer/CanvasRoot/HBoxContainer/VBoxContainer/HBoxContainer/Corner1
- @onready var h_ruler: Panel = $CanvasLayer/CanvasRoot/HBoxContainer/VBoxContainer/HBoxContainer/HRuler
- @onready var v_ruler: Panel = $CanvasLayer/CanvasRoot/HBoxContainer/VBoxContainer/HBoxContainer2/VRuler
- @onready var tool_bar_panel: Panel = $CanvasLayer/CanvasRoot/HBoxContainer/VBoxContainer/HBoxContainer2/CanvasContainer/ToolBarPanel
- @onready var button_0: Button = $CanvasLayer/CanvasRoot/HBoxContainer/VBoxContainer/HBoxContainer2/CanvasContainer/ToolBarPanel/VBoxContainer/Panel/HBoxContainer/Button0
- @onready var button_1: Button = $CanvasLayer/CanvasRoot/HBoxContainer/VBoxContainer/HBoxContainer2/CanvasContainer/ToolBarPanel/VBoxContainer/Panel/HBoxContainer/Button1
- @onready var button_2: Button = $CanvasLayer/CanvasRoot/HBoxContainer/VBoxContainer/HBoxContainer2/CanvasContainer/ToolBarPanel/VBoxContainer/Panel/HBoxContainer/Button2
- @onready var button_3: Button = $CanvasLayer/CanvasRoot/HBoxContainer/VBoxContainer/HBoxContainer2/CanvasContainer/ToolBarPanel/VBoxContainer/Panel/HBoxContainer/Button3
- @onready var button_4: Button = $CanvasLayer/CanvasRoot/HBoxContainer/VBoxContainer/HBoxContainer2/CanvasContainer/ToolBarPanel/VBoxContainer/Panel/HBoxContainer/Button4
- @onready var asset_listview: Tree = $CanvasLayer/CanvasRoot/HBoxContainer/VBoxContainer/HBoxContainer2/CanvasContainer/ToolBarPanel/VBoxContainer/AssetListview
- @onready var v_scroll = $CanvasLayer/CanvasRoot/HBoxContainer/VBoxContainer2/VScrollBar
- @onready var h_scroll = $CanvasLayer/CanvasRoot/HBoxContainer/VBoxContainer/HBoxContainer3/HScrollBar
- @onready var zoom_line_edit: LineEdit = $CanvasLayer/CanvasRoot/HBoxContainer/VBoxContainer/HBoxContainer3/PanelContainer/HBoxContainer/ZoomLineEdit
- @onready var mouse_position_label: LineEdit = $CanvasLayer/CanvasRoot/HBoxContainer/VBoxContainer/HBoxContainer3/PanelContainer/HBoxContainer/MousePositionLabel
- var texture_up: Texture2D = preload("res://Resources/UI/Up.png")
- var texture_down: Texture2D = preload("res://Resources/UI/Down.png")
- var texture_delete: Texture2D = preload("res://Resources/UI/Trash.png")
- # 相机控制参数
- var min_zoom: int = 5
- var max_zoom: int = 1600
- var current_zoom: int = 25
- var allow_viewport: Rect2
- # 拖动相关变量
- var is_ready_dragging = false
- var is_dragging = false
- var camera_start_position = Vector2.ZERO
- var mouse_start_screen_position
- # element
- var sprites = {}
- var sprites_names = []
- var current_element: SpriteElement
- #
- var bg_buttons:Array[Button] = []
- var editable = false
- var mouse_in_canvas = false
- # use in all canvas
- static var bg_color;
- static var current_bg_button_index = -1;
- func _ready():
- current_element = null
- init_gui()
-
- RenderingServer.set_default_clear_color(Color(0.098, 0.098, 0.098))
- set_background(Vector2(2048, 2048), 0)
- zoom_camera(current_zoom)
- func _is_visible_in_tree():
- var parent_visible = true
- var p = get_parent()
- while p != null:
- if p is Control and p.visible == false:
- parent_visible = false
- break
- p = p.get_parent()
- return parent_visible
- func _input(event):
- if not _is_visible_in_tree():
- return
-
- if event is InputEventMouseButton:
- # 滚轮放大
- if event.button_index == MOUSE_BUTTON_WHEEL_UP and event.pressed:
- _zoom_camera_by_mouse_wheel(true)
-
- # 滚轮缩小
- elif event.button_index == MOUSE_BUTTON_WHEEL_DOWN and event.pressed:
- _zoom_camera_by_mouse_wheel(false)
-
- # 双击确认变换
- elif event.button_index == MOUSE_BUTTON_LEFT and event.double_click:
- if asset_listview.get_column_at_position(asset_listview.get_local_mouse_position()) == -1:
- cancle_free_transform()
- else:
- get_viewport().set_input_as_handled()
-
- # 右键拖拽画布
- elif event.button_index == MOUSE_BUTTON_RIGHT:
- if event.pressed:
- # 开始拖动
- is_dragging = true
- camera_start_position = camera.position
- mouse_start_screen_position = get_viewport().get_mouse_position()
- get_viewport().set_input_as_handled()
- else:
- # 结束拖动
- is_dragging = false
-
- # 空格+左键拖拽画布
- elif event.button_index == MOUSE_BUTTON_LEFT and Input.is_key_pressed(KEY_SPACE):
- # 检查空格键是否同时被按下
- if event.pressed:
- # 开始拖动
- is_dragging = true
- camera_start_position = camera.position
- mouse_start_screen_position = get_viewport().get_mouse_position()
- get_viewport().set_input_as_handled()
- else:
- # 结束拖动
- is_dragging = false
-
- # 鼠标拖动
- elif event is InputEventMouseMotion:
- var pos = get_global_mouse_position()
- mouse_position_label.text = "%d, %d" %[int(pos.x), int(pos.y)]
-
- if is_dragging:
- var current_screen_mouse = get_viewport().get_mouse_position()
- var screen_offset = mouse_start_screen_position - current_screen_mouse
- var world_offset = screen_offset / camera.zoom
- var new_position = camera_start_position + world_offset
- new_position.x = clamp(new_position.x, allow_viewport.position.x, allow_viewport.end.x)
- new_position.y = clamp(new_position.y, allow_viewport.position.y, allow_viewport.end.y)
- camera.position = new_position
- _update_scrollbars()
- get_viewport().set_input_as_handled()
-
- elif event is InputEventKey:
- if event.pressed and not event.echo:
- if event.ctrl_pressed and Input.is_key_pressed(KEY_KP_0):
- zoom_fit()
-
- elif event.ctrl_pressed and Input.is_key_pressed(KEY_KP_1):
- zoom_100()
- get_viewport().set_input_as_handled()
-
- elif Input.is_key_pressed(KEY_ENTER) or Input.is_key_pressed(KEY_KP_ENTER):
- cancle_free_transform()
-
- func _process(_delta: float) -> void:
- if not _is_visible_in_tree():
- return
-
- _update_ruler()
- var need_update_cursor = false
- if free_transform.is_dragging == true:
- need_update_cursor = true
- elif mouse_in_canvas:
- var subviewport_container = get_parent().get_parent()
- if subviewport_container is SubViewportContainer:
- var pos = subviewport_container.get_local_mouse_position()
- var rect = tool_bar_panel.get_rect()
- rect = Rect2(corner.size.x + rect.position.x, corner.size.y, rect.size.x, rect.size.y)
- if rect.has_point(pos):
- need_update_cursor = false
- else:
- rect = subviewport_container.get_rect()
- rect = Rect2(corner.size.x, corner.size.y, rect.size.x - corner.size.x * 2, rect.size.y - corner.size.y * 2)
- if rect.has_point(pos):
- need_update_cursor = true
-
- free_transform.update_free_transform(need_update_cursor)
-
- func init_gui():
- canvas_container.set_drag_forwarding(Callable(), _on_canvas_can_drop_data, _on_canvas_drop_data)
- free_transform.value_change.connect(_on_free_transform_value_change)
-
- # asset_listview
- asset_listview.columns = 5
- asset_listview.hide_root = true
- asset_listview.set_column_title(0, "ID")
- asset_listview.set_column_title(1, "Name")
- asset_listview.set_column_custom_minimum_width(0, 40)
- asset_listview.set_column_custom_minimum_width(2, 16)
- asset_listview.set_column_custom_minimum_width(3, 16)
- asset_listview.set_column_custom_minimum_width(4, 16)
- asset_listview.set_column_expand(0, false)
- asset_listview.set_column_expand(1, true)
- asset_listview.set_column_expand(2, false)
- asset_listview.set_column_expand(3, false)
- asset_listview.set_column_expand(4, false)
- asset_listview.item_selected.connect(_on_asset_listview_item_selected)
- asset_listview.nothing_selected.connect(_on_asset_listview_nothing_selected)
-
- # bg button
- bg_buttons.append(button_0)
- bg_buttons.append(button_1)
- bg_buttons.append(button_2)
- bg_buttons.append(button_3)
- bg_buttons.append(button_4)
- var button_group = ButtonGroup.new()
- for i in range(bg_buttons.size()):
- var btn = bg_buttons[i]
- btn.button_group = button_group
- btn.pressed.connect(_on_bg_button_pressed.bind(i))
- button_0.button_pressed = true
-
- # 连接滚动条信号
- v_scroll.value_changed.connect(_on_v_scroll_value_changed)
- h_scroll.value_changed.connect(_on_h_scroll_value_changed)
- zoom_line_edit.text_submitted.connect(_on_zoom_line_edit_text_submitted)
- func _on_bg_button_pressed(index):
- current_bg_button_index = index
- bg_buttons[index].button_pressed = true
- set_background(root.texture.get_size(), index)
- func _on_v_scroll_value_changed(value):
- camera.position.y = value
- _update_scrollbars()
- func _on_h_scroll_value_changed(value):
- camera.position.x = value
- _update_scrollbars()
- func _on_canvas_can_drop_data(at_position, data):
- return data is Dictionary and data.get("type") == "asset_panel_drag"
-
- func _on_canvas_drop_data(at_position, data):
- asset_drop.emit(data["data"]["asset_name"], get_global_mouse_position())
- func _on_asset_listview_item_selected():
- if asset_listview.get_selected() == null:
- current_element = null
- free_transform.set_target(null, -1)
- return
-
- var selected_item = asset_listview.get_selected()
- var index = selected_item.get_index()
- var column = asset_listview.get_column_at_position(asset_listview.get_local_mouse_position())
- match column:
- 2: element_action.emit(index, "UP", {})
- 3: element_action.emit(index, "DOWN", {})
- 4: element_action.emit(index, "REMOVE", {})
- _:
- current_element = sprites[int(selected_item.get_text(0))]
- if selected_item.get_text(1) != "__blank__":
- free_transform.set_target(current_element, index, editable)
- else:
- free_transform.set_target(current_element, index, false)
- element_selected.emit(index)
-
- func _on_asset_listview_nothing_selected():
- cancle_free_transform()
-
- func _on_zoom_line_edit_text_submitted(new_text: String):
- var new_zoom = new_text.replace(" ", "").replace("%", "")
- if new_zoom.is_valid_int():
- zoom_camera(int(new_zoom))
- elif new_zoom.is_valid_float():
- zoom_camera(int(float(new_zoom)))
- else:
- zoom_camera(current_zoom)
- zoom_line_edit.release_focus()
-
- func _on_free_transform_value_change(_index: int, _position: Vector2, _rotation: float, _scale: Vector2, _skew: float):
- var deg = fposmod(rad_to_deg(_rotation), 360)
- element_property_changed.emit(_index, _position, deg, _scale, _skew)
- func _zoom_camera_by_mouse_wheel(zoom_up: bool):
- var zoom_step = 0;
- if current_zoom < 100: zoom_step = 5
- elif current_zoom < 300: zoom_step = 20
- elif current_zoom < 500: zoom_step = 25
- elif current_zoom < 800: zoom_step = 50
- elif current_zoom <= 1600: zoom_step = 100
-
- if zoom_up: zoom_camera(current_zoom + zoom_step)
- else: zoom_camera(current_zoom - zoom_step)
- func _update_scrollbars():
- var bar_size = 0.4 * (allow_viewport.end.x - allow_viewport.position.x)
- h_scroll.min_value = allow_viewport.position.x
- h_scroll.max_value = allow_viewport.end.x + bar_size
- h_scroll.page = bar_size
- h_scroll.set_value_no_signal(camera.position.x)
-
- bar_size = 0.4 * (allow_viewport.end.y - allow_viewport.position.y)
- v_scroll.min_value = allow_viewport.position.y
- v_scroll.max_value = allow_viewport.end.y + bar_size
- v_scroll.page = bar_size
- v_scroll.set_value_no_signal(camera.position.y)
- _update_ruler()
-
- func _update_ruler():
- var viewport_size = get_viewport().get_visible_rect().size
-
- var corner_cover_size = corner.size / camera.zoom
- var visible_rect = viewport_size / camera.zoom
-
- var viewport_rect = Rect2(camera.position - visible_rect / 2 + corner_cover_size, visible_rect - 2.0 * corner_cover_size)
- var ruler_range = Vector4(viewport_rect.position.x, viewport_rect.position.y, viewport_rect.end.x, viewport_rect.end.y)
-
- var root_rect = root.get_rect()
- var highlight_range = Vector4(root_rect.position.x, root_rect.position.y, root_rect.end.x, root_rect.end.y)
-
- var mousr_pos = get_local_mouse_position()
-
- h_ruler.material.set_shader_parameter("ruler_size", h_ruler.size)
- h_ruler.material.set_shader_parameter("ruler_range", ruler_range)
- h_ruler.material.set_shader_parameter("highlight_range", highlight_range)
- h_ruler.material.set_shader_parameter("mouse_pos", mousr_pos)
-
- v_ruler.material.set_shader_parameter("ruler_size", v_ruler.size)
- v_ruler.material.set_shader_parameter("ruler_range", ruler_range)
- v_ruler.material.set_shader_parameter("highlight_range", highlight_range)
- v_ruler.material.set_shader_parameter("mouse_pos", mousr_pos)
- func zoom_camera(new_zoom: int):
- current_zoom = clamp(new_zoom, min_zoom, max_zoom)
- zoom_line_edit.text = "%d%%" % (current_zoom)
- var zoom = current_zoom / 100.0
- camera.zoom = Vector2(zoom, zoom)
- free_transform.zoom = zoom
-
- var visible_size = get_viewport().get_visible_rect().size / camera.zoom
- var sprite_size = root.texture.get_size()
- var corner_cover_size = corner.size / camera.zoom
-
- xaxis.width = 2.0 / zoom
- yaxis.width = 2.0 / zoom
-
- allow_viewport.position.x = min(-sprite_size.x, sprite_size.x - visible_size.x) / 2 + corner_cover_size.x
- allow_viewport.end.x = max(sprite_size.x, -sprite_size.x + visible_size.x) / 2 - corner_cover_size.x
- allow_viewport.position.y = min(-sprite_size.y, sprite_size.y - visible_size.y) / 2 + corner_cover_size.y
- allow_viewport.end.y = max(sprite_size.y, -sprite_size.y + visible_size.y) / 2 - corner_cover_size.y
- _update_scrollbars()
- set_background(root.texture.get_size())
-
- func zoom_fit():
- var visible_size = get_viewport().get_visible_rect().size
- var sprite_size = root.texture.get_size()
- var zoom = 0.8 * min(visible_size.x, visible_size.y) / max(sprite_size.x, sprite_size.y)
- zoom_camera(zoom * 100)
- camera.position = Vector2.ZERO
-
- func zoom_100():
- zoom_camera(100)
- camera.position = Vector2.ZERO
-
- func clear_all_sprites() -> void:
- sprites.clear()
- sprites_names.clear()
- for child in root.get_children():
- if child is Sprite2D:
- child.queue_free()
-
- asset_listview.clear()
- asset_listview.create_item() # root
- free_transform.set_target(null, -1)
- current_element = null
- func load_elements(elements_data, selected_index = -1):
- clear_all_sprites()
-
- var selected_item = null
- asset_listview.set_block_signals(true)
- for i in range(elements_data.size()):
- var element = elements_data[i]
- var sprite = SpriteElement.new()
- var asset_id = int(element["AssetId"])
- sprite.texture = AvatarDollDataMgr.get_asset(asset_id)
- var asset_name = AvatarDollDataMgr.get_asset_name(asset_id)
- root.add_child(sprite)
-
- sprite.position = Vector2(element["PositionX"], element["PositionY"])
- sprite.rotation = deg_to_rad(element["Rotation"])
- sprite.scale = Vector2(element["ScaleX"], element["ScaleY"])
- sprite.set_shader_param({})
-
- var item = asset_listview.create_item()
- item.set_cell_mode(2, TreeItem.CELL_MODE_ICON)
- item.set_cell_mode(3, TreeItem.CELL_MODE_ICON)
- item.set_cell_mode(4, TreeItem.CELL_MODE_ICON)
- item.set_text(0, str(i))
- item.set_text(1, asset_name)
- if editable:
- item.set_icon(2, texture_up)
- item.set_icon(3, texture_down)
- item.set_icon(4, texture_delete)
-
- if i == selected_index:
- selected_item = item
-
- sprites[i] = sprite
- sprites_names.append(asset_name)
-
- if selected_item:
- asset_listview.set_selected(selected_item, 0)
- current_element = sprites[int(selected_item.get_text(0))]
- if selected_item.get_text(1) != "__blank__":
- free_transform.set_target(current_element, selected_index, editable)
- else:
- free_transform.set_target(current_element, selected_index, false)
-
- asset_listview.set_block_signals(false)
-
- func update_element(index, element):
- var sprite = sprites[index]
- sprite.position = Vector2(element["PositionX"], element["PositionY"])
- sprite.rotation = deg_to_rad(element["Rotation"])
- sprite.scale = Vector2(element["ScaleX"], element["ScaleY"])
-
- free_transform.position = sprite.position
- free_transform.rotation = sprite.rotation
- free_transform.scale = sprite.scale
- func load_icon(icon_asset_id):
- clear_all_sprites()
- var asset_id = int(icon_asset_id)
- var asset_name = AvatarDollDataMgr.get_asset_name(asset_id)
-
- var item = asset_listview.create_item()
- item.set_cell_mode(2, TreeItem.CELL_MODE_ICON)
- item.set_cell_mode(3, TreeItem.CELL_MODE_ICON)
- item.set_cell_mode(4, TreeItem.CELL_MODE_ICON)
- item.set_text(0, "0")
- item.set_text(1, asset_name)
- if editable:
- item.set_icon(2, texture_up)
- item.set_icon(3, texture_down)
- item.set_icon(4, texture_delete)
-
- var sprite = SpriteElement.new()
- sprite.texture = AvatarDollDataMgr.get_asset(asset_id)
- sprites[0] = sprite
- root.add_child(sprite)
- func update_palette(element_index, palettes):
- if element_index >= 0 and element_index < sprites.size():
- var sprite = sprites[element_index]
- sprite.set_shader_param(palettes)
- func sync_background():
- if current_bg_button_index != -1:
- bg_buttons[current_bg_button_index].button_pressed = true
- func set_background(size: Vector2, background_type: int = -1):
- if root.texture == null or root.texture.get_size() != size:
- var image = Image.create(int(size.x), int(size.y), false, Image.FORMAT_RGBA8)
- image.fill(Color(0, 0, 0, 0))
- root.texture = ImageTexture.create_from_image(image)
-
- if background_type == 0: bg_color = Color.TRANSPARENT
- elif background_type == 1: bg_color = Color.WHITE
- elif background_type == 2: bg_color = Color(0.5, 0.5, 0.5, 1.0)
- elif background_type == 3: bg_color = Color(0.25, 0.25, 0.25, 1.0)
- elif background_type == 4: bg_color = Color.BLACK
-
- root.material.set_shader_parameter("bg_color", bg_color)
- root.material.set_shader_parameter("zoom", current_zoom / 100.0)
- func set_editable(_editable: bool):
- editable = _editable
- if editable == false:
- free_transform.set_target(null, -1)
- func set_selected(index):
- asset_listview.deselect_all()
- if index >= 0:
- current_element = sprites[index]
- asset_listview.set_selected(asset_listview.get_root().get_child(index), 0)
- func cancle_free_transform():
- asset_listview.deselect_all()
- free_transform.set_target(null, -1)
- current_element = null
- element_selected.emit(-1)
- func update_mouse_in_canvas(b: bool):
- mouse_in_canvas = b
|