Skip to content

Instantly share code, notes, and snippets.

@willnationsdev
Last active August 20, 2018 00:21
Show Gist options
  • Save willnationsdev/82e23911c0b40ec79b0c732e6dfa3ce6 to your computer and use it in GitHub Desktop.
Save willnationsdev/82e23911c0b40ec79b0c732e6dfa3ce6 to your computer and use it in GitHub Desktop.
VBoxItemList: A vertical list of Controls. + button to append new Control to list. X button beside each Control to remove that item. Optional enumerated label can be defined.
tool
extends VBoxContainer
class_name VBoxItemList
signal item_inserted(p_index, p_data)
signal item_removed(p_index, p_data)
const ICON_ADD: Texture = preload("../icons/icon_add.svg")
const ICON_DELETE: Texture = preload("../icons/icon_import_fail.svg")
export var title: String = "" setget set_title
export var item_prefix: String = "" setget set_item_prefix
export var item_script: Script = null setget set_item_script
export var item_scene: PackedScene = null setget set_item_scene
var label: Label
var add_button: ToolButton
var content: VBoxContainer
func _init(p_title: String = "", p_item_prefix: String = "", p_type: Resource = null):
if p_type:
if p_type is Script:
item_script = p_type
elif p_type is PackedScene:
item_scene = p_type
else:
printerr("'p_type' in VBoxItemList.new() is not a Script or PackedScene")
var main_toolbar := HBoxContainer.new()
main_toolbar.name = "Toolbar"
add_child(main_toolbar)
label = Label.new()
label.name = "Title"
label.text = p_title
main_toolbar.add_child(label)
add_button = ToolButton.new()
add_button.icon = ICON_ADD
add_button.name = "AddButton"
#warning-ignore:return_value_discarded
add_button.connect("pressed", self, "append_item")
main_toolbar.add_child(add_button)
content = VBoxContainer.new()
content.name = "Content"
add_child(content)
item_prefix = p_item_prefix
func insert_item(p_index: int) -> Control:
var node: Control = _get_node_from_type()
if not node:
return null
node.name = "Item"
var hbox := HBoxContainer.new()
var item_label := Label.new()
item_label.name = "ItemLabel"
hbox.add_child(item_label)
hbox.add_child(node)
var del_btn := ToolButton.new()
del_btn.icon = ICON_DELETE
hbox.add_child(del_btn)
var data := node._get_data() as Dictionary if node.has_method("_get_data") else {}
content.add_child(hbox)
if p_index >= 0:
content.move_child(node, p_index)
else:
p_index = len(content.get_children())-1
_reset_prefix_on_label(item_label, p_index)
#warning-ignore:return_value_discarded
del_btn.connect("pressed", self, "remove_item", [p_index])
_item_inserted(p_index, data)
emit_signal("item_inserted", p_index, data)
return node
func get_item(p_index: int) -> Control:
if p_index < 0:
return null
return content.get_child(p_index).get_node("Item") as Control
func append_item():
return insert_item(-1)
#warning-ignore:unused_argument
#warning-ignore:unused_argument
func _item_inserted(p_index: int, p_data: Dictionary):
pass
#warning-ignore:unused_argument
#warning-ignore:unused_argument
func _item_removed(p_index: int, p_data: Dictionary):
pass
func remove_item(p_idx: int):
var node := content.get_child(p_idx) as HBoxContainer
var data := node._get_data() as Dictionary if node.has_method("_get_data") else {}
node.free()
_reset_prefixes()
_item_removed(p_idx, data)
emit_signal("item_removed", p_idx, data)
func _get_node_from_type() -> Control:
var node: Control = null
if item_script:
node = item_script.new() as Control
elif item_scene:
node = item_scene.instance() as Control
else:
return null
return node
func set_title(p_value: String):
title = p_value
label.text = title
func set_item_prefix(p_value: String):
item_prefix = p_value
_reset_prefixes()
func _reset_prefixes():
var index: int = 0
for hbox in content.get_children():
var a_label := (hbox as HBoxContainer).get_node("ItemLabel") as Label
_reset_prefix_on_label(a_label, index)
index += 1
func _reset_prefix_on_label(p_label: Label, p_index: int = -1):
if not p_label:
return
if item_prefix:
p_label.text = "%s %d" % [item_prefix, len(content.get_children())-1 if p_index < 0 else p_index]
p_label.show()
else:
p_label.hide()
func set_item_script(p_value: Script):
if _validate_item_type(p_value):
item_script = p_value
func set_item_scene(p_value: PackedScene):
if _validate_item_type(p_value):
item_scene = p_value
func _validate_item_type(p_res: Resource) -> bool:
if not p_res:
return true
var node: Node = null
if p_res is Script:
node = p_res.new() as Control
elif p_res is PackedScene:
node = p_res.instance() as Control
else:
printerr("Item Resource is unassigned.")
return false
if not node:
printerr("An error occurred in creating a node from the Item Resource.")
return false
elif not node is Control:
printerr("Item Resource does not create a Control.")
return false
if not node.has_method("_get_data"):
printerr("Item does not implement '_get_data'")
return false
if node is Node:
node.queue_free()
return true
@willnationsdev
Copy link
Author

Updated to remove warnings.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment