Allow FocusScope to reject the events

This commit is contained in:
Olivier Goffart 2021-01-26 17:04:43 +01:00
parent 2e23b5bbdd
commit 9de5af75ce
10 changed files with 140 additions and 38 deletions

View file

@ -77,6 +77,7 @@ using cbindgen_private::TextVerticalAlignment;
using cbindgen_private::TraversalOrder;
using cbindgen_private::ImageFit;
using cbindgen_private::KeyEvent;
using cbindgen_private::EventResult;
using cbindgen_private::KeyboardModifiers;
namespace private_api {

View file

@ -104,8 +104,8 @@ export FocusScope := _ {
property <length> width;
property <length> height;
property <bool> has_focus;
callback key_pressed(KeyEvent);
callback key_released(KeyEvent);
callback key_pressed(KeyEvent) -> EventResult;
callback key_released(KeyEvent) -> EventResult;
//-default_size_binding:expands_to_parent_geometry
//-accepts_focus
}

View file

@ -160,6 +160,14 @@ impl<'a> LookupCtx<'a> {
type_loader: None,
}
}
fn return_type(&self) -> &Type {
if let Type::Callback { return_type, .. } = &self.property_type {
return_type.as_ref().map_or(&Type::Void, |b| &(**b))
} else {
&self.property_type
}
}
}
fn find_element_by_id(roots: &[ElementRc], name: &str) -> Option<ElementRc> {
@ -310,11 +318,7 @@ impl Expression {
node: syntax_nodes::ReturnStatement,
ctx: &mut LookupCtx,
) -> Expression {
let return_type = if let Type::Callback { return_type, .. } = &ctx.property_type {
return_type.as_ref().map_or(Type::Void, |b| (**b).clone())
} else {
ctx.property_type.clone()
};
let return_type = ctx.return_type().clone();
Expression::ReturnStatement(node.Expression().map(|n| {
Box::new(Self::from_expression_node(n.into(), ctx).maybe_convert_to(
return_type,
@ -555,7 +559,7 @@ impl Expression {
return Expression::Invalid;
}
match &ctx.property_type {
match ctx.return_type() {
Type::Color => {
if let Some(c) = css_color_parser2::NAMED_COLORS.get(first_str.as_str()) {
let value = ((c.a as u32 * 255) << 24)

View file

@ -122,6 +122,7 @@ impl TypeRegister {
&["stretch", "center", "start", "end", "space_between", "space_around"],
);
declare_enum("ImageFit", &["fill", "contain"]);
declare_enum("EventResult", &["reject", "accept"]);
register.supported_property_animation_types.insert(Type::Float32.to_string());
register.supported_property_animation_types.insert(Type::Int32.to_string());

View file

@ -386,6 +386,21 @@ ItemVTable_static! {
pub static TouchAreaVTable for TouchArea
}
#[derive(Copy, Clone, Debug, PartialEq, strum_macros::EnumString, strum_macros::Display)]
#[repr(C)]
#[allow(non_camel_case_types)]
/// What is returned from the event handler
pub enum EventResult {
reject,
accept,
}
impl Default for EventResult {
fn default() -> Self {
Self::reject
}
}
/// A runtime item that exposes key
#[repr(C)]
#[derive(FieldOffsets, Default, SixtyFPSElement)]
@ -396,8 +411,8 @@ pub struct FocusScope {
pub width: Property<f32>,
pub height: Property<f32>,
pub has_focus: Property<bool>,
pub key_pressed: Callback<KeyEventArg>,
pub key_released: Callback<KeyEventArg>,
pub key_pressed: Callback<KeyEventArg, EventResult>,
pub key_released: Callback<KeyEventArg, EventResult>,
/// FIXME: remove this
pub cached_rendering_data: CachedRenderingData,
}
@ -431,19 +446,22 @@ impl Item for FocusScope {
window.set_focus_item(self_rc);
}
}
InputEventResult::EventAccepted
InputEventResult::EventIgnored
}
fn key_event(self: Pin<&Self>, event: &KeyEvent, _window: &ComponentWindow) -> KeyEventResult {
match event.event_type {
let r = match event.event_type {
KeyEventType::KeyPressed => {
Self::FIELD_OFFSETS.key_pressed.apply_pin(self).call(&(event.clone(),));
Self::FIELD_OFFSETS.key_pressed.apply_pin(self).call(&(event.clone(),))
}
KeyEventType::KeyReleased => {
Self::FIELD_OFFSETS.key_released.apply_pin(self).call(&(event.clone(),));
Self::FIELD_OFFSETS.key_released.apply_pin(self).call(&(event.clone(),))
}
};
KeyEventResult::EventAccepted
match r {
EventResult::accept => KeyEventResult::EventAccepted,
EventResult::reject => KeyEventResult::EventIgnored,
}
}
fn focus_event(self: Pin<&Self>, event: &FocusEvent, _window: &ComponentWindow) {

View file

@ -41,6 +41,7 @@ declare_ValueType![
crate::model::StandardListViewItem,
crate::items::ImageFit,
crate::input::KeyEvent,
crate::items::EventResult,
];
/// What kind of animation is on a binding

View file

@ -247,6 +247,7 @@ declare_value_enum_conversion!(corelib::items::TextVerticalAlignment, TextVertic
declare_value_enum_conversion!(corelib::layout::LayoutAlignment, LayoutAlignment);
declare_value_enum_conversion!(corelib::items::ImageFit, ImageFit);
declare_value_enum_conversion!(corelib::input::KeyEventType, KeyEventType);
declare_value_enum_conversion!(corelib::items::EventResult, EventResult);
impl TryFrom<corelib::animations::Instant> for Value {
type Error = ();

View file

@ -28,6 +28,7 @@ W := Window {
}
debug(event.text);
t.text += event.text;
accept
}
Rectangle { color: yellow; }
}

View file

@ -19,7 +19,8 @@ TestCase := Rectangle {
FocusScope {
width: 75%;
key-pressed(event) => {
recieved += event.text
recieved += event.text;
accept
}
input2 := TextInput {
@ -81,26 +82,4 @@ assert_eq(instance.get_input2_text(), "Hello");
assert_eq(instance.get_input1_text(), "");
assert_eq(instance.get_recieved(), "ß");
```
```j*s
var instance = new sixtyfps.TestCase();
assert(!instance.input1_focused);
assert(!instance.input2_focused);
instance.send_mouse_click(150., 100.);
assert(instance.input1_focused);
assert(!instance.input2_focused);
instance.send_keyboard_string_sequence("Only for field 1");
assert.equal(instance.input1_text, "Only for field 1");
assert.equal(instance.input2_text, "");
instance.send_mouse_click(150., 300.);
assert(!instance.input1_focused);
assert(instance.input2_focused);
instance.send_keyboard_string_sequence("Only for field 2");
assert.equal(instance.input1_text, "Only for field 1");
assert.equal(instance.input2_text, "Only for field 2");
```
*/

View file

@ -0,0 +1,96 @@
/* LICENSE BEGIN
This file is part of the SixtyFPS Project -- https://sixtyfps.io
Copyright (c) 2020 Olivier Goffart <olivier.goffart@sixtyfps.io>
Copyright (c) 2020 Simon Hausmann <simon.hausmann@sixtyfps.io>
SPDX-License-Identifier: GPL-3.0-only
This file is also available under commercial licensing terms.
Please contact info@sixtyfps.io for more information.
LICENSE END */
TestCase := Window {
width: 100phx;
height: 100phx;
FocusScope {
key-pressed(event) => {
r1 += event.text;
return event.text == "a" ? accept : reject;
}
FocusScope {
key-pressed(event) => {
r2 += event.text;
return event.text == "b" ? accept : reject;
}
Rectangle {
FocusScope {
key-pressed(event) => {
r3 += event.text;
return event.text == "c" ? accept : reject;
}
if (toggle) : FocusScope {
key-pressed(event) => {
r4 += event.text;
return event.text == "d" ? accept : reject;
}
FocusScope {
key-pressed(event) => {
r5 += event.text;
return event.text == "e" ? accept : reject;
}
TouchArea {
clicked => {
parent.focus();
}
}
}
}
}
}
}
}
property<bool> toggle: true;
property<string> r1;
property<string> r2;
property<string> r3;
property<string> r4;
property<string> r5;
}
/*
```rust
let instance = TestCase::new();
sixtyfps::testing::send_mouse_click(&instance, 50., 50.);
sixtyfps::testing::send_keyboard_string_sequence(&instance, "__abcdefghij__");
assert_eq!(instance.get_r1(), "__afghij__");
assert_eq!(instance.get_r2(), "__abfghij__");
assert_eq!(instance.get_r3(), "__abcfghij__");
assert_eq!(instance.get_r4(), "__abcdfghij__");
assert_eq!(instance.get_r5(), "__abcdefghij__");
```
```cpp
auto handle = TestCase::create();
const TestCase &instance = *handle;
sixtyfps::testing::send_mouse_click(&handle, 50., 50.);
sixtyfps::testing::send_keyboard_string_sequence(&instance, "__abcdefghij__");
assert_eq(instance.get_r1(), "__afghij__");
assert_eq(instance.get_r2(), "__abfghij__");
assert_eq(instance.get_r3(), "__abcfghij__");
assert_eq(instance.get_r4(), "__abcdfghij__");
assert_eq(instance.get_r5(), "__abcdefghij__");
```
```js
var instance = new sixtyfps.TestCase();
instance.send_mouse_click(50., 50.);
instance.send_keyboard_string_sequence("__abcdefghij__");
assert.equal(instance.r1, "__afghij__");
assert.equal(instance.r2, "__abfghij__");
assert.equal(instance.r3, "__abcfghij__");
assert.equal(instance.r4, "__abcdfghij__");
assert.equal(instance.r5, "__abcdefghij__");
```
*/