Skip to content

Commit 31313cc

Browse files
committed
Add readme
1 parent 0c20c03 commit 31313cc

2 files changed

Lines changed: 122 additions & 0 deletions

File tree

README.md

Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
# Control List for Godot
2+
3+
A small Godot addon that renders a dynamic list of items as UI Controls.
4+
5+
- Drop a ControlList node under any Control container.
6+
- Give it an array of items.
7+
- It will insert, delete, and move child Controls to match your data efficiently
8+
using [the Myers diffing algorithm](https://www.nathaniel.ai/myers-diff/).
9+
- Existing Controls are reused when possible, so your per-item state stays intact.
10+
11+
Useful for inventories, chat/message feeds, settings lists, leaderboards, etc.
12+
13+
This is similar to Qt's ListView and Android's RecyclerView+DiffUtil.
14+
15+
## Features
16+
17+
- Reuses existing nodes when items are the “same” (you decide what “same” means)
18+
- Can be placed in any container that handles multiple items (HFlowContainer, VBoxContainer…)
19+
- Can exist alongside other Controls in the same container, such as headers and footers
20+
- Simple factory API - return any Control you like (Label, HBoxContainer, custom scene…)
21+
- Deferred updates by default to prevent redundant updates, with an option to update immediately
22+
23+
## Install
24+
25+
There are two options:
26+
27+
1. From the Asset Library
28+
29+
2. From a release
30+
- Download the control-list.zip from the GitHub Releases of this repo.
31+
- Unzip into your project so it lands at: addons/control-list
32+
33+
## Quick start
34+
35+
1. Add a ControlList node as a child under any Control container that should hold your items (e.g. a VBoxContainer).
36+
2. Provide a factory function to build a Control for each item: `set_control_factory`
37+
3. (Recommended) Provide a key function that returns a stable identity for each item: `set_item_key`
38+
4. Call `update_list(new_items)` whenever your data changes.
39+
40+
Example:
41+
42+
<img src="./misc/screenshot_simplescenetree.png">
43+
44+
```gdscript
45+
@onready var cl: ControlList = $VBoxContainer/ControlList
46+
47+
func _ready():
48+
# Create a simple Label for each item
49+
cl.set_control_factory(
50+
func(item):
51+
var label := Label.new()
52+
label.text = item.name
53+
return label
54+
)
55+
56+
# Use a stable key so items are reused/moved
57+
cl.set_item_key(func(item): return item.id)
58+
59+
# Render items
60+
cl.update_list([
61+
{ "id": "item_sword", "name": "Sword" },
62+
{ "id": "item_shield", "name": "Shield" },
63+
{ "id": "item_helmet", "name": "Helmet" },
64+
])
65+
66+
67+
# Later… update with new content
68+
cl.update_list([
69+
{ "id": "item_shield", "name": "Shield" }, # moved
70+
{ "id": "item_bow", "name": "Bow" }, # inserted
71+
{ "id": "item_helmet", "name": "Helmet" }, # moved
72+
])
73+
```
74+
75+
## Sample project
76+
77+
See the sample/ directory for a small example of a shop UI.
78+
ControlList is set up in [sample_shop.gd](./sample/sample_shop.gd).
79+
80+
## How it works
81+
82+
ControlList looks at the previous item array vs the new one.
83+
It runs a Myers diff and computes insert/delete/move operations.
84+
It applies those operations to child Controls under the ControlList’s parent.
85+
If keys match, nodes are reused and only moved. If a key disappears, the node is freed.
86+
87+
## Important notes
88+
89+
- Parent must be a Control. Add ControlList as a child under the container that should hold your list items.
90+
- Items are added as siblings next to the ControlList (children of its parent),
91+
ordered immediately after the ControlList.
92+
- Your factory should create fresh Controls for inserts. Visual updates for existing items are up to you.
93+
94+
## Testing
95+
96+
This repo includes GdUnit4 tests.
97+
98+
- You’ll need Godot 4.4 installed. Tests currently fail on 4.5,
99+
but it seems to be an issue with the test runner, not this library.
100+
- Set the environment variable GODOT_BINARY to your Godot executable.
101+
- Run: `./run_all_tests.sh`
102+
103+
Example on macOS:
104+
105+
```bash
106+
export GODOT_BINARY=/Applications/Godot.app/Contents/MacOS/Godot
107+
./run_all_tests.sh
108+
```
109+
110+
## Compatibility
111+
112+
- Tested on Godot 4.5 and 4.4.
113+
114+
## Future plans
115+
116+
- Maybe: Content change notifications
117+
- Given a function that determines whether two items have equal data,
118+
notify that that item should be updated.
119+
I'm used to this pattern from mobile UI development, but not sure
120+
if it makes as much sense in Godot.
121+
- Maybe: Make position known to items
122+
- Maybe: Background thread diffing
11 KB
Loading

0 commit comments

Comments
 (0)