extends VBoxContainer signal on_select_change(avatar_type: String, index: int, state_code: String) @onready var button_0: Button = $MarginContainer/VBoxContainer/HBoxContainer2/Button0 @onready var button_1: Button = $MarginContainer/VBoxContainer/HBoxContainer2/Button1 @onready var button_2: Button = $MarginContainer/VBoxContainer/HBoxContainer2/Button2 @onready var button_3: Button = $MarginContainer/VBoxContainer/HBoxContainer2/Button3 @onready var button_collapse: Button = $MarginContainer/VBoxContainer/HBoxContainer2/ButtonCollapse @onready var button_expand: Button = $MarginContainer/VBoxContainer/HBoxContainer2/ButtonExpand @onready var state_name_label: Label = $MarginContainer/VBoxContainer/StateNameLabel @onready var state_treeview: Tree = $MarginContainer/VBoxContainer/StateTreeview var avatar_type: String = "Clothes" var current_avatar_part = null var current_avatar_index = 0 var current_tree_item: TreeItem = null var current_state_code = "" var state_map = {} var icon_checked:Texture2D var icon_warning:Texture2D var filter_type = 0 var tree_max_depth = 0 var item_collection = {} func _ready() -> void: _init_gui() func _process(_delta: float) -> void: pass func _init_gui(): icon_checked = load("res://Resources/UI/checked.png") icon_warning = load("res://Resources/UI/warning.png") state_treeview.columns = 3 state_treeview.hide_root = true state_treeview.set_column_custom_minimum_width(1, 60) state_treeview.set_column_custom_minimum_width(2, 16) state_treeview.set_column_expand(0, true) state_treeview.set_column_expand(1, false) state_treeview.set_column_expand(2, false) state_treeview.item_selected.connect(_on_state_treeview_item_selected) state_treeview.item_activated.connect(_on_state_treeview_item_activated) state_treeview.create_item() var group = ButtonGroup.new() var buttons = [button_0, button_1, button_2, button_3] for i in range(buttons.size()): var button = buttons[i] button.button_group = group button.pressed.connect(_on_filter_button_pressed.bind(i)) button_collapse.pressed.connect(_on_button_collapse_pressed) button_expand.pressed.connect(_on_button_expand_pressed) func set_avatar_type(index, rebuild_tree: bool): current_avatar_index = index if current_avatar_index >= 0 and AvatarDollDataMgr.avatar_doll_data[avatar_type].size() > index: current_avatar_part = AvatarDollDataMgr.avatar_doll_data[avatar_type][index] update_data(rebuild_tree) func set_state_code(state_code): var item = state_treeview.get_root() for c in state_code: var index = AvatarDollDataMgr.get_state_index(c) item = item.get_child(index) if item == null: return state_treeview.set_selected(item, 0) state_treeview.scroll_to_item(item) _on_state_treeview_item_selected() func update_data(rebuild_tree: bool = false): if not AvatarDollDataMgr.initialed or avatar_type not in AvatarDollDataMgr.avatar_doll_data: state_treeview.clear() state_treeview.create_item() # root return #var old_index = current_avatar_index #var old_state = current_state_code var states = AvatarDollDataMgr.avatar_part_state[avatar_type] var root if rebuild_tree: state_treeview.clear() root = state_treeview.create_item() item_collection = {} if current_avatar_index >= 0: tree_max_depth = states.size() for i in range(tree_max_depth): item_collection[i] = [] _add_state_item(rebuild_tree, states, root) else: root = state_treeview.get_root() if current_avatar_index >= 0: _add_state_item(rebuild_tree, states, root) func _add_state_item(rebuild_tree, states: Array, parent: TreeItem, depth = 0, current_list = ["R"], state_code=""): if depth >= states.size(): var state_name = "/".join(current_list) var setup = current_avatar_part["Elements"].get(state_code, []).size() > 0 var requirment = current_list[0] == "R" if setup: parent.set_icon(2, icon_checked) elif requirment: parent.set_icon(2, icon_warning) else: parent.set_icon(2, null) if (filter_type == 1 and not setup) or \ (filter_type == 2 and not requirment) or \ (filter_type == 3 and not (requirment and not setup)): parent.visible = false else: parent.visible = true parent.set_metadata(0, state_name) parent.set_metadata(1, state_code) parent.set_metadata(2, Vector3i(1 if setup else 0, 1 if requirment else 0, 1)) parent.set_custom_color(0, Color.WHITE) else: var state = states[depth] var state_count = state["Values"].size() var item for i in range(state_count): var value = state["Values"][i] if rebuild_tree: item = parent.create_child() item_collection[depth].append(item) else: item = parent.get_child(i) var c = AvatarDollDataMgr.get_state_char(i) item.set_text(0, "%s %s" % [c, value]) item.set_cell_mode(2, TreeItem.CELL_MODE_ICON) var new_list = current_list + [value] var new_code = state_code + c if state["Required"][i] == false: new_list[0] = "N" _add_state_item(rebuild_tree, states, item, depth + 1, new_list, new_code) var parent_visible = false var total = Vector3i.ZERO var missing = false for child in parent.get_children(): if child.visible == true: parent_visible = true if child.get_icon(2) == icon_warning: missing = true total += child.get_metadata(2) parent.visible = parent_visible parent.set_text(1, "%d/%d/%d" % [total.x, total.y, total.z]) parent.set_text_alignment(1, HORIZONTAL_ALIGNMENT_RIGHT) parent.set_icon(2, icon_warning if missing else icon_checked) parent.set_metadata(2, total) parent.set_custom_color(0, Color(0.6, 0.6, 0.6)) func _on_filter_button_pressed(index): filter_type = index update_data() func _on_state_treeview_item_selected(): var item = state_treeview.get_selected() var state_name = item.get_metadata(0) var state_code = item.get_metadata(1) if state_code != null: var parent if current_tree_item != null: current_tree_item.clear_custom_bg_color(0) current_tree_item.clear_custom_bg_color(1) current_tree_item.clear_custom_bg_color(2) parent = current_tree_item.get_parent() while parent != state_treeview.get_root(): parent.clear_custom_bg_color(0) parent.clear_custom_bg_color(1) parent.clear_custom_bg_color(2) parent = parent.get_parent() var color = Color(0.0, 0.6, 0.8, 1.0) item.set_custom_bg_color(0, color) item.set_custom_bg_color(1, color) item.set_custom_bg_color(2, color) color = Color(0.0, 0.3, 0.4, 1.0) parent = item.get_parent() while parent != state_treeview.get_root(): parent.set_custom_bg_color(0, color) parent.set_custom_bg_color(1, color) parent.set_custom_bg_color(2, color) parent = parent.get_parent() current_tree_item = item current_state_code = state_code state_name_label.text = "%s %s" % [state_code, state_name.substr(2)] on_select_change.emit(avatar_type, current_avatar_index, state_code) print("State: ", state_name, " ", state_code) pass func _on_state_treeview_item_activated(): var item = state_treeview.get_selected() var state_code = item.get_metadata(1) if state_code == null: item.collapsed = not item.collapsed func _on_button_collapse_pressed(): if not AvatarDollDataMgr.initialed: return var result = _collect_tree_item_collapse_and_expand(state_treeview.get_root(), tree_max_depth - 1) var max_expand = result[1] while max_expand < tree_max_depth: for item in item_collection[max_expand - 1]: item.collapsed = true max_expand += 1 func _on_button_expand_pressed(): if not AvatarDollDataMgr.initialed: return var result = _collect_tree_item_collapse_and_expand(state_treeview.get_root(), tree_max_depth - 1) var min_collapse = result[0] while min_collapse > 0: for item in item_collection[min_collapse - 1]: item.collapsed = false min_collapse -= 1 func _collect_tree_item_collapse_and_expand(parent: TreeItem, min_collapse:int = 9999, max_expand:int = 1, depth = 0): if parent.get_child_count() == 0: return [9999, 0] var all_collapsed = false for item in parent.get_children(): if item.collapsed: min_collapse = min(min_collapse, depth + 1) else: all_collapsed = false var result = _collect_tree_item_collapse_and_expand(item, min_collapse, depth + 1, depth + 1) min_collapse = min(min_collapse, result[0]) max_expand = max(max_expand, result[1]) if all_collapsed: return [min_collapse, depth] else: return [min_collapse, max_expand]