UiService v2.1: Virtualized lists (#2342)

* UiService: Add `pane_add_list`

* Fix CSS scoping
This commit is contained in:
Luke Street
2026-08-23 14:33:36 -06:00
committed by GitHub
parent d281c34a65
commit 1db2a74192
17 changed files with 802 additions and 57 deletions
+43
View File
@@ -496,6 +496,49 @@ controls are only available inside window tabs.
and calls the group's build callback with that pane, which is useful for organizing related controls without adding
more tabs.
**Lists:** `pane_add_list` adds a scrollable virtualized list of items that can be efficiently updated and filtered.
Keys must be unique and remain stable across replacements.
```cpp
UiListHandle locationList = 0;
void replace_locations(std::string_view query) {
std::vector<UiListItem> items;
for (uint64_t i = 0; i < locations.size(); ++i) {
if (matches(locations[i], query)) {
UiListItem item = UI_LIST_ITEM_INIT;
item.key = i;
item.label = locations[i].c_str();
items.push_back(item);
}
}
svc_ui->list_set_items(mod_ctx, locationList, items.data(), items.size());
}
void set_filter(ModContext*, void*, const UiControlValue* value) {
replace_locations(value->string_value);
}
bool location_selected(ModContext*, UiListHandle, uint64_t key, void*) {
return selected_locations.contains(key);
}
UiControlDesc filter = UI_CONTROL_DESC_INIT;
filter.kind = UI_CONTROL_STRING;
filter.label = "Filter";
filter.get = get_filter;
filter.set = set_filter;
filter.string_set_mode = UI_STRING_SET_ON_CHANGE; /* invoke `set` while typing */
svc_ui->pane_add_control(mod_ctx, pane, &filter, nullptr);
UiListDesc list = UI_LIST_DESC_INIT;
/* items may be passed as a part of list creation, or set afterwards */
list.on_pressed = location_pressed;
list.is_selected = location_selected;
svc_ui->pane_add_list(mod_ctx, pane, &list, &locationList);
replace_locations(""); /* calls `list_set_items` */
```
**Windows:** `window_push` pushes a tabbed two-pane window onto the document stack and shows it. Each tab's `build`
receives the window handle plus fresh left and right pane handles on every activation. The optional per-tab `update`
runs each frame while that tab is active. `on_closed` fires when the window is destroyed. `desc.rcss` optionally styles