import progress
This commit is contained in:
parent
bae51f23ee
commit
cdc4e3f14e
29
ControlTree.gd
Normal file
29
ControlTree.gd
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
extends Control
|
||||||
|
class_name ControlTree
|
||||||
|
|
||||||
|
export(PackedScene) var item_scene: PackedScene
|
||||||
|
|
||||||
|
export(bool) var allow_multi_select: bool = false
|
||||||
|
|
||||||
|
onready var items_container: VBoxContainer = $"%Items"
|
||||||
|
|
||||||
|
var items: Array = []
|
||||||
|
|
||||||
|
var item_select_btn_group: ButtonGroup = ButtonGroup.new()
|
||||||
|
|
||||||
|
|
||||||
|
func add_item(text: String, parent_item: ControlTreeItem = null) -> ControlTreeItem:
|
||||||
|
var new_item: ControlTreeItem = item_scene.instance()
|
||||||
|
|
||||||
|
if !parent_item:
|
||||||
|
items_container.add_child(new_item)
|
||||||
|
items.append(new_item)
|
||||||
|
else:
|
||||||
|
parent_item.add_subitem(new_item)
|
||||||
|
|
||||||
|
new_item.set_text(text)
|
||||||
|
|
||||||
|
if !allow_multi_select:
|
||||||
|
new_item.set_button_group(item_select_btn_group)
|
||||||
|
|
||||||
|
return new_item
|
31
ControlTree.tscn
Normal file
31
ControlTree.tscn
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
[gd_scene load_steps=3 format=2]
|
||||||
|
|
||||||
|
[ext_resource path="res://ControlTree.gd" type="Script" id=1]
|
||||||
|
[ext_resource path="res://ControlTreeItem.tscn" type="PackedScene" id=2]
|
||||||
|
|
||||||
|
[node name="ControlTree" type="Control"]
|
||||||
|
anchor_right = 0.492844
|
||||||
|
anchor_bottom = 1.0
|
||||||
|
margin_right = 0.327972
|
||||||
|
script = ExtResource( 1 )
|
||||||
|
__meta__ = {
|
||||||
|
"_edit_use_anchors_": true,
|
||||||
|
"_editor_description_": "An item tree with functionality similar to that of the built-in Tree control, but utilizing Control nodes instead of an internal state.
|
||||||
|
It is not recommended to create trees using scenes, the intended way is to create them through code."
|
||||||
|
}
|
||||||
|
item_scene = ExtResource( 2 )
|
||||||
|
|
||||||
|
[node name="ItemsList" type="PanelContainer" parent="."]
|
||||||
|
anchor_right = 1.0
|
||||||
|
anchor_bottom = 1.0
|
||||||
|
|
||||||
|
[node name="ItemsScroller" type="ScrollContainer" parent="ItemsList"]
|
||||||
|
margin_left = 7.0
|
||||||
|
margin_top = 7.0
|
||||||
|
margin_right = 498.0
|
||||||
|
margin_bottom = 593.0
|
||||||
|
|
||||||
|
[node name="Items" type="VBoxContainer" parent="ItemsList/ItemsScroller"]
|
||||||
|
unique_name_in_owner = true
|
||||||
|
margin_right = 491.0
|
||||||
|
size_flags_horizontal = 3
|
94
ControlTreeItem.gd
Normal file
94
ControlTreeItem.gd
Normal file
@ -0,0 +1,94 @@
|
|||||||
|
extends VBoxContainer
|
||||||
|
class_name ControlTreeItem
|
||||||
|
|
||||||
|
# the margin of the offset on the subitem (if this item is a subitem)
|
||||||
|
const SUBITEM_MARGIN_SIZE := 32
|
||||||
|
|
||||||
|
# if this property is true, the item can be interacted with
|
||||||
|
# e.g, it can be renamed, its checkmark can be ticked
|
||||||
|
var editable: bool = true
|
||||||
|
|
||||||
|
# proxy property for the CheckBox's `pressed` property
|
||||||
|
var checked: bool = false setget set_checked, is_checked
|
||||||
|
|
||||||
|
# if true, this item can be reordered in the tree
|
||||||
|
var draggable: bool = true
|
||||||
|
|
||||||
|
# an array of this item's subitems
|
||||||
|
var subitems: Array = []
|
||||||
|
|
||||||
|
# if true, this item's subitems will not be visible
|
||||||
|
var collapsed: bool = false
|
||||||
|
|
||||||
|
onready var subitem_margin_container: MarginContainer = $"%SubitemMargin"
|
||||||
|
onready var collapse_button: Button = $"%CollapseButton"
|
||||||
|
onready var drag_handle: Panel = $"%DragHandle"
|
||||||
|
onready var check_box: CheckBox = $"%CheckBox"
|
||||||
|
onready var item_text_button: Button = $"%ItemTextButton"
|
||||||
|
|
||||||
|
onready var subitem_container: VBoxContainer = $"%Subitems"
|
||||||
|
|
||||||
|
|
||||||
|
func _ready() -> void:
|
||||||
|
# warning-ignore:return_value_discarded
|
||||||
|
# warning-ignore:return_value_discarded
|
||||||
|
check_box.connect("pressed", self, "set_enabled", [true])
|
||||||
|
collapse_button.connect("pressed", self, "toggle_collapsed")
|
||||||
|
|
||||||
|
|
||||||
|
func set_checked(v: bool, from_checkbox: bool = false) -> void:
|
||||||
|
checked = v
|
||||||
|
if from_checkbox: return
|
||||||
|
check_box.pressed = v
|
||||||
|
|
||||||
|
|
||||||
|
func is_checked() -> bool:
|
||||||
|
return checked
|
||||||
|
|
||||||
|
|
||||||
|
func set_text(t: String) -> void:
|
||||||
|
item_text_button.text = t
|
||||||
|
|
||||||
|
|
||||||
|
func get_text() -> String:
|
||||||
|
return item_text_button.text
|
||||||
|
|
||||||
|
|
||||||
|
func add_subitem(item: ControlTreeItem) -> void:
|
||||||
|
subitem_container.add_child(item)
|
||||||
|
subitems.append(item)
|
||||||
|
item.subitem_margin_container.visible = true
|
||||||
|
print('d: ', get_depth(item))
|
||||||
|
item.subitem_margin_container.rect_min_size.x = SUBITEM_MARGIN_SIZE * get_depth(item)# - (clamp(collapse_button.rect_size.x * subitems.size(), 0, 1))
|
||||||
|
collapse_button.visible = true
|
||||||
|
|
||||||
|
|
||||||
|
func set_button_group(bg: ButtonGroup) -> void:
|
||||||
|
item_text_button.group = bg
|
||||||
|
|
||||||
|
|
||||||
|
func get_depth(item: ControlTreeItem) -> int:
|
||||||
|
var depth := 0
|
||||||
|
# this is the stupidest hack ever to get around cyclic deps
|
||||||
|
# basically, you can't check if an object is of the same class
|
||||||
|
# as self, ie `Object is ControlTreeItem` will error out
|
||||||
|
# so instead we're making a stupid, idiotic method
|
||||||
|
# that only this class has and checking for its presence
|
||||||
|
while item.get_parent().get_parent().has_method("i_am_item"):
|
||||||
|
depth += 1
|
||||||
|
item = item.get_parent().get_parent()
|
||||||
|
|
||||||
|
return depth
|
||||||
|
|
||||||
|
|
||||||
|
func i_am_item() -> void:
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
func toggle_collapsed() -> void:
|
||||||
|
collapsed = !collapsed
|
||||||
|
|
||||||
|
collapse_button.text = ">" if collapsed else "v"
|
||||||
|
|
||||||
|
for i in subitems:
|
||||||
|
i.visible = !collapsed
|
67
ControlTreeItem.tscn
Normal file
67
ControlTreeItem.tscn
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
[gd_scene load_steps=2 format=2]
|
||||||
|
|
||||||
|
[ext_resource path="res://ControlTreeItem.gd" type="Script" id=1]
|
||||||
|
|
||||||
|
[node name="ControlTreeItem" type="VBoxContainer"]
|
||||||
|
anchor_right = 0.479
|
||||||
|
anchor_bottom = 0.06
|
||||||
|
margin_right = 0.503967
|
||||||
|
script = ExtResource( 1 )
|
||||||
|
__meta__ = {
|
||||||
|
"_editor_description_": "An item singlet, i.e. the quintessential item container type for ControlTree. Has a \"main\" item and potentially a number of sub-items."
|
||||||
|
}
|
||||||
|
|
||||||
|
[node name="ItemAtom" type="HBoxContainer" parent="."]
|
||||||
|
margin_right = 490.0
|
||||||
|
margin_bottom = 32.0
|
||||||
|
rect_min_size = Vector2( 0, 32 )
|
||||||
|
size_flags_vertical = 5
|
||||||
|
__meta__ = {
|
||||||
|
"_editor_description_": "Atomic ControlTree item subtype, i.e. the smallest uncontained tree item that is only aware of itself and not any of its' sub-items."
|
||||||
|
}
|
||||||
|
|
||||||
|
[node name="SubitemMargin" type="MarginContainer" parent="ItemAtom"]
|
||||||
|
unique_name_in_owner = true
|
||||||
|
visible = false
|
||||||
|
margin_bottom = 32.0
|
||||||
|
|
||||||
|
[node name="CollapseButton" type="Button" parent="ItemAtom"]
|
||||||
|
unique_name_in_owner = true
|
||||||
|
visible = false
|
||||||
|
margin_right = 19.0
|
||||||
|
margin_bottom = 32.0
|
||||||
|
toggle_mode = true
|
||||||
|
text = "v"
|
||||||
|
flat = true
|
||||||
|
|
||||||
|
[node name="DragHandle" type="Panel" parent="ItemAtom"]
|
||||||
|
unique_name_in_owner = true
|
||||||
|
margin_right = 32.0
|
||||||
|
margin_bottom = 32.0
|
||||||
|
rect_min_size = Vector2( 32, 0 )
|
||||||
|
|
||||||
|
[node name="CheckBox" type="CheckBox" parent="ItemAtom"]
|
||||||
|
unique_name_in_owner = true
|
||||||
|
margin_left = 36.0
|
||||||
|
margin_right = 60.0
|
||||||
|
margin_bottom = 32.0
|
||||||
|
|
||||||
|
[node name="ItemTextButton" type="Button" parent="ItemAtom"]
|
||||||
|
unique_name_in_owner = true
|
||||||
|
margin_left = 64.0
|
||||||
|
margin_right = 490.0
|
||||||
|
margin_bottom = 32.0
|
||||||
|
size_flags_horizontal = 3
|
||||||
|
toggle_mode = true
|
||||||
|
text = "Item text"
|
||||||
|
flat = true
|
||||||
|
align = 0
|
||||||
|
|
||||||
|
[node name="Subitems" type="VBoxContainer" parent="."]
|
||||||
|
unique_name_in_owner = true
|
||||||
|
margin_top = 36.0
|
||||||
|
margin_right = 490.0
|
||||||
|
margin_bottom = 36.0
|
||||||
|
__meta__ = {
|
||||||
|
"_editor_description_": "A container for a ControlTreeItem's sub-items, which are themselves ControlTreeItems."
|
||||||
|
}
|
57
TestArea.tscn
Normal file
57
TestArea.tscn
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
[gd_scene load_steps=3 format=2]
|
||||||
|
|
||||||
|
[ext_resource path="res://ControlTree.tscn" type="PackedScene" id=1]
|
||||||
|
|
||||||
|
[sub_resource type="GDScript" id=1]
|
||||||
|
script/source = "extends Control
|
||||||
|
|
||||||
|
var i
|
||||||
|
var j
|
||||||
|
|
||||||
|
func _ready() -> void:
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
func _on_Button_pressed() -> void:
|
||||||
|
i = $ControlTree.add_item('test')
|
||||||
|
|
||||||
|
|
||||||
|
func _on_Button2_pressed() -> void:
|
||||||
|
j = $ControlTree.add_item('test2', i)
|
||||||
|
|
||||||
|
|
||||||
|
func _on_Button3_pressed() -> void:
|
||||||
|
$ControlTree.add_item('test3', j)
|
||||||
|
"
|
||||||
|
|
||||||
|
[node name="TestArea" type="Control"]
|
||||||
|
anchor_right = 1.0
|
||||||
|
anchor_bottom = 1.0
|
||||||
|
script = SubResource( 1 )
|
||||||
|
|
||||||
|
[node name="ControlTree" parent="." instance=ExtResource( 1 )]
|
||||||
|
|
||||||
|
[node name="Button" type="Button" parent="."]
|
||||||
|
margin_left = 634.0
|
||||||
|
margin_top = 48.0
|
||||||
|
margin_right = 765.0
|
||||||
|
margin_bottom = 97.0
|
||||||
|
text = "Add item"
|
||||||
|
|
||||||
|
[node name="Button2" type="Button" parent="."]
|
||||||
|
margin_left = 634.0
|
||||||
|
margin_top = 117.0
|
||||||
|
margin_right = 765.0
|
||||||
|
margin_bottom = 166.0
|
||||||
|
text = "Add subitem"
|
||||||
|
|
||||||
|
[node name="Button3" type="Button" parent="."]
|
||||||
|
margin_left = 634.0
|
||||||
|
margin_top = 194.0
|
||||||
|
margin_right = 765.0
|
||||||
|
margin_bottom = 243.0
|
||||||
|
text = "Add subsubitem"
|
||||||
|
|
||||||
|
[connection signal="pressed" from="Button" to="." method="_on_Button_pressed"]
|
||||||
|
[connection signal="pressed" from="Button2" to="." method="_on_Button2_pressed"]
|
||||||
|
[connection signal="pressed" from="Button3" to="." method="_on_Button3_pressed"]
|
7
default_env.tres
Normal file
7
default_env.tres
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
[gd_resource type="Environment" load_steps=2 format=2]
|
||||||
|
|
||||||
|
[sub_resource type="ProceduralSky" id=1]
|
||||||
|
|
||||||
|
[resource]
|
||||||
|
background_mode = 2
|
||||||
|
background_sky = SubResource( 1 )
|
35
icon.png.import
Normal file
35
icon.png.import
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
[remap]
|
||||||
|
|
||||||
|
importer="texture"
|
||||||
|
type="StreamTexture"
|
||||||
|
path="res://.import/icon.png-487276ed1e3a0c39cad0279d744ee560.stex"
|
||||||
|
metadata={
|
||||||
|
"vram_texture": false
|
||||||
|
}
|
||||||
|
|
||||||
|
[deps]
|
||||||
|
|
||||||
|
source_file="res://icon.png"
|
||||||
|
dest_files=[ "res://.import/icon.png-487276ed1e3a0c39cad0279d744ee560.stex" ]
|
||||||
|
|
||||||
|
[params]
|
||||||
|
|
||||||
|
compress/mode=0
|
||||||
|
compress/lossy_quality=0.7
|
||||||
|
compress/hdr_mode=0
|
||||||
|
compress/bptc_ldr=0
|
||||||
|
compress/normal_map=0
|
||||||
|
flags/repeat=0
|
||||||
|
flags/filter=true
|
||||||
|
flags/mipmaps=false
|
||||||
|
flags/anisotropic=false
|
||||||
|
flags/srgb=2
|
||||||
|
process/fix_alpha_border=true
|
||||||
|
process/premult_alpha=false
|
||||||
|
process/HDR_as_SRGB=false
|
||||||
|
process/invert_color=false
|
||||||
|
process/normal_map_invert_y=false
|
||||||
|
stream=false
|
||||||
|
size_limit=0
|
||||||
|
detect_3d=true
|
||||||
|
svg/scale=1.0
|
42
project.godot
Normal file
42
project.godot
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
; Engine configuration file.
|
||||||
|
; It's best edited using the editor UI and not directly,
|
||||||
|
; since the parameters that go here are not all obvious.
|
||||||
|
;
|
||||||
|
; Format:
|
||||||
|
; [section] ; section goes between []
|
||||||
|
; param=value ; assign values to parameters
|
||||||
|
|
||||||
|
config_version=4
|
||||||
|
|
||||||
|
_global_script_classes=[ {
|
||||||
|
"base": "Control",
|
||||||
|
"class": "ControlTree",
|
||||||
|
"language": "GDScript",
|
||||||
|
"path": "res://ControlTree.gd"
|
||||||
|
}, {
|
||||||
|
"base": "VBoxContainer",
|
||||||
|
"class": "ControlTreeItem",
|
||||||
|
"language": "GDScript",
|
||||||
|
"path": "res://ControlTreeItem.gd"
|
||||||
|
} ]
|
||||||
|
_global_script_class_icons={
|
||||||
|
"ControlTree": "",
|
||||||
|
"ControlTreeItem": ""
|
||||||
|
}
|
||||||
|
|
||||||
|
[application]
|
||||||
|
|
||||||
|
config/name="customtree"
|
||||||
|
config/icon="res://icon.png"
|
||||||
|
|
||||||
|
[gui]
|
||||||
|
|
||||||
|
common/drop_mouse_on_gui_input_disabled=true
|
||||||
|
|
||||||
|
[physics]
|
||||||
|
|
||||||
|
common/enable_pause_aware_picking=true
|
||||||
|
|
||||||
|
[rendering]
|
||||||
|
|
||||||
|
environment/default_environment="res://default_env.tres"
|
Loading…
Reference in New Issue
Block a user