GPU-accelerated UI toolkit (Vulkan)
git clone https://git.lucas.co/cce-ui.git
fix: TreeList unlinks its rename editor, which was eating row clicks forever after
`mouse_body` registers AND `link_ids`-attaches `edit_box` when a double-click starts
a rename, but nothing ever undid it. Both the paint and the `set_rect` are gated on
`editing_key_idx.is_some()`, so once editing ended the box kept its last rect, stayed
`visible()` with the default `gates_presses`, and remained a tree child the router
descends into — an invisible 170x24 dead zone parked at the last-edited row's screen
coordinates, swallowing the press before `TreeList::mouse_body` ever ran. Each rename
also minted a fresh TextBox id into the same field, so the child list grew forever.
The other three field widgets (`search_box`, `add_key_btn`, `add_key_popover_box`)
follow the rule this file documents at its `register_embedded_children` — registered
but deliberately NOT tree-linked, because the router's children-first descent both
double-delivers and starves the tree-level logic. The rename editor was the one that
broke it; teardown now matches setup rather than dropping the link, so in-box typing
keeps routing exactly as before.
Live-reproduced in cce-data-editor (its only consumer, and it routes presses through
`propagate_event(tree_list.id())`): double-click a row to rename, Escape, click a
different row, then click the renamed row — before, the selection would not move; the
click vanished. After, the row selects and its value editor opens. Renaming itself
still commits (verified "bell" -> "zz" with the value preserved).
Co-Authored-By: Claude Opus 5 <[email protected]>
src/widget/container/treelist.rs | 12 ++++++++++++
1 file changed, 12 insertions(+)
diff --git a/src/widget/container/treelist.rs b/src/widget/container/treelist.rs
index 3462103..bc6022e 100644
--- a/src/widget/container/treelist.rs
+++ b/src/widget/container/treelist.rs
@@ -1106,6 +1106,7 @@ impl Input for TreeList {
/// adapter on commit), and runs the scrollbar activity fade.
fn tick_ctx(&mut self, dt: f32, ectx: &mut EventCtx) -> bool {
let host = ectx.host_ptr();
+ let host_id = ectx.id;
let Some(ui) = ectx.ui.as_deref_mut() else {
return false;
};
@@ -1167,6 +1168,17 @@ impl Input for TreeList {
}
}
self.editing_key_idx = None;
+ // Undo the register+link done when editing began (see `mouse_body`). The paint
+ // (`if self.editing_key_idx.is_some()`) and the `set_rect` beside it are both
+ // gated on editing, but the tree link was not — so leaving it attached parked a
+ // 170x24 child at the last-edited row's screen coordinates that kept its stale
+ // rect, kept hit-testing (visible, gates_presses default true) and swallowed the
+ // press before `mouse_body` ever ran: an invisible dead zone that ate row clicks
+ // and silently re-entered editing on an unpainted box. Each rename also minted a
+ // fresh TextBox id into the same field, so the child list grew monotonically.
+ let eb_id = self.edit_box.base().id();
+ ui.unlink_child(host_id, eb_id);
+ ui.unregister_widget(eb_id);
if let Some(h) = host { ui.set_focused_ptr(h); }
changed = true;
}