Rework and simplify the focus handling

Instead of determining the focus item through item tree traversal and
pointer comparison and storing the intermediate indices in the
components in the tree, remember the focus item by a pair of
VWeak<ComponentVTable, Dyn> and item_index: usize.

This speeds up determining the focus item as well as delivering events,
which can now be done directly after retrieving an ItemRef with
get_item_ref.

This also fixes the duplicate line edit focus in the 7gui cells
test case.
This commit is contained in:
Simon Hausmann 2020-11-19 21:07:54 +01:00
parent 2cc1070b7b
commit 89e0b57627
20 changed files with 189 additions and 560 deletions

View file

@ -98,9 +98,10 @@ public:
cbindgen_private::sixtyfps_component_window_free_graphics_resources(&inner, &items);
}
void set_focus_item(vtable::VRef<ComponentVTable> c, vtable::VRef<ItemVTable> item)
void set_focus_item(const ComponentRc &component_rc, uintptr_t item_index)
{
cbindgen_private::sixtyfps_component_window_set_focus_item(&inner, c, item);
cbindgen_private::sixtyfps_component_window_set_focus_item(&inner, &component_rc,
item_index);
}
template<typename Component, typename ItemTree>
@ -167,7 +168,6 @@ inline ItemRef get_item_ref(ComponentRef component, Slice<ItemTreeNode> item_tre
}
using cbindgen_private::FocusEvent;
using cbindgen_private::FocusEventResult;
using cbindgen_private::InputEventResult;
using cbindgen_private::KeyEvent;
using cbindgen_private::KeyEventResult;
@ -177,8 +177,7 @@ namespace private_api {
template<typename GetDynamic>
inline InputEventResult process_input_event(const ComponentRc &component_rc, int64_t &mouse_grabber,
MouseEvent mouse_event, Slice<ItemTreeNode> tree,
GetDynamic get_dynamic, const ComponentWindow *window,
const ComponentRef *app_component)
GetDynamic get_dynamic, const ComponentWindow *window)
{
if (mouse_grabber != -1) {
auto item_index = mouse_grabber & 0xffffffff;
@ -196,11 +195,11 @@ inline InputEventResult process_input_event(const ComponentRc &component_rc, int
reinterpret_cast<char *>(component_rc.borrow().instance)
+ item_node.item.item.offset,
},
mouse_event, window, *app_component);
mouse_event, window, &component_rc, item_index);
break;
case ItemTreeNode::Tag::DynamicTree: {
ComponentRef comp = get_dynamic(item_node.dynamic_tree.index, rep_index);
result = comp.vtable->input_event(comp, mouse_event, window, app_component);
result = comp.vtable->input_event(comp, mouse_event, window);
} break;
}
if (result != InputEventResult::GrabMouse) {
@ -208,80 +207,10 @@ inline InputEventResult process_input_event(const ComponentRc &component_rc, int
}
return result;
} else {
return cbindgen_private::sixtyfps_process_ungrabbed_mouse_event(
&component_rc, mouse_event, window, *app_component, &mouse_grabber);
return cbindgen_private::sixtyfps_process_ungrabbed_mouse_event(&component_rc, mouse_event,
window, &mouse_grabber);
}
}
template<typename GetDynamic>
inline KeyEventResult process_key_event(ComponentRef component, int64_t focus_item,
const KeyEvent *event, Slice<ItemTreeNode> tree,
GetDynamic get_dynamic, const ComponentWindow *window)
{
if (focus_item != -1) {
auto item_index = focus_item & 0xffffffff;
auto rep_index = focus_item >> 32;
const auto &item_node = tree.ptr[item_index];
switch (item_node.tag) {
case ItemTreeNode::Tag::Item:
return item_node.item.item.vtable->key_event(
{
item_node.item.item.vtable,
reinterpret_cast<char *>(component.instance)
+ item_node.item.item.offset,
},
event, window);
case ItemTreeNode::Tag::DynamicTree: {
ComponentRef comp = get_dynamic(item_node.dynamic_tree.index, rep_index);
return comp.vtable->key_event(comp, event, window);
};
}
}
return KeyEventResult::EventIgnored;
}
template<typename GetDynamic>
inline FocusEventResult process_focus_event(const ComponentRc &component_rc, int64_t &focus_item,
const FocusEvent *event, Slice<ItemTreeNode> tree,
GetDynamic get_dynamic, const ComponentWindow *window)
{
switch (event->tag) {
case FocusEvent::Tag::FocusIn:
return cbindgen_private::sixtyfps_locate_and_activate_focus_item(&component_rc, event,
window, &focus_item);
case FocusEvent::Tag::FocusOut:
[[fallthrough]];
case FocusEvent::Tag::WindowReceivedFocus:
[[fallthrough]];
case FocusEvent::Tag::WindowLostFocus:
if (focus_item != -1) {
auto item_index = focus_item & 0xffffffff;
auto rep_index = focus_item >> 32;
const auto &item_node = tree.ptr[item_index];
switch (item_node.tag) {
case ItemTreeNode::Tag::Item:
item_node.item.item.vtable->focus_event(
{
item_node.item.item.vtable,
reinterpret_cast<char *>(component_rc.borrow().instance)
+ item_node.item.item.offset,
},
event, window);
break;
case ItemTreeNode::Tag::DynamicTree: {
ComponentRef comp = get_dynamic(item_node.dynamic_tree.index, rep_index);
comp.vtable->focus_event(comp, event, window);
} break;
}
if (event->tag == FocusEvent::Tag::FocusOut) {
focus_item = -1;
}
return FocusEventResult::FocusItemFound;
} else {
return FocusEventResult::FocusItemNotFound;
}
}
return FocusEventResult::FocusItemNotFound;
}
void dealloc(const ComponentVTable *, uint8_t *ptr, vtable::Layout layout)
{