class_name EditableHorizontalList extends HBoxContainer @onready var item_array: Array[EditableHorizontalListItem] = [] @onready var item_container := ( $'ItemsScrollContainer/Items' as HBoxContainer ) @onready var button_push_item := ( $'PushItemMargin/PushItem' as Button ) @onready var button_pop_item := ( $'PopItemMargin/PopItem' as Button ) @onready var button_clear_list := ( $'ClearListMargin/ClearList' as Button ) signal new_item_needs_content(item: EditableHorizontalListItem) func _ready() -> void: button_push_item.pressed.connect(_on_push_item_clicked) button_pop_item.pressed.connect(_on_pop_item_clicked) button_clear_list.pressed.connect(_on_clear_list_clicked) for descendant in item_container.get_children(): if descendant is EditableHorizontalListItem: item_array.push_back(descendant) descendant.insert_before_clicked.connect(_fulfill_insert_before) descendant.shift_back_clicked.connect(_fulfill_shift_back) descendant.remove_clicked.connect(_fulfill_remove) descendant.shift_forward_clicked.connect(_fulfill_shift_forward) descendant.insert_after_clicked.connect(_fulfill_insert_after) else: push_warning(( "Non-EditableHorizontalListItem child of Items container " + "will be deleted: %s" ) % descendant) item_container.remove_child(descendant) descendant.queue_free() reorganize() func reorganize() -> void: for item in item_array: if item.get_parent() == item_container: item_container.remove_child(item) for descendant in item_container.get_children(): push_warning( "Unexpected child of Items container will be deleted: %s" % descendant ) item_container.remove_child(descendant) descendant.queue_free() for item in item_array: item_container.add_child(item) item.button_shift_back.disabled = false item.button_shift_forward.disabled = false if item_array.is_empty(): button_pop_item.disabled = true button_clear_list.disabled = true else: var first := item_array[0] var last := item_array[item_array.size() - 1] first.button_shift_back.disabled = true last.button_shift_forward.disabled = true button_pop_item.disabled = false button_clear_list.disabled = false func insert(index: int = -1) -> EditableHorizontalListItem: var item := ( preload('res://ui/EditableHorizontalListItem.tscn').instantiate() ) as EditableHorizontalListItem if index >= 0 and index < item_array.size(): item_array.insert(index, item) else: item_array.push_back(item) item.insert_before_clicked.connect(_fulfill_insert_before) item.shift_back_clicked.connect(_fulfill_shift_back) item.remove_clicked.connect(_fulfill_remove) item.shift_forward_clicked.connect(_fulfill_shift_forward) item.insert_after_clicked.connect(_fulfill_insert_after) reorganize() new_item_needs_content.emit(item) return item func remove(index: int = -1) -> bool: var item: EditableHorizontalListItem = null if index >= 0 and index < item_array.size(): item = item_array[index] item_array.remove_at(index) elif item_array.is_empty(): return false else: item = item_array[item_array.size() - 1] item_array.pop_back() item.insert_before_clicked.disconnect(_fulfill_insert_before) item.shift_back_clicked.disconnect(_fulfill_shift_back) item.remove_clicked.disconnect(_fulfill_remove) item.shift_forward_clicked.disconnect(_fulfill_shift_forward) item.insert_after_clicked.disconnect(_fulfill_insert_after) if item.get_parent() == item_container: item_container.remove_child(item) item.queue_free() reorganize() return true func shift_back(index: int) -> bool: if index > 0 and index < item_array.size(): var a := item_array[index - 1] var b := item_array[index] item_array[index] = a item_array[index - 1] = b reorganize() return true else: return false func shift_forward(index: int) -> bool: if index >= 0 and index < item_array.size() - 1: var a := item_array[index] var b := item_array[index + 1] item_array[index + 1] = a item_array[index] = b reorganize() return true else: return false func clear() -> void: for item in item_array: item.insert_before_clicked.disconnect(_fulfill_insert_before) item.shift_back_clicked.disconnect(_fulfill_shift_back) item.remove_clicked.disconnect(_fulfill_remove) item.shift_forward_clicked.disconnect(_fulfill_shift_forward) item.insert_after_clicked.disconnect(_fulfill_insert_after) if item.get_parent() == item_container: item_container.remove_child(item) item.queue_free() for descendant in item_container.get_children(): push_warning( "Unexpected child of Items container will be deleted: %s" % descendant ) item_container.remove_child(descendant) descendant.queue_free() item_array.clear() func size() -> int: return item_array.size() func _fulfill_insert_before(item: EditableHorizontalListItem) -> void: var index := item_array.find(item) if index >= 0: insert(index) func _fulfill_shift_back(item: EditableHorizontalListItem) -> void: var index := item_array.find(item) if index >= 0: shift_back(index) func _fulfill_remove(item: EditableHorizontalListItem) -> void: var index := item_array.find(item) if index >= 0: remove(index) func _fulfill_shift_forward(item: EditableHorizontalListItem) -> void: var index := item_array.find(item) if index >= 0: shift_forward(index) func _fulfill_insert_after(item: EditableHorizontalListItem) -> void: var index := item_array.find(item) if index >= 0: insert(index + 1) func _on_push_item_clicked() -> void: insert() func _on_pop_item_clicked() -> void: remove() func _on_clear_list_clicked() -> void: clear()