PopopWindow: Fix close-policy and close-on-click when inheriting

This commit is contained in:
Olivier Goffart 2024-12-07 00:37:21 +01:00
parent 72b11af08c
commit 0f15a26f35
3 changed files with 701 additions and 87 deletions

View file

@ -3,14 +3,17 @@
//! Passe that transform the PopupWindow element into a component
use crate::diagnostics::BuildDiagnostics;
use crate::expression_tree::{Expression, NamedReference};
use crate::diagnostics::{BuildDiagnostics, SourceLocation};
use crate::expression_tree::{BindingExpression, Expression, NamedReference};
use crate::langtype::{ElementType, EnumerationValue, Type};
use crate::object_tree::*;
use crate::typeregister::TypeRegister;
use smol_str::{format_smolstr, SmolStr};
use std::rc::{Rc, Weak};
const CLOSE_ON_CLICK: &str = "close-on-click";
const CLOSE_POLICY: &str = "close-policy";
pub fn lower_popups(
component: &Rc<Component>,
type_register: &TypeRegister,
@ -42,6 +45,28 @@ fn lower_popup_window(
window_type: &ElementType,
diag: &mut BuildDiagnostics,
) {
if let Some(binding) = popup_window_element.borrow().bindings.get(CLOSE_ON_CLICK) {
if popup_window_element.borrow().bindings.get(CLOSE_POLICY).is_some() {
diag.push_error(
"close-policy and close-on-click cannot be set at the same time".into(),
&binding.borrow().span,
);
} else {
diag.push_property_deprecation_warning(
CLOSE_ON_CLICK,
CLOSE_POLICY,
&binding.borrow().span,
);
if !matches!(binding.borrow().expression, Expression::BoolLiteral(_)) {
report_const_error(CLOSE_ON_CLICK, &binding.borrow().span, diag);
}
}
} else if let Some(binding) = popup_window_element.borrow().bindings.get(CLOSE_POLICY) {
if !matches!(binding.borrow().expression, Expression::EnumerationValue(_)) {
report_const_error(CLOSE_POLICY, &binding.borrow().span, diag);
}
}
let parent_component = popup_window_element.borrow().enclosing_component.upgrade().unwrap();
let parent_element = match parent_element {
None => {
@ -76,103 +101,73 @@ fn lower_popup_window(
popup_window_element.borrow_mut().base_type = window_type.clone();
}
const CLOSE_ON_CLICK: &str = "close-on-click";
let close_on_click = popup_window_element.borrow_mut().bindings.remove(CLOSE_ON_CLICK);
// Take a reference to the close on click
let close_on_click = close_on_click
.map(|b| {
diag.push_property_deprecation_warning(
"close-on-click",
"close-policy",
&b.borrow().span,
);
let b = b.into_inner();
(b.expression, b.span)
let map_close_on_click_value = |b: &BindingExpression| {
let Expression::BoolLiteral(v) = b.expression else {
assert!(diag.has_errors());
return None;
};
let enum_ty = crate::typeregister::BUILTIN.with(|e| e.enums.PopupClosePolicy.clone());
let s = if v { "close-on-click" } else { "no-auto-close" };
Some(EnumerationValue {
value: enum_ty.values.iter().position(|v| v == s).unwrap(),
enumeration: enum_ty,
})
.or_else(|| {
let mut base = popup_window_element.borrow().base_type.clone();
while let ElementType::Component(b) = base {
base = b.root_element.borrow().base_type.clone();
if let Some(binding) = b.root_element.borrow().bindings.get(CLOSE_ON_CLICK) {
let b = binding.borrow();
return Some((b.expression.clone(), b.span.clone()));
}
};
let close_policy =
popup_window_element.borrow_mut().bindings.remove(CLOSE_POLICY).and_then(|b| {
let b = b.into_inner();
if let Expression::EnumerationValue(v) = b.expression {
Some(v)
} else {
assert!(diag.has_errors());
None
}
None
});
const CLOSE_POLICY: &str = "close-policy";
let close_policy = popup_window_element.borrow_mut().bindings.remove(CLOSE_POLICY);
// Take a reference to the close policy
let close_policy = close_policy
.map(|b| {
let b = b.into_inner();
(b.expression, b.span)
.or_else(|| {
popup_window_element
.borrow_mut()
.bindings
.remove(CLOSE_ON_CLICK)
.and_then(|b| map_close_on_click_value(&b.borrow()))
})
.or_else(|| {
// check bases
let mut base = popup_window_element.borrow().base_type.clone();
while let ElementType::Component(b) = base {
base = b.root_element.borrow().base_type.clone();
if let Some(binding) = b.root_element.borrow().bindings.get(CLOSE_POLICY) {
let b = binding.borrow();
return Some((b.expression.clone(), b.span.clone()));
let base_policy = b
.root_element
.borrow()
.bindings
.get(CLOSE_POLICY)
.and_then(|b| {
let b = b.borrow();
if let Expression::EnumerationValue(v) = &b.expression {
return Some(v.clone());
}
assert!(diag.has_errors());
None
})
.or_else(|| {
b.root_element
.borrow()
.bindings
.get(CLOSE_ON_CLICK)
.and_then(|b| map_close_on_click_value(&b.borrow()))
});
if let Some(base_policy) = base_policy {
return Some(base_policy);
}
base = b.root_element.borrow().base_type.clone();
}
None
})
.unwrap_or_else(|| EnumerationValue {
value: 0,
enumeration: crate::typeregister::BUILTIN.with(|e| e.enums.PopupClosePolicy.clone()),
});
if close_policy.is_some() && close_on_click.is_some() {
diag.push_error(
"close-policy and close-on-click cannot be set at the same time".into(),
&close_on_click.unwrap().1,
);
return;
}
let close_on_click = match close_on_click {
Some((expr, location)) => match expr {
Expression::BoolLiteral(value) => Some(value),
_ => {
diag.push_error(
"The close-on-click property only supports constants at the moment".into(),
&location,
);
return;
}
},
None => None,
};
let close_policy = match close_policy {
Some((expr, location)) => match expr {
Expression::EnumerationValue(value) => value,
_ => {
diag.push_error(
"The close-policy property only supports constants at the moment".into(),
&location,
);
return;
}
},
None => {
let enum_ty = crate::typeregister::BUILTIN.with(|e| e.enums.PopupClosePolicy.clone());
let mut value = String::from("close-on-click");
if let Some(close_on_click) = close_on_click {
if !close_on_click {
value = "no-auto-close".into()
}
}
EnumerationValue {
value: enum_ty.values.iter().position(|v| v == value.as_str()).unwrap(),
enumeration: enum_ty,
}
}
};
let popup_comp = Rc::new(Component {
root_element: popup_window_element.clone(),
parent_element: Rc::downgrade(parent_element),
@ -235,6 +230,10 @@ fn lower_popup_window(
});
}
fn report_const_error(prop: &str, span: &Option<SourceLocation>, diag: &mut BuildDiagnostics) {
diag.push_error(format!("The {} property only supports constants at the moment", prop), span);
}
fn check_element(
element: &ElementRc,
popup_comp: &Weak<Component>,

View file

@ -1,6 +1,35 @@
// Copyright © SixtyFPS GmbH <info@slint.dev>
// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0
component DeprecatedDerives inherits PopupWindow {
close-on-click: false;
// ^warning{The property 'close-on-click' has been deprecated. Please use 'close-policy' instead}
}
component Derives inherits PopupWindow {
close-policy: close-on-click-outside;
}
component D1 inherits PopupWindow {
close-on-click: false;
// ^error{close-policy and close-on-click cannot be set at the same }
close-policy: close-on-click-outside;
}
component D2 inherits PopupWindow {
close-on-click: (!false);
// ^warning{The property 'close-on-click' has been deprecated. Please use 'close-policy' instead}
// ^^error{The close-on-click property only supports constants at the moment}
}
component D3 inherits PopupWindow {
in property <PopupClosePolicy> pp;
close-policy: pp;
// ^error{The close-policy property only supports constants at the moment}
}
export component Bar {
in property <bool> external;
@ -10,13 +39,51 @@ export component Bar {
init => {
xx.close-on-click = true;
// ^error{The property must be known at compile time and cannot be changed at runtime}
xx.close-policy = PopupClosePolicy.close-on-click;
// ^error{The property must be known at compile time and cannot be changed at runtime}
}
}
PopupWindow {
close-on-click: root.external;
// ^warning{The property 'close-on-click' has been deprecated. Please use 'close-policy' instead}
// ^warning{The property 'close-on-click' has been deprecated. Please use 'close-policy' instead}
// ^^error{The close-on-click property only supports constants at the moment}
}
Rectangle {
PopupWindow {
close-policy: close-on-click-outside;
close-on-click: true;
// ^error{close-policy and close-on-click cannot be set at the same time}
}
DeprecatedDerives {
close-policy: close-on-click-outside;
}
Derives {
close-on-click: false;
// ^warning{The property 'close-on-click' has been deprecated. Please use 'close-policy' instead}
}
DeprecatedDerives {
close-on-click: true;
// ^warning{The property 'close-on-click' has been deprecated. Please use 'close-policy' instead}
}
DeprecatedDerives {
close-on-click: !true;
// ^warning{The property 'close-on-click' has been deprecated. Please use 'close-policy' instead}
// ^^error{The close-on-click property only supports constants at the moment}
}
D1{}
D2{}
D3{}
D1{}
D2{}
D3{ close-on-click: true; }
// ^warning{The property 'close-on-click' has been deprecated. Please use 'close-policy' instead}
}
}

View file

@ -0,0 +1,548 @@
// Copyright © SixtyFPS GmbH <info@slint.dev>
// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0
component DerivesNoClose inherits PopupWindow {
close-policy: no-auto-close;
}
component DerivesNoCloseLegacy inherits PopupWindow {
close-on-click: false;
}
component DerivesAutoClose inherits DerivesNoClose {
close-on-click: true;
}
component DerivesDerivesNoClose inherits DerivesNoClose {
}
export component TestCase {
width: 300px;
height: 300px;
in-out property <bool> popup-created;
in-out property <int> click-count;
in-out property <int> popup-selector: 0;
in-out property <int> popup-clicked;
out property <length> last-underneath-mouse-x: ta.mouse-x;
out property <length> last-underneath-mouse-y: ta.mouse-y;
callback do-close;
do-close => {
close-from-outside.close();
}
default-popup := DerivesAutoClose {
x: 10px;
y: 10px;
width: parent.width - 20px;
height: parent.height - 20px;
Text {
text: "I'm a default";
}
init => {
root.popup-created = true;
}
TouchArea {
width: 7px; x: 0px;
clicked => {
popup-clicked += 1;
}
}
}
self-closing-popup := DerivesDerivesNoClose {
x: 10px;
y: 10px;
width: parent.width - 20px;
height: parent.height - 20px;
Text {
text: "I'm a self-closing popup";
}
TouchArea {
clicked => {
self-closing-popup.close();
}
}
init => {
root.popup-created = true;
}
}
close-from-outside := DerivesAutoClose {
close-policy: no-auto-close;
x: 10px;
y: 10px;
width: parent.width - 20px;
height: parent.height - 20px;
Text {
text: "I'm a popup that only close from outside";
}
TouchArea {
clicked => {
popup-clicked += 1000;
}
}
init => {
root.popup-created = true;
}
}
close-click-outside := DerivesNoCloseLegacy {
x: 10px;
y: 10px;
width: parent.width - 20px;
height: parent.height - 20px;
close-policy: close-on-click-outside;
Text {
text: "I close on outside click";
}
init => {
root.popup-created = true;
}
TouchArea {
width: 7px; x: 0px;
clicked => {
popup-clicked += 2;
}
}
}
ta := TouchArea {
clicked => {
root.click-count = root.click-count + 1;
if (root.popup-selector == 0) {
root.popup-selector = 4;
default-popup.show();
} else if (root.popup-selector == 1) {
root.popup-selector = 4;
self-closing-popup.show();
} else if (root.popup-selector == 2) {
root.popup-selector = 4;
close-from-outside.show();
} else if (root.popup-selector == 3) {
root.popup-selector = 4;
close-click-outside.show();
}
}
}
}
/*
```rust
use slint::{platform::WindowEvent, platform::PointerEventButton, LogicalPosition};
let instance = TestCase::new().unwrap();
assert_eq!(instance.get_click_count(), 0);
assert_eq!(instance.get_popup_created(), false);
// --------- Default popup
instance.set_popup_selector(0);
instance.set_popup_created(false);
instance.set_click_count(0);
slint_testing::send_mouse_click(&instance, 15., 15.);
assert_eq!(instance.get_click_count(), 1);
assert_eq!(instance.get_popup_created(), true);
assert_eq!(instance.get_popup_clicked(), 0);
// Click to close
slint_testing::send_mouse_click(&instance, 15., 15.);
assert_eq!(instance.get_click_count(), 1);
// Subsequent click to verify that it was closed
slint_testing::send_mouse_click(&instance, 15., 15.);
assert_eq!(instance.get_click_count(), 2);
assert_eq!(instance.get_popup_clicked(), 1);
// --------- Default popup but verify closed on press when outside
instance.set_popup_selector(0);
instance.set_popup_created(false);
instance.set_click_count(0);
slint_testing::send_mouse_click(&instance, 15., 15.);
assert_eq!(instance.get_last_underneath_mouse_x(), 15.);
assert_eq!(instance.get_last_underneath_mouse_y(), 15.);
assert_eq!(instance.get_click_count(), 1);
assert_eq!(instance.get_popup_created(), true);
assert_eq!(instance.get_popup_clicked(), 1);
// mouse grabbed, underneath won't notice
instance.window().dispatch_event(WindowEvent::PointerMoved { position: LogicalPosition::new(1.0, 1.0) });
assert_eq!(instance.get_last_underneath_mouse_x(), 15.);
assert_eq!(instance.get_last_underneath_mouse_y(), 15.);
// press should close
instance.window().dispatch_event(WindowEvent::PointerPressed { position: LogicalPosition::new(1.0, 1.0), button: PointerEventButton::Left });
// if it was closed, the underneath should receive the move event
instance.window().dispatch_event(WindowEvent::PointerMoved { position: LogicalPosition::new(12.0, 12.0) });
assert_eq!(instance.get_last_underneath_mouse_x(), 12.);
assert_eq!(instance.get_last_underneath_mouse_y(), 12.);
slint_testing::mock_elapsed_time(50);
instance.window().dispatch_event(WindowEvent::PointerReleased { position: LogicalPosition::new(12.0, 12.0), button: PointerEventButton::Left });
assert_eq!(instance.get_click_count(), 1);
// Subsequent click to verify that it was closed
slint_testing::send_mouse_click(&instance, 15., 15.);
assert_eq!(instance.get_click_count(), 2);
assert_eq!(instance.get_popup_clicked(), 1);
// --------- Popup with close-policy: no-auto-close
instance.set_popup_selector(1);
instance.set_popup_created(false);
instance.set_click_count(0);
slint_testing::send_mouse_click(&instance, 15., 15.);
assert_eq!(instance.get_click_count(), 1);
assert_eq!(instance.get_popup_created(), true);
assert_eq!(instance.get_popup_clicked(), 1);
// Click outside, nothing happens
slint_testing::send_mouse_click(&instance, 1., 1.);
assert_eq!(instance.get_click_count(), 1);
// Click outside again, nothing happens
slint_testing::send_mouse_click(&instance, 295., 295.);
assert_eq!(instance.get_click_count(), 1);
assert_eq!(instance.get_popup_clicked(), 1);
// Click on the popup, it's registered and the custom TouchArea calls close()
slint_testing::send_mouse_click(&instance, 15., 15.);
assert_eq!(instance.get_click_count(), 1);
// Subsequent click to verify that it was closed
slint_testing::send_mouse_click(&instance, 15., 15.);
assert_eq!(instance.get_click_count(), 2);
assert_eq!(instance.get_popup_clicked(), 1);
// --------- Popup with close-policy: no-auto-close closed externally
instance.set_popup_selector(2);
instance.set_popup_created(false);
instance.set_click_count(0);
slint_testing::send_mouse_click(&instance, 15., 15.);
assert_eq!(instance.get_click_count(), 1);
assert_eq!(instance.get_popup_created(), true);
assert_eq!(instance.get_popup_clicked(), 1);
// Press esc nothing happen
slint_testing::send_keyboard_string_sequence(&instance, "\u{001b}");
slint_testing::send_mouse_click(&instance, 15., 15.);
assert_eq!(instance.get_click_count(), 1);
assert_eq!(instance.get_popup_clicked(), 1001);
// Click outside, nothing happens
slint_testing::send_mouse_click(&instance, 1., 1.);
assert_eq!(instance.get_click_count(), 1);
assert_eq!(instance.get_popup_clicked(), 1001);
// Click on the popup, it's registered but nothing is done
slint_testing::send_mouse_click(&instance, 15., 15.);
assert_eq!(instance.get_click_count(), 1);
assert_eq!(instance.get_popup_clicked(), 2001);
// Click again to verify that it was _not_ closed
slint_testing::send_mouse_click(&instance, 15., 15.);
assert_eq!(instance.get_click_count(), 1);
assert_eq!(instance.get_popup_clicked(), 3001);
// Close manually and verify that subsequent click is passed through
instance.invoke_do_close();
slint_testing::send_mouse_click(&instance, 5., 5.);
assert_eq!(instance.get_click_count(), 2);
instance.invoke_do_close();
slint_testing::send_mouse_click(&instance, 15., 15.);
assert_eq!(instance.get_click_count(), 3);
assert_eq!(instance.get_popup_clicked(), 3001);
// --------- Close outside click popup
instance.set_popup_selector(3);
instance.set_popup_created(false);
instance.set_click_count(0);
slint_testing::send_mouse_click(&instance, 15., 15.);
assert_eq!(instance.get_click_count(), 1);
assert_eq!(instance.get_popup_created(), true);
assert_eq!(instance.get_popup_clicked(), 3001);
// click inside
slint_testing::send_mouse_click(&instance, 15., 15.);
assert_eq!(instance.get_popup_clicked(), 3003);
// Click outside to close
slint_testing::send_mouse_click(&instance, 5., 5.);
assert_eq!(instance.get_click_count(), 1);
// Subsequent click to verify that it was closed
slint_testing::send_mouse_click(&instance, 5., 5.);
assert_eq!(instance.get_click_count(), 2);
assert_eq!(instance.get_popup_clicked(), 3003);
// --------- Close outside click popup by esc
instance.set_popup_selector(3);
instance.set_click_count(0);
slint_testing::send_mouse_click(&instance, 5., 5.);
assert_eq!(instance.get_click_count(), 1);
// click inside
slint_testing::send_mouse_click(&instance, 15., 15.);
assert_eq!(instance.get_popup_clicked(), 3005);
// close by esc
slint_testing::send_keyboard_string_sequence(&instance, "\u{001b}");
slint_testing::send_mouse_click(&instance, 15., 15.);
assert_eq!(instance.get_click_count(), 2);
```
```cpp
auto handle = TestCase::create();
const TestCase &instance = *handle;
assert_eq(instance.get_click_count(), 0);
assert_eq(instance.get_popup_created(), false);
// --------- Default popup
instance.set_popup_selector(0);
instance.set_popup_created(false);
instance.set_click_count(0);
slint_testing::send_mouse_click(&instance, 15., 15.);
assert_eq(instance.get_click_count(), 1);
assert_eq(instance.get_popup_created(), true);
assert_eq(instance.get_popup_clicked(), 0);
// Click to close
slint_testing::send_mouse_click(&instance, 15., 15.);
assert_eq(instance.get_click_count(), 1);
// Subsequent click to verify that it was closed
slint_testing::send_mouse_click(&instance, 15., 15.);
assert_eq(instance.get_click_count(), 2);
assert_eq(instance.get_popup_clicked(), 1);
// --------- Default popup but verify closed on press when outside
instance.set_popup_selector(0);
instance.set_popup_created(false);
instance.set_click_count(0);
slint_testing::send_mouse_click(&instance, 15., 15.);
assert_eq(instance.get_last_underneath_mouse_x(), 15.);
assert_eq(instance.get_last_underneath_mouse_y(), 15.);
assert_eq(instance.get_click_count(), 1);
assert_eq(instance.get_popup_created(), true);
assert_eq(instance.get_popup_clicked(), 1);
// mouse grabbed, underneath won't notice
instance.window().dispatch_pointer_move_event(slint::LogicalPosition({1.0, 1.0}));
assert_eq(instance.get_last_underneath_mouse_x(), 15.);
assert_eq(instance.get_last_underneath_mouse_y(), 15.);
// press should close
instance.window().dispatch_pointer_press_event(slint::LogicalPosition({1.0, 1.0}), slint::PointerEventButton::Left);
// if it was closed, the underneath should receive the move event
instance.window().dispatch_pointer_move_event(slint::LogicalPosition({12.0, 12.0}));
assert_eq(instance.get_last_underneath_mouse_x(), 12.);
assert_eq(instance.get_last_underneath_mouse_y(), 12.);
slint_testing::mock_elapsed_time(50);
instance.window().dispatch_pointer_release_event(slint::LogicalPosition({12.0, 12.0}), slint::PointerEventButton::Left);
assert_eq(instance.get_click_count(), 1);
// Subsequent click to verify that it was closed
slint_testing::send_mouse_click(&instance, 15., 15.);
assert_eq(instance.get_click_count(), 2);
assert_eq(instance.get_popup_clicked(), 1);
// --------- Popup with close-policy: no-auto-close
instance.set_popup_selector(1);
instance.set_popup_created(false);
instance.set_click_count(0);
slint_testing::send_mouse_click(&instance, 15., 15.);
assert_eq(instance.get_click_count(), 1);
assert_eq(instance.get_popup_created(), true);
assert_eq(instance.get_popup_clicked(), 1);
// Click outside, nothing happens
slint_testing::send_mouse_click(&instance, 1., 1.);
assert_eq(instance.get_click_count(), 1);
// Click outside again, nothing happens
slint_testing::send_mouse_click(&instance, 295., 295.);
assert_eq(instance.get_click_count(), 1);
assert_eq(instance.get_popup_clicked(), 1);
// Click on the popup, it's registered and the custom TouchArea calls close()
slint_testing::send_mouse_click(&instance, 15., 15.);
assert_eq(instance.get_click_count(), 1);
// Subsequent click to verify that it was closed
slint_testing::send_mouse_click(&instance, 15., 15.);
assert_eq(instance.get_click_count(), 2);
assert_eq(instance.get_popup_clicked(), 1);
// --------- Popup with close-policy: no-auto-close closed externally
instance.set_popup_selector(2);
instance.set_popup_created(false);
instance.set_click_count(0);
slint_testing::send_mouse_click(&instance, 15., 15.);
assert_eq(instance.get_click_count(), 1);
assert_eq(instance.get_popup_created(), true);
assert_eq(instance.get_popup_clicked(), 1);
// Click outside, nothing happens
slint_testing::send_mouse_click(&instance, 1., 1.);
assert_eq(instance.get_click_count(), 1);
assert_eq(instance.get_popup_clicked(), 1);
// Click on the popup, it's registered but nothing is done
slint_testing::send_mouse_click(&instance, 15., 15.);
assert_eq(instance.get_click_count(), 1);
assert_eq(instance.get_popup_clicked(), 1001);
// Click again to verify that it was _not_ closed
slint_testing::send_mouse_click(&instance, 15., 15.);
assert_eq(instance.get_click_count(), 1);
assert_eq(instance.get_popup_clicked(), 2001);
// Close manually and verify that subsequent click is passed through
instance.invoke_do_close();
slint_testing::send_mouse_click(&instance, 15., 15.);
assert_eq(instance.get_click_count(), 2);
instance.invoke_do_close();
slint_testing::send_mouse_click(&instance, 15., 15.);
assert_eq(instance.get_click_count(), 3);
assert_eq(instance.get_popup_clicked(), 2001);
// --------- Close outside click popup
instance.set_popup_selector(3);
instance.set_popup_created(false);
instance.set_click_count(0);
slint_testing::send_mouse_click(&instance, 15., 15.);
assert_eq(instance.get_click_count(), 1);
assert_eq(instance.get_popup_created(), true);
assert_eq(instance.get_popup_clicked(), 2001);
// click inside
slint_testing::send_mouse_click(&instance, 15., 15.);
assert_eq(instance.get_popup_clicked(), 2003);
// Click outside to close
slint_testing::send_mouse_click(&instance, 5., 5.);
assert_eq(instance.get_click_count(), 1);
// Subsequent click to verify that it was closed
slint_testing::send_mouse_click(&instance, 5., 5.);
assert_eq(instance.get_click_count(), 2);
assert_eq(instance.get_popup_clicked(), 2003);
// --------- Close outside click popup by esc
instance.set_popup_selector(3);
instance.set_click_count(0);
slint_testing::send_mouse_click(&instance, 5., 5.);
assert_eq(instance.get_click_count(), 1);
// click inside
slint_testing::send_mouse_click(&instance, 15., 15.);
assert_eq(instance.get_popup_clicked(), 2005);
// close by esc
slint_testing::send_keyboard_string_sequence(&instance, "\u001b");
slint_testing::send_mouse_click(&instance, 15., 15.);
assert_eq(instance.get_click_count(), 2);
```
```disable-because-nodejs-runs-with-qt-and-send-mouse-click-wont-send-to-popup-qwindow
var instance = new slint.TestCase({});
assert.equal(instance.click_count, 0);
assert.equal(instance.popup_created, false);
instance.popup_selector = 0;
instance.popup_created = false;
instance.click_count = 0;
slintlib.private_api.send_mouse_click(instance, 15., 15.);
assert.equal(instance.click_count, 1);
assert.equal(instance.popup_created, true);
slintlib.private_api.send_mouse_click(instance, 15., 15.);
assert.equal(instance.click_count, 1);
slintlib.private_api.send_mouse_click(instance, 15., 15.);
assert.equal(instance.click_count, 2);
instance.popup_selector = 1;
instance.popup_created = false;
instance.click_count = 0;
slintlib.private_api.send_mouse_click(instance, 15., 15.);
assert.equal(instance.click_count, 1);
assert.equal(instance.popup_created, true);
slintlib.private_api.send_mouse_click(instance, 1., 1.);
assert.equal(instance.click_count, 1);
slintlib.private_api.send_mouse_click(instance, 15., 15.);
assert.equal(instance.click_count, 1);
slintlib.private_api.send_mouse_click(instance, 15., 15.);
assert.equal(instance.click_count, 2);
instance.popup_selector = 2;
instance.popup_created = false;
instance.click_count = 0;
slintlib.private_api.send_mouse_click(instance, 15., 15.);
assert.equal(instance.click_count, 1);
assert.equal(instance.popup_created, true);
slintlib.private_api.send_mouse_click(instance, 15., 15.);
assert.equal(instance.click_count, 1);
slintlib.private_api.send_mouse_click(instance, 15., 15.);
assert.equal(instance.click_count, 1);
instance.do_close();
slintlib.private_api.send_mouse_click(instance, 15., 15.);
assert.equal(instance.click_count, 2);
instance.do_close();
slintlib.private_api.send_mouse_click(instance, 15., 15.);
assert.equal(instance.click_count, 3);
// --------- Close outside click popup
instance.set_popup_selector(3);
instance.set_popup_created(false);
instance.set_click_count(0);
slintlib.private_api.send_mouse_click(instance, 15., 15.);
assert.equal(instance.get_click_count(), 1);
assert.equal(instance.get_popup_created(), true);
assert.equal(instance.get_popup_clicked(), 2001);
// click inside
slintlib.private_api.send_mouse_click(instance, 15., 15.);
assert.equal(instance.get_popup_clicked(), 2003);
// Click outside to close
slintlib.private_api.send_mouse_click(instance, 5., 5.);
assert.equal(instance.get_click_count(), 1);
// Subsequent click to verify that it was closed
slintlib.private_api.send_mouse_click(instance, 15., 15.);
assert.equal(instance.get_click_count(), 2);
assert.equal(instance.get_popup_clicked(), 2003);
// --------- Close outside click popup by esc
instance.set_popup_selector(3);
instance.set_click_count(0);
slintlib.private_api.send_mouse_click(instance, 5., 5.);
assert.equal(instance.get_click_count(), 1);
// click inside
slintlib.private_api.send_mouse_click(instance, 15., 15.);
assert.equal(instance.get_popup_clicked(), 2005);
// close by esc
slintlib.private_api.send_keyboard_string_sequence(instance, "\u{001b}");
slintlib.private_api.send_mouse_click(instance, 15., 15.);
assert.equal(instance.get_click_count(), 2);
```
*/