fix(ui): maintain the parent link in every collection mutator
The parent link (#122/#183) is meant to be the inverse of collection
membership, but only append() maintained it.
insert(), extend() and setitem() called setParent(owner.lock())
unconditionally. A scene collection has no owner drawable, so that
resolved to null -- and setParent(nullptr) also clears parent_scene. The
drawable landed in the scene's UI vector, rendered fine, and reported a
.parent of None.
The slice arms never touched the link at all. A slice-delete left the
removed child pointing at a parent that no longer contained it; a
slice-assign never parented the incoming items, nor unparented the ones
they displaced. A stale parent is a live weak_ptr to a frame the child
has left, and it is what get_global_position() walks.
Route every mutator through link_child()/unlink_child(), which are now
the single place that knows a scene parents via setParentScene() and a
drawable via setParent().
Three latent traps in the same functions, found while fixing this:
* collection[-1] on an EMPTY collection hung the engine forever:
`while (index < 0) index += size()` adds zero on every pass.
* getitem's `index > size() - 1` check underflowed to SIZE_MAX when
size() was 0, so the bounds check passed and it indexed an empty
vector.
* insert() and setitem() resolved the index before detaching the
incoming drawable from its old parent. If it was already a member of
the same collection, detaching erased it and shifted everything
after -- so an index validated against the old size could write past
the end. Slice-assign now builds its result as an independent vector
for the same reason.
closes #377
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-14 07:53:21 -04:00
|
|
|
{"commit":"57db8cb","dirty":true,"functions":{"bresenham":{"doc_sha":"ee2d0f7a54a664f5","kind":"function","lifecycle":{"since":"0.2.8"},"signature":"bresenham(start, end, include_start=True, include_end=True) -> list[tuple[int, int]]"},"end_benchmark":{"doc_sha":"5d783c5dabb7a4e9","kind":"function","lifecycle":{"since":"0.2.8"},"signature":"end_benchmark() -> str"},"exit":{"doc_sha":"7572d4d6b1a1c8a4","kind":"function","lifecycle":{"since":"0.2.8"},"signature":"exit() -> None"},"find":{"doc_sha":"364b95807edcf8b4","kind":"function","lifecycle":{"since":"0.2.8"},"signature":"find(name: str, scene: str = None) -> UIDrawable | None"},"find_all":{"doc_sha":"b4a278f16b172131","kind":"function","lifecycle":{"since":"0.2.8"},"signature":"find_all(pattern: str, scene: str = None) -> list"},"get_metrics":{"doc_sha":"a0bbee3858baa4a9","kind":"function","lifecycle":{"modified":{"commit":"464af6a","version":"0.2.8-dev"},"since":"0.2.8"},"signature":"get_metrics() -> dict"},"lock":{"doc_sha":"e42989cabc81d080","kind":"function","lifecycle":{"since":"0.2.8"},"signature":"lock() -> _LockContext"},"log_benchmark":{"doc_sha":"4564bf7321366a0a","kind":"function","lifecycle":{"since":"0.2.8"},"signature":"log_benchmark(message: str) -> None"},"set_dev_console":{"doc_sha":"940ed19ff4f5243f","kind":"function","lifecycle":{"since":"0.2.8"},"signature":"set_dev_console(enabled: bool) -> None"},"set_scale":{"doc_sha":"b565b441a326af48","kind":"function","lifecycle":{"since":"0.2.8"},"signature":"set_scale(multiplier: float) -> None"},"start_benchmark":{"doc_sha":"783957f3517518fe","kind":"function","lifecycle":{"since":"0.2.8"},"signature":"start_benchmark() -> None"},"step":{"doc_sha":"90dec8ed10ee644f","kind":"function","lifecycle":{"since":"0.2.8"},"signature":"step(dt: float = None) -> float"}},"module_attributes":{"animations":{"doc_sha":"30d25725feac9eb6","kind":"attribute","lifecycle":{"since":"0.2.8-dev"},"readonly":true},"current_scene":{"doc_sha":"ab496ea99fec2fa8","kind":"attribute","lifecycle":{"since":"0.2.8-dev"},"readonly":false},"default_transition":{"doc_sha":"73fb568e9cb25540","kind":"attribute","lifecycle":{"since":"0.2.8-dev"},"readonly":false},"default_transition_duration":{"doc_sha":"ae57530eded49138","kind":"attribute","lifecycle":{"since":"0.2.8-dev"},"readonly":false},"save_dir":{"doc_sha":"96ffa5a27d178b14","kind":"attribute","lifecycle":{"since":"0.2.8-dev"},"readonly":true},"scenes":{"doc_sha":"8021c54383d3cb8e","kind":"attribute","lifecycle":{"since":"0.2.8-dev"},"readonly":true},"timers":{"doc_sha":"48e2aa7747d8f527","kind":"attribute","lifecycle":{"since":"0.2.8-dev"},"readonly":true}},"objects":{"AStarPath":{"doc_sha":"60dd12bb4a54f3dd","kind":"class","lifecycle":{"since":"0.2.8"},"members":{"destination":{"doc_sha":"62a81c7267ad9ed9","kind":"property","lifecycle":{"since":"0.2.8"},"signature":""},"origin":{"doc_sha":"c7dd130b8d4ef800","kind":"property","lifecycle":{"since":"0.2.8"},"signature":""},"peek":{"doc_sha":"14054f10b4d9dda0","kind":"method","lifecycle":{"since":"0.2.8"},"signature":"peek() -> Vector"},"remaining":{"doc_sha":"c193adc4bbfa3564","kind":"property","lifecycle":{"since":"0.2.8"},"signature":""},"walk":{"doc_sha":"3fb64b239109d301","kind":"method","lifecycle":{"since":"0.2.8"},"signature":"walk() -> Vector"}}},"Alignment":{"doc_sha":"77d93d03c8994f84","kind":"class","lifecycle":{"since":"0.2.8"},"members":{"as_integer_ratio":{"doc_sha":"3eb115fab0d0e0ec","kind":"method","lifecycle":{"since":"0.2.8"},"signature":"($self, /)"},"bit_count":{"doc_sha":"f276da700b5a2e37","kind":"method","lifecycle":{"since":"0.2.8"},"signature":"($self, /)"},"bit_length":{"doc_sha":"15b29db62fd0fa6c","kind":"method","lifecycle":{"since":"0.2.8"},"signature":"($self, /)"},"conjugate":{"doc_sha":"6517a002faad7c75","kind":"method","lifecycle":{"since":"0.2.8"},"signature":"($self, /)"},"denominator":{"doc_sha":"5051eb1570768851","kind":"property","lifecycle":{"since":"0.2.8"},"signature":""},"from_bytes":{"doc_sha":"64672607865643a7","kind":"classmethod","lifecycle":{"since":"0.2.8"},"signature":"($type, /, bytes, by
|