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)
{

View file

@ -180,10 +180,9 @@ pub mod re_exports {
PathArcTo, PathData, PathElement, PathEvent, PathLineTo, Point, Rect, Size,
};
pub use sixtyfps_corelib::input::{
locate_and_activate_focus_item, process_ungrabbed_mouse_event, FocusEvent,
FocusEventResult, InputEventResult, KeyCode, KeyEvent, KeyEventResult, KeyboardModifiers,
MouseEvent, ALT_MODIFIER, CONTROL_MODIFIER, COPY_PASTE_MODIFIER, LOGO_MODIFIER,
NO_MODIFIER, SHIFT_MODIFIER,
process_ungrabbed_mouse_event, FocusEvent, InputEventResult, KeyCode, KeyEvent,
KeyEventResult, KeyboardModifiers, MouseEvent, ALT_MODIFIER, CONTROL_MODIFIER,
COPY_PASTE_MODIFIER, LOGO_MODIFIER, NO_MODIFIER, SHIFT_MODIFIER,
};
pub use sixtyfps_corelib::item_tree::{
item_offset, visit_item_tree, ItemTreeNode, ItemVisitorRefMut, ItemVisitorVTable,

View file

@ -1104,7 +1104,7 @@ fn generate_component(
Declaration::Function(Function {
name: "input_event".into(),
signature:
"(sixtyfps::private_api::ComponentRef component, sixtyfps::MouseEvent mouse_event, const sixtyfps::private_api::ComponentWindow *window, const sixtyfps::private_api::ComponentRef *app_component) -> sixtyfps::InputEventResult"
"(sixtyfps::private_api::ComponentRef component, sixtyfps::MouseEvent mouse_event, const sixtyfps::private_api::ComponentWindow *window) -> sixtyfps::InputEventResult"
.into(),
is_static: true,
statements: Some(vec![
@ -1113,53 +1113,6 @@ fn generate_component(
"return sixtyfps::private_api::process_input_event(self_rc, self->mouse_grabber, mouse_event, item_tree(), [self](int dyn_index, [[maybe_unused]] int rep_index) {".into(),
" (void)self;".into(),
format!(" switch(dyn_index) {{ {} }};", repeated_input_branch.join("")),
" return sixtyfps::private_api::ComponentRef{nullptr, nullptr};\n}, window, app_component);".into(),
]),
..Default::default()
}),
));
component_struct.members.push((
Access::Private,
Declaration::Function(Function {
name: "key_event".into(),
signature:
"(sixtyfps::private_api::ComponentRef component, const sixtyfps::KeyEvent *key_event, const sixtyfps::private_api::ComponentWindow *window) -> sixtyfps::KeyEventResult"
.into(),
is_static: true,
statements: Some(vec![
format!(" auto self = reinterpret_cast<{}*>(component.instance);", component_id),
"return sixtyfps::private_api::process_key_event(component, self->focus_item, key_event, item_tree(), [self](int dyn_index, [[maybe_unused]] int rep_index) {".into(),
" (void)self;".into(),
format!(" switch(dyn_index) {{ {} }};", repeated_input_branch.join("")),
" return sixtyfps::private_api::ComponentRef{nullptr, nullptr};\n}, window);".into(),
]),
..Default::default()
}),
));
component_struct.members.push((
Access::Private,
Declaration::Var(Var {
ty: "int64_t".into(),
name: "focus_item".into(),
init: Some("-1".into()),
}),
));
component_struct.members.push((
Access::Private,
Declaration::Function(Function {
name: "focus_event".into(),
signature:
"(sixtyfps::private_api::ComponentRef component, const sixtyfps::FocusEvent *focus_event, const sixtyfps::private_api::ComponentWindow *window) -> sixtyfps::FocusEventResult"
.into(),
is_static: true,
statements: Some(vec![
format!("auto self = reinterpret_cast<{}*>(component.instance);", component_id),
"auto self_rc = self->self_weak.lock()->into_dyn();".into(),
"return sixtyfps::private_api::process_focus_event(self_rc, self->focus_item, focus_event, item_tree(), [self](int dyn_index, [[maybe_unused]] int rep_index) {".into(),
" (void)self;".into(),
format!(" switch(dyn_index) {{ {} }};", repeated_input_branch.join("")),
" return sixtyfps::private_api::ComponentRef{nullptr, nullptr};\n}, window);".into(),
]),
..Default::default()
@ -1243,7 +1196,7 @@ fn generate_component(
ty: "const sixtyfps::private_api::ComponentVTable".to_owned(),
name: format!("{}::component_type", component_id),
init: Some(format!(
"{{ visit_children, get_item_ref, layouting_info, apply_layout, input_event, key_event, focus_event, sixtyfps::private_api::drop_in_place<{}>, sixtyfps::private_api::dealloc }}",
"{{ visit_children, get_item_ref, layouting_info, apply_layout, input_event, sixtyfps::private_api::drop_in_place<{}>, sixtyfps::private_api::dealloc }}",
component_id)
),
}));
@ -1476,14 +1429,7 @@ fn compile_expression(e: &crate::expression_tree::Expression, component: &Rc<Com
if let Expression::ElementReference(focus_item) = &arguments[0] {
let focus_item = focus_item.upgrade().unwrap();
let focus_item = focus_item.borrow();
let component =
format!("{{&{}::component_type, self}}", component_id(component));
let item = format!(
"{{&sixtyfps::private_api::{vt}, &self->{item}}}",
vt = focus_item.base_type.as_native().vtable_symbol,
item = focus_item.id
);
format!("self->window.set_focus_item({}, {});", component, item)
format!("self->window.set_focus_item(self->self_weak.lock()->into_dyn(), {});", focus_item.item_index.get().unwrap())
} else {
panic!("internal error: argument to SetFocusItem must be an element")
}

View file

@ -358,8 +358,6 @@ fn generate_component(
let mut repeated_element_components = Vec::new();
let mut repeated_visit_branch = Vec::new();
let mut repeated_input_branch = Vec::new();
let mut repeated_key_event_branch = Vec::new();
let mut repeated_focus_branch = Vec::new();
let mut init = Vec::new();
let mut window_field_init = None;
let mut window_parent_param = None;
@ -524,13 +522,7 @@ fn generate_component(
}
repeated_input_branch.push(quote!(
#repeater_index => self.#repeater_id.input_event(rep_index, event, window, app_component),
));
repeated_key_event_branch.push(quote!(
#repeater_index => self.#repeater_id.key_event(rep_index, event, window),
));
repeated_focus_branch.push(quote!(
#repeater_index => self.#repeater_id.focus_event(rep_index, event, window),
#repeater_index => self.#repeater_id.input_event(rep_index, event, window),
));
item_tree_array.push(quote!(
@ -694,10 +686,10 @@ fn generate_component(
}
}
fn input_event(self: ::core::pin::Pin<&Self>, mouse_event : sixtyfps::re_exports::MouseEvent, window: &sixtyfps::re_exports::ComponentWindow,
app_component: &::core::pin::Pin<sixtyfps::re_exports::VRef<sixtyfps::re_exports::ComponentVTable>>) -> sixtyfps::re_exports::InputEventResult {
fn input_event(self: ::core::pin::Pin<&Self>, mouse_event : sixtyfps::re_exports::MouseEvent, window: &sixtyfps::re_exports::ComponentWindow) -> sixtyfps::re_exports::InputEventResult {
use sixtyfps::re_exports::*;
let mouse_grabber = self.mouse_grabber.get();
let self_rc = VRc::into_dyn(self.as_ref().self_weak.get().unwrap().upgrade().unwrap());
#[allow(unused)]
let (status, new_grab) = if let Some((item_index, rep_index)) = mouse_grabber.aborted_indexes() {
let tree = Self::item_tree();
@ -706,7 +698,7 @@ fn generate_component(
event.pos -= offset.to_vector();
let res = match tree[item_index] {
ItemTreeNode::Item { item, .. } => {
item.apply_pin(self).as_ref().input_event(event, window, app_component.clone())
item.apply_pin(self).as_ref().input_event(event, window, &self_rc, item_index)
}
ItemTreeNode::DynamicTree { index } => {
match index {
@ -720,72 +712,12 @@ fn generate_component(
_ => (res, VisitChildrenResult::CONTINUE),
}
} else {
process_ungrabbed_mouse_event(&VRc::into_dyn(self.as_ref().self_weak.get().unwrap().upgrade().unwrap()), mouse_event, window, app_component.clone())
process_ungrabbed_mouse_event(&self_rc, mouse_event, window)
};
self.mouse_grabber.set(new_grab);
status
}
fn key_event(self: ::core::pin::Pin<&Self>, event : &sixtyfps::re_exports::KeyEvent, window: &sixtyfps::re_exports::ComponentWindow)
-> sixtyfps::re_exports::KeyEventResult {
use sixtyfps::re_exports::*;
#[allow(unused)]
if let Some((item_index, rep_index)) = self.focus_item.get().aborted_indexes() {
let tree = Self::item_tree();
match tree[item_index] {
ItemTreeNode::Item { item, .. } => {
item.apply_pin(self).as_ref().key_event(&event, window)
}
ItemTreeNode::DynamicTree { index } => {
match index {
#(#repeated_key_event_branch)*
_ => panic!("invalid index {}", index),
}
}
}
} else {
KeyEventResult::EventIgnored
}
}
fn focus_event(self: ::core::pin::Pin<&Self>, event: &sixtyfps::re_exports::FocusEvent, window: &sixtyfps::re_exports::ComponentWindow)
-> sixtyfps::re_exports::FocusEventResult {
use sixtyfps::re_exports::*;
#[allow(unused)]
match event {
FocusEvent::FocusIn(_) => {
let (event_result, visit_result) = locate_and_activate_focus_item(&VRc::into_dyn(self.as_ref().self_weak.get().unwrap().upgrade().unwrap()), event, window);
if event_result == FocusEventResult::FocusItemFound {
self.focus_item.set(visit_result)
}
event_result
}
FocusEvent::FocusOut | FocusEvent::WindowReceivedFocus | FocusEvent::WindowLostFocus => {
if let Some((item_index, rep_index)) = self.focus_item.get().aborted_indexes() {
let tree = Self::item_tree();
match tree[item_index] {
ItemTreeNode::Item { item, .. } => {
item.apply_pin(self).as_ref().focus_event(&event, window)
}
ItemTreeNode::DynamicTree { index } => {
match index {
#(#repeated_focus_branch)*
_ => panic!("invalid index {}", index),
};
}
};
// Preserve the focus_item field unless we're clearing it as part of a focus out phase.
if matches!(event, FocusEvent::FocusOut) {
self.focus_item.set(VisitChildrenResult::CONTINUE);
}
FocusEventResult::FocusItemFound // We had a focus item and "found" it and notified it
} else {
FocusEventResult::FocusItemNotFound
}
}
}
}
#layouts
fn get_item_ref(self: ::core::pin::Pin<&Self>, index: usize) -> ::core::pin::Pin<ItemRef> {
@ -842,7 +774,6 @@ fn generate_component(
#(#self_weak : sixtyfps::re_exports::OnceCell<sixtyfps::re_exports::VWeak<sixtyfps::re_exports::ComponentVTable, #component_id>>,)*
#(parent : sixtyfps::re_exports::VWeak<sixtyfps::re_exports::ComponentVTable, #parent_component_type>,)*
mouse_grabber: ::core::cell::Cell<sixtyfps::re_exports::VisitChildrenResult>,
focus_item: ::core::cell::Cell<sixtyfps::re_exports::VisitChildrenResult>,
#(#global_name : ::core::pin::Pin<::std::rc::Rc<#global_type>>,)*
#window_field
}
@ -863,7 +794,6 @@ fn generate_component(
#(#self_weak : ::core::default::Default::default(),)*
#(parent : parent as sixtyfps::re_exports::VWeak::<sixtyfps::re_exports::ComponentVTable, #parent_component_type>,)*
mouse_grabber: ::core::cell::Cell::new(sixtyfps::re_exports::VisitChildrenResult::CONTINUE),
focus_item: ::core::cell::Cell::new(sixtyfps::re_exports::VisitChildrenResult::CONTINUE),
#(#global_name : #global_type::new(),)*
#window_field_init
};
@ -1129,9 +1059,11 @@ fn compile_expression(e: &Expression, component: &Rc<Component>) -> TokenStream
panic!("internal error: incorrect argument count to SetFocusItem call");
}
if let Expression::ElementReference(focus_item) = &arguments[0] {
let item = format_ident!("{}", focus_item.upgrade().unwrap().borrow().id);
let focus_item = focus_item.upgrade().unwrap();
let focus_item = focus_item.borrow();
let item_index = focus_item.item_index.get().unwrap();
quote!(
_self.window.set_focus_item(VRef::new_pin(self_pinned.as_pin_ref()), VRef::new_pin(Self::FIELD_OFFSETS.#item.apply_pin(self_pinned.as_pin_ref())));
_self.window.set_focus_item(&VRc::into_dyn(_self.self_weak.get().unwrap().upgrade().unwrap()), #item_index);
)
} else {
panic!("internal error: argument to SetFocusItem must be an element")

View file

@ -165,6 +165,25 @@ pub async fn run_passes<'a>(
passes::resolve_native_classes::resolve_native_classes(&doc.root_component);
passes::collect_globals::collect_globals(&doc.root_component, diag);
passes::collect_structs::collect_structs(&doc.root_component, diag);
fn generate_item_indices(component: &Rc<object_tree::Component>) {
let mut current_item_index: usize = 0;
generator::build_array_helper(&component, move |item_rc, _, is_flickable_rect| {
let item = item_rc.borrow();
if is_flickable_rect {
current_item_index += 1;
} else if item.base_type == crate::langtype::Type::Void {
} else if item.repeated.is_some() {
generate_item_indices(&*item.base_type.as_component());
current_item_index += 1;
} else {
item.item_index.set(current_item_index).unwrap();
current_item_index += 1;
}
});
}
generate_item_indices(&doc.root_component);
}
mod library {

View file

@ -268,6 +268,10 @@ pub struct Element {
pub child_of_layout: bool,
/// This is the component-local index of this item in the item tree array.
/// It is generated after the last pass and before the generators run.
pub item_index: once_cell::unsync::OnceCell<usize>,
/// The AST node, if available
pub node: Option<syntax_nodes::Element>,
}

View file

@ -167,6 +167,7 @@ fn duplicate_element_with_mapping(
.map(|t| duplicate_transition(t, mapping, root_component))
.collect(),
child_of_layout: elem.child_of_layout,
item_index: Default::default(), // Not determined yet
}));
mapping.insert(element_key(element.clone()), new.clone());
new

View file

@ -46,6 +46,7 @@ fn create_repeater_components(component: &Rc<Component>) {
states: std::mem::take(&mut elem.states),
transitions: std::mem::take(&mut elem.transitions),
child_of_layout: elem.child_of_layout,
item_index: Default::default(), // Not determined yet
})),
parent_element,
..Component::default()

View file

@ -13,9 +13,7 @@ LICENSE END */
use crate::eventloop::ComponentWindow;
use crate::graphics::Rect;
use crate::input::{
FocusEvent, FocusEventResult, InputEventResult, KeyEvent, KeyEventResult, MouseEvent,
};
use crate::input::{InputEventResult, MouseEvent};
use crate::item_tree::{ItemVisitorVTable, TraversalOrder, VisitChildrenResult};
use crate::items::ItemVTable;
use crate::layout::LayoutInfo;
@ -52,23 +50,8 @@ pub struct ComponentVTable {
core::pin::Pin<VRef<ComponentVTable>>,
MouseEvent,
&ComponentWindow,
&core::pin::Pin<VRef<ComponentVTable>>,
) -> InputEventResult,
/// key event
pub key_event: extern "C" fn(
core::pin::Pin<VRef<ComponentVTable>>,
&KeyEvent,
&ComponentWindow,
) -> KeyEventResult,
/// Event sent to transfer focus between items or to communicate window focus change.
pub focus_event: extern "C" fn(
core::pin::Pin<VRef<ComponentVTable>>,
&FocusEvent,
&ComponentWindow,
) -> FocusEventResult,
/// in-place destructor (for VRc)
pub drop_in_place: unsafe fn(VRefMut<ComponentVTable>) -> vtable::Layout,
/// dealloc function (for VRc)

View file

@ -13,18 +13,13 @@ LICENSE END */
[GenericWindow] trait used by the generated code and the run-time to change
aspects of windows on the screen.
*/
use crate::{
component::{ComponentRc, ComponentVTable},
items::ItemRef,
slice::Slice,
};
use crate::{component::ComponentRc, items::ItemRef, slice::Slice};
use std::cell::RefCell;
use std::{
convert::TryInto,
pin::Pin,
rc::{Rc, Weak},
};
use vtable::*;
use crate::input::{KeyEvent, MouseEventType};
#[cfg(not(target_arch = "wasm32"))]
@ -107,11 +102,7 @@ pub trait GenericWindow {
/// Sets the focus to the item pointed to by item_ptr. This will remove the focus from any
/// currently focused item.
fn set_focus_item(
self: Rc<Self>,
component: core::pin::Pin<crate::component::ComponentRef>,
item_ptr: *const u8,
);
fn set_focus_item(self: Rc<Self>, focus_item_component: &ComponentRc, focus_item_index: usize);
/// Sets the focus on the window to true or false, depending on the have_focus argument.
/// This results in WindowFocusReceived and WindowFocusLost events.
fn set_focus(self: Rc<Self>, have_focus: bool);
@ -181,12 +172,8 @@ impl ComponentWindow {
/// Clears the focus on any previously focused item and makes the provided
/// item the focus item, in order to receive future key events.
pub fn set_focus_item(
&self,
component: core::pin::Pin<crate::component::ComponentRef>,
item: Pin<VRef<crate::items::ItemVTable>>,
) {
self.0.clone().set_focus_item(component, item.as_ptr())
pub fn set_focus_item(&self, focus_item_component: &ComponentRc, focus_item_index: usize) {
self.0.clone().set_focus_item(focus_item_component, focus_item_index)
}
/// Associates this window with the specified component, for future event handling, etc.
@ -532,7 +519,6 @@ pub mod ffi {
#![allow(unsafe_code)]
use super::*;
use crate::items::ItemVTable;
#[allow(non_camel_case_types)]
type c_void = ();
@ -609,11 +595,11 @@ pub mod ffi {
#[no_mangle]
pub unsafe extern "C" fn sixtyfps_component_window_set_focus_item(
handle: *const ComponentWindowOpaque,
component: Pin<VRef<ComponentVTable>>,
item: Pin<VRef<ItemVTable>>,
focus_item_component: &ComponentRc,
focus_item_index: usize,
) {
let window = &*(handle as *const ComponentWindow);
window.set_focus_item(component, item)
window.set_focus_item(focus_item_component, focus_item_index)
}
/// Associates the window with the given component.

View file

@ -526,6 +526,8 @@ pub struct GraphicsWindow<Backend: GraphicsBackend + 'static> {
keyboard_modifiers: std::cell::Cell<KeyboardModifiers>,
component: std::cell::RefCell<ComponentWeak>,
layout_listener: Pin<Rc<PropertyTracker>>,
focus_item_component: std::cell::RefCell<ComponentWeak>,
focus_item_index: std::cell::Cell<usize>,
}
impl<Backend: GraphicsBackend + 'static> GraphicsWindow<Backend> {
@ -547,6 +549,8 @@ impl<Backend: GraphicsBackend + 'static> GraphicsWindow<Backend> {
keyboard_modifiers: Default::default(),
component: Default::default(),
layout_listener: Rc::pin(Default::default()),
focus_item_component: Default::default(),
focus_item_index: Default::default(),
})
}
@ -631,7 +635,7 @@ impl<Backend: GraphicsBackend> crate::eventloop::GenericWindow for GraphicsWindo
crate::item_tree::visit_items(
&component_rc,
crate::item_tree::TraversalOrder::BackToFront,
|_, item, _| {
|_, item, _, _| {
crate::item_rendering::update_item_rendering_data(
item,
&window.rendering_cache,
@ -674,15 +678,17 @@ impl<Backend: GraphicsBackend> crate::eventloop::GenericWindow for GraphicsWindo
component.as_ref().input_event(
MouseEvent { pos: euclid::point2(pos.x as _, pos.y as _), what },
&crate::eventloop::ComponentWindow::new(self.clone()),
&component,
);
}
fn process_key_input(self: Rc<Self>, event: &KeyEvent) {
let component = self.component.borrow().upgrade().unwrap();
ComponentRc::borrow_pin(&component)
.as_ref()
.key_event(event, &crate::eventloop::ComponentWindow::new(self.clone()));
if let Some(focus_item_component) = self.as_ref().focus_item_component.borrow().upgrade() {
let window = &crate::eventloop::ComponentWindow::new(self.clone());
let comp_ref_pin = ComponentRc::borrow_pin(&focus_item_component);
let focus_item =
comp_ref_pin.as_ref().get_item_ref(self.as_ref().focus_item_index.get() as usize);
focus_item.as_ref().key_event(event, &window);
}
}
fn with_platform_window(&self, callback: &dyn Fn(&winit::window::Window)) {
@ -855,14 +861,25 @@ impl<Backend: GraphicsBackend> crate::eventloop::GenericWindow for GraphicsWindo
self.keyboard_modifiers.set(state)
}
fn set_focus_item(
self: Rc<Self>,
component: core::pin::Pin<crate::component::ComponentRef>,
item_ptr: *const u8,
) {
fn set_focus_item(self: Rc<Self>, focus_item_component: &ComponentRc, focus_item_index: usize) {
let window = crate::eventloop::ComponentWindow::new(self.clone());
component.as_ref().focus_event(&crate::input::FocusEvent::FocusOut, &window);
component.as_ref().focus_event(&crate::input::FocusEvent::FocusIn(item_ptr), &window);
if let Some(old_focus_item_component) =
self.as_ref().focus_item_component.borrow().upgrade()
{
let comp_ref_pin = ComponentRc::borrow_pin(&old_focus_item_component);
let old_focus_item =
comp_ref_pin.as_ref().get_item_ref(self.as_ref().focus_item_index.get());
old_focus_item.as_ref().focus_event(&crate::input::FocusEvent::FocusOut, &window);
}
*self.as_ref().focus_item_component.borrow_mut() =
ComponentRc::downgrade(&focus_item_component);
self.as_ref().focus_item_index.set(focus_item_index);
let comp_ref_pin = ComponentRc::borrow_pin(&focus_item_component);
let new_focus_item = comp_ref_pin.as_ref().get_item_ref(focus_item_index);
new_focus_item.as_ref().focus_event(&crate::input::FocusEvent::FocusIn, &window);
}
fn set_focus(self: Rc<Self>, have_focus: bool) {
@ -872,8 +889,13 @@ impl<Backend: GraphicsBackend> crate::eventloop::GenericWindow for GraphicsWindo
} else {
crate::input::FocusEvent::WindowLostFocus
};
let component = self.component.borrow().upgrade().unwrap();
ComponentRc::borrow_pin(&component).as_ref().focus_event(&event, &window);
if let Some(focus_item_component) = self.as_ref().focus_item_component.borrow().upgrade() {
let comp_ref_pin = ComponentRc::borrow_pin(&focus_item_component);
let focus_item =
comp_ref_pin.as_ref().get_item_ref(self.as_ref().focus_item_index.get() as usize);
focus_item.as_ref().focus_event(&event, &window);
}
}
}

View file

@ -11,7 +11,7 @@ LICENSE END */
*/
#![warn(missing_docs)]
use crate::component::{ComponentRc, ComponentRefPin};
use crate::component::ComponentRc;
use crate::graphics::Point;
use crate::item_tree::{ItemVisitorResult, VisitChildrenResult};
use euclid::default::Vector2D;
@ -453,10 +453,8 @@ pub enum KeyEventResult {
#[derive(Debug, Clone, PartialEq)]
#[repr(C)]
pub enum FocusEvent {
/// This event is sent when an item receives the focus. The value contained
/// in the tuple is a raw pointer to the item that is intended to receive the
/// focus. This is only used for equality comparison.
FocusIn(*const u8),
/// This event is sent when an item receives the focus.
FocusIn,
/// This event is sent when an item looses the focus.
FocusOut,
/// This event is sent when the window receives the keyboard focus.
@ -465,52 +463,6 @@ pub enum FocusEvent {
WindowLostFocus,
}
/// Represents how a component's focus_event dealt with the transfer of focus
/// to an item.
#[derive(Debug, Clone, PartialEq, Copy)]
#[repr(C)]
pub enum FocusEventResult {
/// The requested item to transfer focus to was found.
FocusItemFound,
/// The requested focus item was not in the component's tree of items.
FocusItemNotFound,
}
/// Scans the tree of items of the component to locate the item pointed to by
/// the focus_event (assuming it is of type FocusIn). Once located, the focus in
/// even will also be dispatched to the item itself.
pub fn locate_and_activate_focus_item(
component: &ComponentRc,
focus_event: &FocusEvent,
window: &crate::eventloop::ComponentWindow,
) -> (FocusEventResult, VisitChildrenResult) {
let mut result = FocusEventResult::FocusItemNotFound;
let item_index = crate::item_tree::visit_items(
component,
crate::item_tree::TraversalOrder::FrontToBack,
|_, item, _| -> ItemVisitorResult<()> {
if let FocusEvent::FocusIn(new_focus_item_ptr) = focus_event {
if item.as_ptr() == *new_focus_item_ptr {
item.as_ref().focus_event(focus_event, window);
result = FocusEventResult::FocusItemFound;
return ItemVisitorResult::Abort;
}
}
ItemVisitorResult::Continue(())
},
(),
);
(
result,
if result == FocusEventResult::FocusItemFound {
item_index
} else {
VisitChildrenResult::CONTINUE
},
)
}
/// Feed the given mouse event into the tree of items that component holds. The
/// event will be delivered to items in front first.
///
@ -525,7 +477,6 @@ pub fn process_ungrabbed_mouse_event(
component: &ComponentRc,
event: MouseEvent,
window: &crate::eventloop::ComponentWindow,
app_component: ComponentRefPin,
) -> (InputEventResult, VisitChildrenResult) {
let offset = Vector2D::new(0., 0.);
@ -533,14 +484,14 @@ pub fn process_ungrabbed_mouse_event(
let item_index = crate::item_tree::visit_items(
component,
crate::item_tree::TraversalOrder::FrontToBack,
|_, item, offset| -> ItemVisitorResult<Vector2D<f32>> {
|comp_rc, item, item_index, offset| -> ItemVisitorResult<Vector2D<f32>> {
let geom = item.as_ref().geometry();
let geom = geom.translate(*offset);
if geom.contains(event.pos) {
let mut event2 = event.clone();
event2.pos -= geom.origin.to_vector();
match item.as_ref().input_event(event2, window, app_component) {
match item.as_ref().input_event(event2, window, comp_rc, item_index) {
InputEventResult::EventAccepted => {
result = InputEventResult::EventAccepted;
return ItemVisitorResult::Abort;
@ -599,10 +550,9 @@ pub(crate) mod ffi {
component: &ComponentRc,
event: MouseEvent,
window: &crate::eventloop::ComponentWindow,
app_component: core::pin::Pin<crate::component::ComponentRef>,
new_mouse_grabber: &mut crate::item_tree::VisitChildrenResult,
) -> InputEventResult {
let (res, grab) = process_ungrabbed_mouse_event(component, event, window, app_component);
let (res, grab) = process_ungrabbed_mouse_event(component, event, window);
*new_mouse_grabber = grab;
res
}
@ -617,16 +567,4 @@ pub(crate) mod ffi {
) -> (InputEventResult, crate::item_tree::VisitChildrenResult) {
process_grabbed_mouse_event(component, item, offset, event, old_grab)
}*/
#[no_mangle]
pub extern "C" fn sixtyfps_locate_and_activate_focus_item(
component: &ComponentRc,
event: &FocusEvent,
window: &crate::eventloop::ComponentWindow,
new_focus_item: &mut crate::item_tree::VisitChildrenResult,
) -> FocusEventResult {
let (result, focus_item) = locate_and_activate_focus_item(component, event, window);
*new_focus_item = focus_item;
result
}
}

View file

@ -95,7 +95,7 @@ pub(crate) fn render_component_items<Backend: GraphicsBackend>(
crate::item_tree::visit_items_with_post_visit(
component,
crate::item_tree::TraversalOrder::BackToFront,
|_, item, transform| {
|_, item, _, transform| {
let origin = item.as_ref().geometry().origin;
let transform =
transform * Matrix4::from_translation(Vector3::new(origin.x, origin.y, 0.));

View file

@ -140,13 +140,13 @@ pub enum ItemVisitorResult<State> {
pub fn visit_items<State>(
component: &ComponentRc,
order: TraversalOrder,
mut visitor: impl FnMut(&ComponentRc, Pin<ItemRef>, &State) -> ItemVisitorResult<State>,
mut visitor: impl FnMut(&ComponentRc, Pin<ItemRef>, usize, &State) -> ItemVisitorResult<State>,
state: State,
) -> VisitChildrenResult {
visit_internal(
component,
order,
&mut |component, item, state| (visitor(component, item, state), ()),
&mut |component, item, index, state| (visitor(component, item, index, state), ()),
&mut |_, _, _| {},
-1,
&state,
@ -164,6 +164,7 @@ pub fn visit_items_with_post_visit<State, PostVisitState>(
mut visitor: impl FnMut(
&ComponentRc,
Pin<ItemRef>,
usize,
&State,
) -> (ItemVisitorResult<State>, PostVisitState),
mut post_visitor: impl FnMut(&ComponentRc, Pin<ItemRef>, PostVisitState),
@ -178,6 +179,7 @@ fn visit_internal<State, PostVisitState>(
visitor: &mut impl FnMut(
&ComponentRc,
Pin<ItemRef>,
usize,
&State,
) -> (ItemVisitorResult<State>, PostVisitState),
post_visitor: &mut impl FnMut(&ComponentRc, Pin<ItemRef>, PostVisitState),
@ -188,7 +190,7 @@ fn visit_internal<State, PostVisitState>(
index: usize,
item: Pin<ItemRef>|
-> VisitChildrenResult {
match visitor(component, item, state) {
match visitor(component, item, index, state) {
(ItemVisitorResult::Continue(state), post_visit_state) => {
let result =
visit_internal(component, order, visitor, post_visitor, index as isize, &state);

View file

@ -25,7 +25,7 @@ When adding an item or a property, it needs to be kept in sync with different pl
#![allow(non_upper_case_globals)]
#![allow(missing_docs)] // because documenting each property of items is redundent
use super::component::{ComponentRefPin, ComponentVTable};
use super::component::ComponentVTable;
use super::eventloop::ComponentWindow;
use super::graphics::{Color, HighLevelRenderingPrimitive, PathData, Rect, Resource};
use super::input::{
@ -84,7 +84,8 @@ pub struct ItemVTable {
core::pin::Pin<VRef<ItemVTable>>,
MouseEvent,
window: &ComponentWindow,
app_component: core::pin::Pin<VRef<ComponentVTable>>,
self_component: &VRc<ComponentVTable, vtable::Dyn>,
self_index: usize,
) -> InputEventResult,
pub focus_event:
@ -160,7 +161,8 @@ impl Item for Rectangle {
self: Pin<&Self>,
_: MouseEvent,
_window: &ComponentWindow,
_app_component: ComponentRefPin,
_self_component: &VRc<ComponentVTable, vtable::Dyn>,
_self_index: usize,
) -> InputEventResult {
InputEventResult::EventIgnored
}
@ -248,7 +250,8 @@ impl Item for BorderRectangle {
self: Pin<&Self>,
_: MouseEvent,
_window: &ComponentWindow,
_app_component: ComponentRefPin,
_self_component: &VRc<ComponentVTable, vtable::Dyn>,
_self_index: usize,
) -> InputEventResult {
InputEventResult::EventIgnored
}
@ -334,7 +337,8 @@ impl Item for Image {
self: Pin<&Self>,
_: MouseEvent,
_window: &ComponentWindow,
_app_component: ComponentRefPin,
_self_component: &VRc<ComponentVTable, vtable::Dyn>,
_self_index: usize,
) -> InputEventResult {
InputEventResult::EventIgnored
}
@ -476,7 +480,8 @@ impl Item for Text {
self: Pin<&Self>,
_: MouseEvent,
_window: &ComponentWindow,
_app_component: ComponentRefPin,
_self_component: &VRc<ComponentVTable, vtable::Dyn>,
_self_index: usize,
) -> InputEventResult {
InputEventResult::EventIgnored
}
@ -567,7 +572,8 @@ impl Item for TouchArea {
self: Pin<&Self>,
event: MouseEvent,
_window: &ComponentWindow,
_app_component: ComponentRefPin,
_self_component: &VRc<ComponentVTable, vtable::Dyn>,
_self_index: usize,
) -> InputEventResult {
Self::FIELD_OFFSETS.mouse_x.apply_pin(self).set(event.pos.x);
Self::FIELD_OFFSETS.mouse_y.apply_pin(self).set(event.pos.y);
@ -674,7 +680,8 @@ impl Item for Path {
self: Pin<&Self>,
_: MouseEvent,
_window: &ComponentWindow,
_app_component: ComponentRefPin,
_self_component: &VRc<ComponentVTable, vtable::Dyn>,
_self_index: usize,
) -> InputEventResult {
InputEventResult::EventIgnored
}
@ -750,7 +757,8 @@ impl Item for Flickable {
self: Pin<&Self>,
event: MouseEvent,
_window: &ComponentWindow,
_app_component: ComponentRefPin,
_self_component: &VRc<ComponentVTable, vtable::Dyn>,
_self_index: usize,
) -> InputEventResult {
if !Self::FIELD_OFFSETS.interactive.apply_pin(self).get() {
return InputEventResult::EventIgnored;
@ -875,7 +883,8 @@ impl Item for Window {
self: Pin<&Self>,
_event: MouseEvent,
_window: &ComponentWindow,
_app_component: ComponentRefPin,
_self_component: &VRc<ComponentVTable, vtable::Dyn>,
_self_index: usize,
) -> InputEventResult {
InputEventResult::EventIgnored
}
@ -1034,7 +1043,8 @@ impl Item for TextInput {
self: Pin<&Self>,
event: MouseEvent,
window: &ComponentWindow,
app_component: ComponentRefPin,
self_component: &VRc<ComponentVTable, vtable::Dyn>,
self_index: usize,
) -> InputEventResult {
if !Self::FIELD_OFFSETS.enabled.apply_pin(self).get() {
return InputEventResult::EventIgnored;
@ -1050,7 +1060,7 @@ impl Item for TextInput {
self.as_ref().anchor_position.set(clicked_offset);
self.as_ref().cursor_position.set(clicked_offset);
if !Self::FIELD_OFFSETS.has_focus.apply_pin(self).get() {
window.set_focus_item(app_component, VRef::new_pin(self));
window.set_focus_item(self_component, self_index);
}
}
@ -1166,7 +1176,7 @@ impl Item for TextInput {
fn focus_event(self: Pin<&Self>, event: &FocusEvent, window: &ComponentWindow) {
match event {
FocusEvent::FocusIn(_) | FocusEvent::WindowReceivedFocus => {
FocusEvent::FocusIn | FocusEvent::WindowReceivedFocus => {
self.has_focus.set(true);
self.show_cursor(window);
}

View file

@ -17,7 +17,6 @@ use std::{
rc::{Rc, Weak},
};
use crate::component::ComponentRefPin;
use crate::items::ItemRef;
use crate::Property;
@ -562,36 +561,9 @@ impl<C: RepeatedComponent> Repeater<C> {
idx: usize,
event: crate::input::MouseEvent,
window: &crate::eventloop::ComponentWindow,
app_component: &ComponentRefPin,
) -> crate::input::InputEventResult {
let c = self.inner.borrow().borrow().components[idx].1.clone();
c.map_or(Default::default(), |c| c.as_pin_ref().input_event(event, window, app_component))
}
/// Forward a key event to a particular item
pub fn key_event(
&self,
idx: usize,
event: &crate::input::KeyEvent,
window: &crate::eventloop::ComponentWindow,
) -> crate::input::KeyEventResult {
let c = self.inner.borrow().borrow().components[idx].1.clone();
c.map_or(crate::input::KeyEventResult::EventIgnored, |c| {
c.as_pin_ref().key_event(event, window)
})
}
/// Forward a focus event to a particular item
pub fn focus_event(
&self,
idx: usize,
event: &crate::input::FocusEvent,
window: &crate::eventloop::ComponentWindow,
) -> crate::input::FocusEventResult {
let c = self.inner.borrow().borrow().components[idx].1.clone();
c.map_or(crate::input::FocusEventResult::FocusItemNotFound, |c| {
c.as_pin_ref().focus_event(event, window)
})
c.map_or(Default::default(), |c| c.as_pin_ref().input_event(event, window))
}
/// Return the amount of item currently in the component

View file

@ -35,22 +35,10 @@ pub extern "C" fn sixtyfps_send_mouse_click(
) {
component.as_ref().apply_layout(window.0.get_geometry());
let pos = euclid::point2(x, y);
component.as_ref().input_event(
MouseEvent { pos, what: MouseEventType::MouseMoved },
window,
&component,
);
component.as_ref().input_event(
MouseEvent { pos, what: MouseEventType::MousePressed },
window,
&component,
);
component.as_ref().input_event(MouseEvent { pos, what: MouseEventType::MouseMoved }, window);
component.as_ref().input_event(MouseEvent { pos, what: MouseEventType::MousePressed }, window);
sixtyfps_mock_elapsed_time(50);
component.as_ref().input_event(
MouseEvent { pos, what: MouseEventType::MouseReleased },
window,
&component,
);
component.as_ref().input_event(MouseEvent { pos, what: MouseEventType::MouseReleased }, window);
}
/// Simulate a change in keyboard modifiers pressed.

View file

@ -19,10 +19,9 @@ use sixtyfps_compilerlib::langtype::Type;
use sixtyfps_compilerlib::layout::{Layout, LayoutConstraints, LayoutItem, PathLayout};
use sixtyfps_compilerlib::*;
use sixtyfps_corelib::component::{Component, ComponentRefPin, ComponentVTable};
use sixtyfps_corelib::eventloop::ComponentWindow;
use sixtyfps_corelib::graphics::{Rect, Resource};
use sixtyfps_corelib::input::{
FocusEventResult, InputEventResult, KeyEvent, KeyEventResult, MouseEvent,
};
use sixtyfps_corelib::input::{InputEventResult, MouseEvent};
use sixtyfps_corelib::item_tree::{
ItemTreeNode, ItemVisitorRefMut, ItemVisitorVTable, TraversalOrder, VisitChildrenResult,
};
@ -33,7 +32,6 @@ use sixtyfps_corelib::model::Repeater;
use sixtyfps_corelib::properties::InterpolatedPropertyValue;
use sixtyfps_corelib::rtti::{self, AnimatedBindingKind, FieldOffset, PropertyInfo};
use sixtyfps_corelib::slice::Slice;
use sixtyfps_corelib::{eventloop::ComponentWindow, input::FocusEvent};
use sixtyfps_corelib::{Color, Property, SharedString, Signal};
use std::collections::HashMap;
use std::{pin::Pin, rc::Rc};
@ -112,6 +110,10 @@ impl ItemWithinComponent {
NonNull::new(mem.add(self.offset) as _).unwrap(),
))
}
pub(crate) fn item_index(&self) -> usize {
*self.elem.borrow().item_index.get().unwrap()
}
}
pub(crate) struct PropertiesWithinComponent {
@ -205,25 +207,8 @@ impl Component for ErasedComponentBox {
self: Pin<&Self>,
mouse_event: sixtyfps_corelib::input::MouseEvent,
window: &ComponentWindow,
app_component: &ComponentRefPin,
) -> sixtyfps_corelib::input::InputEventResult {
self.borrow().as_ref().input_event(mouse_event, window, app_component)
}
fn key_event(
self: Pin<&Self>,
event: &sixtyfps_corelib::input::KeyEvent,
window: &ComponentWindow,
) -> sixtyfps_corelib::input::KeyEventResult {
self.borrow().as_ref().key_event(event, window)
}
fn focus_event(
self: Pin<&Self>,
event: &sixtyfps_corelib::input::FocusEvent,
window: &ComponentWindow,
) -> sixtyfps_corelib::input::FocusEventResult {
self.borrow().as_ref().focus_event(event, window)
self.borrow().as_ref().input_event(mouse_event, window)
}
fn layout_info(self: Pin<&Self>) -> sixtyfps_corelib::layout::LayoutInfo {
@ -244,7 +229,6 @@ sixtyfps_corelib::ComponentVTable_static!(static COMPONENT_BOX_VT for ErasedComp
pub(crate) struct ComponentExtraData {
mouse_grabber: core::cell::Cell<VisitChildrenResult>,
focus_item: core::cell::Cell<VisitChildrenResult>,
pub(crate) globals: HashMap<String, Pin<Rc<dyn crate::global_component::GlobalComponent>>>,
pub(crate) self_weak:
once_cell::unsync::OnceCell<vtable::VWeak<ComponentVTable, ErasedComponentBox>>,
@ -254,7 +238,6 @@ impl Default for ComponentExtraData {
fn default() -> Self {
Self {
mouse_grabber: core::cell::Cell::new(VisitChildrenResult::CONTINUE),
focus_item: core::cell::Cell::new(VisitChildrenResult::CONTINUE),
globals: HashMap::new(),
self_weak: Default::default(),
}
@ -703,8 +686,6 @@ fn generate_component<'id>(
layout_info,
apply_layout,
input_event,
key_event,
focus_event,
get_item_ref,
drop_in_place,
dealloc,
@ -1462,33 +1443,32 @@ extern "C" fn input_event(
component: ComponentRefPin,
mouse_event: sixtyfps_corelib::input::MouseEvent,
window: &sixtyfps_corelib::eventloop::ComponentWindow,
app_component: &ComponentRefPin,
) -> sixtyfps_corelib::input::InputEventResult {
// This is fine since we can only be called with a component that with our vtable which is a ComponentDescription
let component_type = unsafe { get_component_type(component) };
let instance = unsafe { Pin::new_unchecked(&*component.as_ptr().cast::<Instance>()) };
let extra_data = component_type.extra_data_offset.apply(&*instance);
generativity::make_guard!(guard);
let instance_ref = unsafe { InstanceRef::from_pin_ref(component, guard) };
let comp_rc = instance_ref.self_weak().get().unwrap().upgrade().unwrap();
let mouse_grabber = extra_data.mouse_grabber.get();
let (status, new_grab) = if let Some((item_index, rep_index)) = mouse_grabber.aborted_indexes()
{
let (status, new_grab) =
if let Some((item_index, rep_index)) = mouse_grabber.aborted_indexes() {
let tree = &component_type.item_tree;
let offset = sixtyfps_corelib::item_tree::item_offset(instance, tree, item_index);
let mut event = mouse_event.clone();
event.pos -= offset.to_vector();
let res = match tree[item_index] {
ItemTreeNode::Item { item, .. } => {
item.apply_pin(instance).as_ref().input_event(event, window, app_component.clone())
}
let res =
match tree[item_index] {
ItemTreeNode::Item { item, .. } => item
.apply_pin(instance)
.as_ref()
.input_event(event, window, &vtable::VRc::into_dyn(comp_rc), item_index),
ItemTreeNode::DynamicTree { index } => {
generativity::make_guard!(guard);
let rep_in_comp = component_type.repeater[index].unerase(guard);
rep_in_comp.offset.apply_pin(instance).input_event(
rep_index,
event,
window,
app_component,
)
rep_in_comp.offset.apply_pin(instance).input_event(rep_index, event, window)
}
};
match res {
@ -1496,102 +1476,16 @@ extern "C" fn input_event(
_ => (res, VisitChildrenResult::CONTINUE),
}
} else {
generativity::make_guard!(guard);
let instance_ref = unsafe { InstanceRef::from_pin_ref(component, guard) };
let comp_rc = instance_ref.self_weak().get().unwrap().upgrade().unwrap();
sixtyfps_corelib::input::process_ungrabbed_mouse_event(
&vtable::VRc::into_dyn(comp_rc),
mouse_event,
window,
app_component.clone(),
)
};
extra_data.mouse_grabber.set(new_grab);
status
}
extern "C" fn key_event(
component: ComponentRefPin,
key_event: &sixtyfps_corelib::input::KeyEvent,
window: &sixtyfps_corelib::eventloop::ComponentWindow,
) -> KeyEventResult {
// This is fine since we can only be called with a component that with our vtable which is a ComponentDescription
let component_type = unsafe { get_component_type(component) };
let instance = unsafe { Pin::new_unchecked(&*component.as_ptr().cast::<Instance>()) };
let extra_data = component_type.extra_data_offset.apply(&*instance);
if let Some((item_index, rep_index)) = extra_data.focus_item.get().aborted_indexes() {
let tree = &component_type.item_tree;
match tree[item_index] {
ItemTreeNode::Item { item, .. } => {
item.apply_pin(instance).as_ref().key_event(key_event, window)
}
ItemTreeNode::DynamicTree { index } => {
generativity::make_guard!(guard);
let rep_in_comp = &component_type.repeater[index].unerase(guard);
rep_in_comp.offset.apply_pin(instance).key_event(rep_index, key_event, window)
}
}
} else {
KeyEventResult::EventIgnored
}
}
extern "C" fn focus_event(
component: ComponentRefPin,
event: &FocusEvent,
window: &sixtyfps_corelib::eventloop::ComponentWindow,
) -> FocusEventResult {
// This is fine since we can only be called with a component that with our vtable which is a ComponentDescription
let component_type = unsafe { get_component_type(component) };
let instance = unsafe { Pin::new_unchecked(&*component.as_ptr().cast::<Instance>()) };
let extra_data = component_type.extra_data_offset.apply(&*instance);
match event {
FocusEvent::FocusIn(_) => {
generativity::make_guard!(guard);
let instance_ref = unsafe { InstanceRef::from_pin_ref(component, guard) };
let comp_rc = instance_ref.self_weak().get().unwrap().upgrade().unwrap();
let (event_result, visit_result) =
sixtyfps_corelib::input::locate_and_activate_focus_item(
&vtable::VRc::into_dyn(comp_rc),
event,
window,
);
if event_result == FocusEventResult::FocusItemFound {
extra_data.focus_item.set(visit_result)
}
event_result
}
FocusEvent::FocusOut | FocusEvent::WindowReceivedFocus | FocusEvent::WindowLostFocus => {
if let Some((item_index, rep_index)) = extra_data.focus_item.get().aborted_indexes() {
let tree = &component_type.item_tree;
match tree[item_index] {
ItemTreeNode::Item { item, .. } => {
item.apply_pin(instance).as_ref().focus_event(&event, window)
}
ItemTreeNode::DynamicTree { index } => {
generativity::make_guard!(guard);
let rep_in_comp = &component_type.repeater[index].unerase(guard);
rep_in_comp
.offset
.apply_pin(instance)
.focus_event(rep_index, &event, window);
}
};
// Preserve the focus_item field unless we're clearing it as part of a focus out phase.
if matches!(event, sixtyfps_corelib::input::FocusEvent::FocusOut) {
extra_data.focus_item.set(VisitChildrenResult::CONTINUE);
}
FocusEventResult::FocusItemFound // We had a focus item and "found" it and notified it
} else {
FocusEventResult::FocusItemNotFound
}
}
}
}
extern "C" fn layout_info(component: ComponentRefPin) -> LayoutInfo {
generativity::make_guard!(guard);
// This is fine since we can only be called with a component that with our vtable which is a ComponentDescription

View file

@ -402,12 +402,6 @@ pub fn eval_expression(e: &Expression, local_context: &mut EvalLocalContext) ->
};
if let Expression::ElementReference(focus_item) = &arguments[0] {
generativity::make_guard!(guard);
let component_ref: Pin<vtable::VRef<corelib::component::ComponentVTable>> = unsafe {
Pin::new_unchecked(vtable::VRef::from_raw(
core::ptr::NonNull::from(&component.component_type.ct).cast(),
core::ptr::NonNull::from(&*component.as_ptr()),
))
};
let focus_item = focus_item.upgrade().unwrap();
let enclosing_component =
@ -415,10 +409,10 @@ pub fn eval_expression(e: &Expression, local_context: &mut EvalLocalContext) ->
let component_type = enclosing_component.component_type;
let item_info = &component_type.items[focus_item.borrow().id.as_str()];
let item =
unsafe { item_info.item_from_component(enclosing_component.as_ptr()) };
window_ref(component).unwrap().set_focus_item(component_ref, item);
let focus_item_comp = enclosing_component.self_weak().get().unwrap().upgrade().unwrap();
window_ref(component).unwrap().set_focus_item(&vtable::VRc::into_dyn(focus_item_comp), item_info.item_index());
Value::Void
} else {
panic!("internal error: argument to SetFocusItem must be an element")

View file

@ -27,7 +27,7 @@ it needs to be kept in sync with different place.
use const_field_offset::FieldOffsets;
use core::pin::Pin;
use cpp::cpp;
use sixtyfps_corelib::component::{ComponentRefPin, ComponentVTable};
use sixtyfps_corelib::component::ComponentVTable;
use sixtyfps_corelib::eventloop::ComponentWindow;
use sixtyfps_corelib::graphics::{HighLevelRenderingPrimitive, Rect, RenderingVariable, Resource};
use sixtyfps_corelib::input::{
@ -197,7 +197,8 @@ impl Item for NativeButton {
self: Pin<&Self>,
event: MouseEvent,
_window: &ComponentWindow,
_app_component: ComponentRefPin,
_self_component: &vtable::VRc<ComponentVTable, vtable::Dyn>,
_self_index: usize,
) -> InputEventResult {
let enabled = Self::FIELD_OFFSETS.enabled.apply_pin(self).get();
if !enabled {
@ -329,7 +330,8 @@ impl Item for NativeCheckBox {
self: Pin<&Self>,
event: MouseEvent,
_window: &ComponentWindow,
_app_component: ComponentRefPin,
_self_component: &vtable::VRc<ComponentVTable, vtable::Dyn>,
_self_index: usize,
) -> InputEventResult {
if matches!(event.what, MouseEventType::MouseReleased) {
Self::FIELD_OFFSETS
@ -490,7 +492,8 @@ impl Item for NativeSpinBox {
self: Pin<&Self>,
event: MouseEvent,
_window: &ComponentWindow,
_app_component: ComponentRefPin,
_self_component: &vtable::VRc<ComponentVTable, vtable::Dyn>,
_self_index: usize,
) -> InputEventResult {
let size: qttypes::QSize = get_size!(self);
let enabled = Self::FIELD_OFFSETS.enabled.apply_pin(self).get();
@ -697,7 +700,8 @@ impl Item for NativeSlider {
self: Pin<&Self>,
event: MouseEvent,
_window: &ComponentWindow,
_app_component: ComponentRefPin,
_self_component: &vtable::VRc<ComponentVTable, vtable::Dyn>,
_self_index: usize,
) -> InputEventResult {
let size: qttypes::QSize = get_size!(self);
let enabled = Self::FIELD_OFFSETS.enabled.apply_pin(self).get();
@ -955,7 +959,8 @@ impl Item for NativeGroupBox {
self: Pin<&Self>,
_: MouseEvent,
_window: &ComponentWindow,
_app_component: ComponentRefPin,
_self_component: &vtable::VRc<ComponentVTable, vtable::Dyn>,
_self_index: usize,
) -> InputEventResult {
InputEventResult::EventIgnored
}
@ -1107,7 +1112,8 @@ impl Item for NativeLineEdit {
self: Pin<&Self>,
_: MouseEvent,
_window: &ComponentWindow,
_app_component: ComponentRefPin,
_self_component: &vtable::VRc<ComponentVTable, vtable::Dyn>,
_self_index: usize,
) -> InputEventResult {
InputEventResult::EventIgnored
}
@ -1358,7 +1364,8 @@ impl Item for NativeScrollView {
self: Pin<&Self>,
event: MouseEvent,
window: &ComponentWindow,
_app_component: ComponentRefPin,
_self_component: &vtable::VRc<ComponentVTable, vtable::Dyn>,
_self_index: usize,
) -> InputEventResult {
let dpr = window.scale_factor();
let size: qttypes::QSize = get_size!(self);
@ -1623,7 +1630,8 @@ impl Item for NativeStandardListViewItem {
self: Pin<&Self>,
_event: MouseEvent,
_window: &ComponentWindow,
_app_component: ComponentRefPin,
_self_component: &vtable::VRc<ComponentVTable, vtable::Dyn>,
_self_index: usize,
) -> InputEventResult {
InputEventResult::EventIgnored
}
@ -1744,7 +1752,8 @@ impl Item for NativeComboBox {
self: Pin<&Self>,
event: MouseEvent,
_window: &ComponentWindow,
_app_component: ComponentRefPin,
_self_component: &vtable::VRc<ComponentVTable, vtable::Dyn>,
_self_index: usize,
) -> InputEventResult {
let enabled = Self::FIELD_OFFSETS.enabled.apply_pin(self).get();
if !enabled {