mirror of
https://github.com/slint-ui/slint.git
synced 2025-10-02 06:41:14 +00:00
PopupWindow: added close-policy property (#6614)
* Update api/cpp/include/slint_window.h Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> * Update docs/reference/src/language/builtins/elements.md Co-authored-by: Simon Hausmann <simon.hausmann@slint.dev> * Update internal/core/window.rs Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> * Update internal/interpreter/eval.rs Co-authored-by: Simon Hausmann <simon.hausmann@slint.dev> * Update internal/backends/qt/qt_window.rs Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> * Update internal/interpreter/dynamic_item_tree.rs Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> * Update internal/compiler/passes/materialize_fake_properties.rs Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> --------- Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: Simon Hausmann <simon.hausmann@slint.dev>
This commit is contained in:
parent
0bf924cf0d
commit
14c7910d49
33 changed files with 657 additions and 61 deletions
|
@ -106,13 +106,14 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename Component, typename Parent, typename PosGetter>
|
template<typename Component, typename Parent, typename PosGetter>
|
||||||
void show_popup(const Parent *parent_component, PosGetter pos, bool close_on_click,
|
void show_popup(const Parent *parent_component, PosGetter pos,
|
||||||
|
cbindgen_private::PopupClosePolicy close_policy,
|
||||||
cbindgen_private::ItemRc parent_item) const
|
cbindgen_private::ItemRc parent_item) const
|
||||||
{
|
{
|
||||||
auto popup = Component::create(parent_component);
|
auto popup = Component::create(parent_component);
|
||||||
cbindgen_private::Point p = pos(popup);
|
cbindgen_private::Point p = pos(popup);
|
||||||
auto popup_dyn = popup.into_dyn();
|
auto popup_dyn = popup.into_dyn();
|
||||||
cbindgen_private::slint_windowrc_show_popup(&inner, &popup_dyn, p, close_on_click,
|
cbindgen_private::slint_windowrc_show_popup(&inner, &popup_dyn, p, close_policy,
|
||||||
&parent_item);
|
&parent_item);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -606,13 +606,13 @@ Note: It isn't allowed to access properties of elements within the popup from ou
|
||||||
|
|
||||||
### Properties
|
### Properties
|
||||||
|
|
||||||
- **`close-on-click`** (_in_ _bool_): By default, a PopupWindow closes when the user clicks. Set this
|
- **`close-policy`** (_in_ _enum [`PopupClosePolicy`](../builtins/enums.md#closepolicy)_): By default, a PopupWindow closes when the user clicks (`close-on-click`). Set this
|
||||||
to false to prevent that behavior and close it manually using the `close()` function. (default value: true)
|
to `off` to prevent that behavior and close it manually using the `close()` function. Set to `close-on-click-outside` to close the PopupWindow when the user clicks outside of the popup.
|
||||||
|
|
||||||
### Functions
|
### Functions
|
||||||
|
|
||||||
- **`show()`** Show the popup on the screen.
|
- **`show()`** Show the popup on the screen.
|
||||||
- **`close()`** Closes the popup. Use this if you set the `close-on-click` property to false.
|
- **`close()`** Closes the popup. Use this if you set the `close-policy` property to `no-auto-close`.
|
||||||
|
|
||||||
### Example
|
### Example
|
||||||
|
|
||||||
|
|
|
@ -33,7 +33,7 @@ export component Example inherits Window {
|
||||||
date-picker := DatePickerPopup {
|
date-picker := DatePickerPopup {
|
||||||
width: 360px;
|
width: 360px;
|
||||||
height: 524px;
|
height: 524px;
|
||||||
close-on-click: false;
|
close-policy: PopupClosePolicy.no-auto-close;
|
||||||
|
|
||||||
accepted(date) => {
|
accepted(date) => {
|
||||||
date-picker.close();
|
date-picker.close();
|
||||||
|
|
|
@ -18,7 +18,7 @@ use i_slint_core::item_rendering::{
|
||||||
use i_slint_core::item_tree::{ItemTreeRc, ItemTreeRef};
|
use i_slint_core::item_tree::{ItemTreeRc, ItemTreeRef};
|
||||||
use i_slint_core::items::{
|
use i_slint_core::items::{
|
||||||
self, ColorScheme, FillRule, ImageRendering, ItemRc, ItemRef, Layer, MouseCursor, Opacity,
|
self, ColorScheme, FillRule, ImageRendering, ItemRc, ItemRef, Layer, MouseCursor, Opacity,
|
||||||
PointerEventButton, RenderingResult, TextOverflow, TextStrokeStyle, TextWrap,
|
PointerEventButton, PopupClosePolicy, RenderingResult, TextOverflow, TextStrokeStyle, TextWrap,
|
||||||
};
|
};
|
||||||
use i_slint_core::layout::Orientation;
|
use i_slint_core::layout::Orientation;
|
||||||
use i_slint_core::lengths::{
|
use i_slint_core::lengths::{
|
||||||
|
@ -160,10 +160,12 @@ cpp! {{
|
||||||
void *parent_of_popup_to_close = nullptr;
|
void *parent_of_popup_to_close = nullptr;
|
||||||
if (auto p = dynamic_cast<const SlintWidget*>(parent())) {
|
if (auto p = dynamic_cast<const SlintWidget*>(parent())) {
|
||||||
void *parent_window = p->rust_window;
|
void *parent_window = p->rust_window;
|
||||||
bool close_popup = rust!(Slint_mouseReleaseEventPopup [parent_window: &QtWindow as "void*"] -> bool as "bool" {
|
bool close_on_click = rust!(Slint_mouseReleaseEventPopup [parent_window: &QtWindow as "void*"] -> bool as "bool" {
|
||||||
parent_window.close_popup_on_click()
|
let close_policy = parent_window.close_policy();
|
||||||
|
|
||||||
|
close_policy == PopupClosePolicy::CloseOnClick || close_policy == PopupClosePolicy::CloseOnClickOutside
|
||||||
});
|
});
|
||||||
if (close_popup) {
|
if (close_on_click) {
|
||||||
parent_of_popup_to_close = parent_window;
|
parent_of_popup_to_close = parent_window;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1745,8 +1747,8 @@ impl QtWindow {
|
||||||
WindowInner::from_pub(&self.window).close_popup();
|
WindowInner::from_pub(&self.window).close_popup();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn close_popup_on_click(&self) -> bool {
|
fn close_policy(&self) -> PopupClosePolicy {
|
||||||
WindowInner::from_pub(&self.window).close_popup_on_click()
|
WindowInner::from_pub(&self.window).close_policy()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn window_state_event(&self) {
|
fn window_state_event(&self) {
|
||||||
|
|
|
@ -431,6 +431,18 @@ macro_rules! for_each_enums {
|
||||||
/// Scrollbar always visible
|
/// Scrollbar always visible
|
||||||
AlwaysOn,
|
AlwaysOn,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// This enum describes the close behaviour of [`PopupWindow`](elements.md#popupwindow)
|
||||||
|
enum PopupClosePolicy {
|
||||||
|
/// Closes the `PopupWindow` when user clicks.
|
||||||
|
CloseOnClick,
|
||||||
|
|
||||||
|
/// Closed the `PopupWindow` when user clicks outside of the popup.
|
||||||
|
CloseOnClickOutside,
|
||||||
|
|
||||||
|
/// Does not close the `PopupWindow` automatically when user clicks
|
||||||
|
NoAutoClose,
|
||||||
|
}
|
||||||
];
|
];
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -417,7 +417,8 @@ export component PopupWindow {
|
||||||
in property <length> anchor_y;
|
in property <length> anchor_y;
|
||||||
in property <length> anchor_height;
|
in property <length> anchor_height;
|
||||||
in property <length> anchor_width;*/
|
in property <length> anchor_width;*/
|
||||||
in property <bool> close-on-click: true; // constexpr hardcoded in typeregister.rs
|
in property <bool> close-on-click;
|
||||||
|
in property <PopupClosePolicy> close-policy; // constexpr hardcoded in typeregister.rs
|
||||||
//show() is hardcoded in typeregister.rs
|
//show() is hardcoded in typeregister.rs
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3560,7 +3560,7 @@ fn compile_builtin_function_call(
|
||||||
format!("{}.text_input_focused()", access_window_field(ctx))
|
format!("{}.text_input_focused()", access_window_field(ctx))
|
||||||
}
|
}
|
||||||
BuiltinFunction::ShowPopupWindow => {
|
BuiltinFunction::ShowPopupWindow => {
|
||||||
if let [llr::Expression::NumberLiteral(popup_index), close_on_click, llr::Expression::PropertyReference(parent_ref)] =
|
if let [llr::Expression::NumberLiteral(popup_index), close_policy, llr::Expression::PropertyReference(parent_ref)] =
|
||||||
arguments
|
arguments
|
||||||
{
|
{
|
||||||
let mut parent_ctx = ctx;
|
let mut parent_ctx = ctx;
|
||||||
|
@ -3586,9 +3586,9 @@ fn compile_builtin_function_call(
|
||||||
Some(ParentCtx::new(&ctx, None)),
|
Some(ParentCtx::new(&ctx, None)),
|
||||||
);
|
);
|
||||||
let position = compile_expression(&popup.position.borrow(), &popup_ctx);
|
let position = compile_expression(&popup.position.borrow(), &popup_ctx);
|
||||||
let close_on_click = compile_expression(close_on_click, ctx);
|
let close_policy = compile_expression(close_policy, ctx);
|
||||||
format!(
|
format!(
|
||||||
"{window}.show_popup<{popup_window_id}>({component_access}, [=](auto self) {{ return {position}; }}, {close_on_click}, {{ {parent_component} }})"
|
"{window}.show_popup<{popup_window_id}>({component_access}, [=](auto self) {{ return {position}; }}, {close_policy}, {{ {parent_component} }})"
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
panic!("internal error: invalid args to ShowPopupWindow {:?}", arguments)
|
panic!("internal error: invalid args to ShowPopupWindow {:?}", arguments)
|
||||||
|
|
|
@ -2605,7 +2605,7 @@ fn compile_builtin_function_call(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
BuiltinFunction::ShowPopupWindow => {
|
BuiltinFunction::ShowPopupWindow => {
|
||||||
if let [Expression::NumberLiteral(popup_index), close_on_click, Expression::PropertyReference(parent_ref)] =
|
if let [Expression::NumberLiteral(popup_index), close_policy, Expression::PropertyReference(parent_ref)] =
|
||||||
arguments
|
arguments
|
||||||
{
|
{
|
||||||
let mut parent_ctx = ctx;
|
let mut parent_ctx = ctx;
|
||||||
|
@ -2630,7 +2630,7 @@ fn compile_builtin_function_call(
|
||||||
);
|
);
|
||||||
let position = compile_expression(&popup.position.borrow(), &popup_ctx);
|
let position = compile_expression(&popup.position.borrow(), &popup_ctx);
|
||||||
|
|
||||||
let close_on_click = compile_expression(close_on_click, ctx);
|
let close_policy = compile_expression(close_policy, ctx);
|
||||||
let window_adapter_tokens = access_window_adapter_field(ctx);
|
let window_adapter_tokens = access_window_adapter_field(ctx);
|
||||||
quote!({
|
quote!({
|
||||||
let popup_instance = #popup_window_id::new(#component_access_tokens.self_weak.get().unwrap().clone()).unwrap();
|
let popup_instance = #popup_window_id::new(#component_access_tokens.self_weak.get().unwrap().clone()).unwrap();
|
||||||
|
@ -2640,7 +2640,7 @@ fn compile_builtin_function_call(
|
||||||
sp::WindowInner::from_pub(#window_adapter_tokens.window()).show_popup(
|
sp::WindowInner::from_pub(#window_adapter_tokens.window()).show_popup(
|
||||||
&sp::VRc::into_dyn(popup_instance.into()),
|
&sp::VRc::into_dyn(popup_instance.into()),
|
||||||
position,
|
position,
|
||||||
#close_on_click,
|
#close_policy,
|
||||||
#parent_component
|
#parent_component
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
|
@ -674,6 +674,7 @@ impl<'a, T> TypeResolutionContext for EvaluationContext<'a, T> {
|
||||||
for i in sub_component_path {
|
for i in sub_component_path {
|
||||||
sub_component = &sub_component.sub_components[*i].ty;
|
sub_component = &sub_component.sub_components[*i].ty;
|
||||||
}
|
}
|
||||||
|
|
||||||
sub_component.items[*item_index as usize].ty.lookup_property(prop_name).unwrap()
|
sub_component.items[*item_index as usize].ty.lookup_property(prop_name).unwrap()
|
||||||
}
|
}
|
||||||
PropertyReference::InParent { level, parent_reference } => {
|
PropertyReference::InParent { level, parent_reference } => {
|
||||||
|
|
|
@ -379,11 +379,12 @@ fn lower_show_popup(args: &[tree_Expression], ctx: &ExpressionContext) -> llr_Ex
|
||||||
&tree_Expression::ElementReference(Rc::downgrade(&popup.parent_element)),
|
&tree_Expression::ElementReference(Rc::downgrade(&popup.parent_element)),
|
||||||
ctx,
|
ctx,
|
||||||
);
|
);
|
||||||
|
|
||||||
llr_Expression::BuiltinFunctionCall {
|
llr_Expression::BuiltinFunctionCall {
|
||||||
function: BuiltinFunction::ShowPopupWindow,
|
function: BuiltinFunction::ShowPopupWindow,
|
||||||
arguments: vec![
|
arguments: vec![
|
||||||
llr_Expression::NumberLiteral(popup_index as _),
|
llr_Expression::NumberLiteral(popup_index as _),
|
||||||
llr_Expression::BoolLiteral(popup.close_on_click),
|
llr_Expression::EnumerationValue(popup.close_policy.clone()),
|
||||||
item_ref,
|
item_ref,
|
||||||
],
|
],
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,6 +9,7 @@
|
||||||
|
|
||||||
use crate::diagnostics::{BuildDiagnostics, SourceLocation, Spanned};
|
use crate::diagnostics::{BuildDiagnostics, SourceLocation, Spanned};
|
||||||
use crate::expression_tree::{self, BindingExpression, Expression, Unit};
|
use crate::expression_tree::{self, BindingExpression, Expression, Unit};
|
||||||
|
use crate::langtype::EnumerationValue;
|
||||||
use crate::langtype::{BuiltinElement, BuiltinPropertyDefault, Enumeration, NativeClass, Type};
|
use crate::langtype::{BuiltinElement, BuiltinPropertyDefault, Enumeration, NativeClass, Type};
|
||||||
use crate::langtype::{ElementType, PropertyLookupResult};
|
use crate::langtype::{ElementType, PropertyLookupResult};
|
||||||
use crate::layout::{LayoutConstraints, Orientation};
|
use crate::layout::{LayoutConstraints, Orientation};
|
||||||
|
@ -271,7 +272,7 @@ pub struct PopupWindow {
|
||||||
pub component: Rc<Component>,
|
pub component: Rc<Component>,
|
||||||
pub x: NamedReference,
|
pub x: NamedReference,
|
||||||
pub y: NamedReference,
|
pub y: NamedReference,
|
||||||
pub close_on_click: bool,
|
pub close_policy: EnumerationValue,
|
||||||
pub parent_element: ElementRc,
|
pub parent_element: ElementRc,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -445,7 +445,7 @@ fn duplicate_popup(p: &PopupWindow, mapping: &mut Mapping, priority_delta: i32)
|
||||||
PopupWindow {
|
PopupWindow {
|
||||||
x: p.x.clone(),
|
x: p.x.clone(),
|
||||||
y: p.y.clone(),
|
y: p.y.clone(),
|
||||||
close_on_click: p.close_on_click,
|
close_policy: p.close_policy.clone(),
|
||||||
component: duplicate_sub_component(&p.component, &parent, mapping, priority_delta),
|
component: duplicate_sub_component(&p.component, &parent, mapping, priority_delta),
|
||||||
parent_element: mapping
|
parent_element: mapping
|
||||||
.get(&element_key(p.parent_element.clone()))
|
.get(&element_key(p.parent_element.clone()))
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
|
|
||||||
use crate::diagnostics::BuildDiagnostics;
|
use crate::diagnostics::BuildDiagnostics;
|
||||||
use crate::expression_tree::{Expression, NamedReference};
|
use crate::expression_tree::{Expression, NamedReference};
|
||||||
use crate::langtype::{ElementType, Type};
|
use crate::langtype::{ElementType, EnumerationValue, Type};
|
||||||
use crate::object_tree::*;
|
use crate::object_tree::*;
|
||||||
use crate::typeregister::TypeRegister;
|
use crate::typeregister::TypeRegister;
|
||||||
use smol_str::format_smolstr;
|
use smol_str::format_smolstr;
|
||||||
|
@ -78,8 +78,15 @@ fn lower_popup_window(
|
||||||
|
|
||||||
const CLOSE_ON_CLICK: &str = "close-on-click";
|
const CLOSE_ON_CLICK: &str = "close-on-click";
|
||||||
let close_on_click = popup_window_element.borrow_mut().bindings.remove(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
|
let close_on_click = close_on_click
|
||||||
.map(|b| {
|
.map(|b| {
|
||||||
|
diag.push_property_deprecation_warning(
|
||||||
|
"close-on-click",
|
||||||
|
"close-policy",
|
||||||
|
&b.borrow().span,
|
||||||
|
);
|
||||||
let b = b.into_inner();
|
let b = b.into_inner();
|
||||||
(b.expression, b.span)
|
(b.expression, b.span)
|
||||||
})
|
})
|
||||||
|
@ -95,9 +102,38 @@ fn lower_popup_window(
|
||||||
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(|| {
|
||||||
|
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()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None
|
||||||
|
});
|
||||||
|
|
||||||
|
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 {
|
let close_on_click = match close_on_click {
|
||||||
Some((expr, location)) => match expr {
|
Some((expr, location)) => match expr {
|
||||||
Expression::BoolLiteral(value) => value,
|
Expression::BoolLiteral(value) => Some(value),
|
||||||
_ => {
|
_ => {
|
||||||
diag.push_error(
|
diag.push_error(
|
||||||
"The close-on-click property only supports constants at the moment".into(),
|
"The close-on-click property only supports constants at the moment".into(),
|
||||||
|
@ -106,7 +142,35 @@ fn lower_popup_window(
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
None => true,
|
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_ENUMS.with(|e| e.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 {
|
let popup_comp = Rc::new(Component {
|
||||||
|
@ -166,7 +230,7 @@ fn lower_popup_window(
|
||||||
component: popup_comp,
|
component: popup_comp,
|
||||||
x: coord_x,
|
x: coord_x,
|
||||||
y: coord_y,
|
y: coord_y,
|
||||||
close_on_click,
|
close_policy,
|
||||||
parent_element: parent_element.clone(),
|
parent_element: parent_element.clone(),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
|
|
||||||
use crate::diagnostics::Spanned;
|
use crate::diagnostics::Spanned;
|
||||||
use crate::expression_tree::{BindingExpression, Expression, Unit};
|
use crate::expression_tree::{BindingExpression, Expression, Unit};
|
||||||
use crate::langtype::{ElementType, Type};
|
use crate::langtype::{ElementType, Enumeration, Type};
|
||||||
use crate::layout::Orientation;
|
use crate::layout::Orientation;
|
||||||
use crate::namedreference::NamedReference;
|
use crate::namedreference::NamedReference;
|
||||||
use crate::object_tree::*;
|
use crate::object_tree::*;
|
||||||
|
@ -113,6 +113,18 @@ fn should_materialize(
|
||||||
} else if prop == "close-on-click" {
|
} else if prop == "close-on-click" {
|
||||||
// PopupWindow::close-on-click
|
// PopupWindow::close-on-click
|
||||||
return Some(Type::Bool);
|
return Some(Type::Bool);
|
||||||
|
} else if prop == "close-policy" {
|
||||||
|
// PopupWindow::close-policy
|
||||||
|
return Some(Type::Enumeration(Rc::new(Enumeration {
|
||||||
|
name: "PopupClosePolicy".into(),
|
||||||
|
values: vec![
|
||||||
|
"close-on-click".into(),
|
||||||
|
"close-on-click-outside".into(),
|
||||||
|
"no-auto-close".into(),
|
||||||
|
],
|
||||||
|
default_value: 0,
|
||||||
|
node: None,
|
||||||
|
})));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
None
|
None
|
||||||
|
|
|
@ -6,6 +6,7 @@ export component Bar {
|
||||||
in property <bool> external;
|
in property <bool> external;
|
||||||
xx := PopupWindow {
|
xx := PopupWindow {
|
||||||
close-on-click: true;
|
close-on-click: true;
|
||||||
|
// ^warning{The property 'close-on-click' has been deprecated. Please use 'close-policy' instead}
|
||||||
init => {
|
init => {
|
||||||
xx.close-on-click = true;
|
xx.close-on-click = true;
|
||||||
// ^error{The property must be known at compile time and cannot be changed at runtime}
|
// ^error{The property must be known at compile time and cannot be changed at runtime}
|
||||||
|
@ -13,7 +14,8 @@ export component Bar {
|
||||||
}
|
}
|
||||||
PopupWindow {
|
PopupWindow {
|
||||||
close-on-click: root.external;
|
close-on-click: root.external;
|
||||||
// ^error{The close-on-click property only supports constants at the moment}
|
// ^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}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
20
internal/compiler/tests/syntax/elements/popup3.slint
Normal file
20
internal/compiler/tests/syntax/elements/popup3.slint
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
// 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
|
||||||
|
|
||||||
|
|
||||||
|
export component Bar {
|
||||||
|
in property <PopupClosePolicy> external;
|
||||||
|
xx := PopupWindow {
|
||||||
|
close-policy: PopupClosePolicy.close-on-click;
|
||||||
|
init => {
|
||||||
|
xx.close-policy = PopupClosePolicy.close-on-click;
|
||||||
|
// ^error{The property must be known at compile time and cannot be changed at runtime}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
PopupWindow {
|
||||||
|
close-policy: root.external;
|
||||||
|
// ^error{The close-policy property only supports constants at the moment}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
|
@ -588,7 +588,7 @@ impl Snapshotter {
|
||||||
.expect("Looking at a known component"),
|
.expect("Looking at a known component"),
|
||||||
x: popup_window.x.snapshot(self),
|
x: popup_window.x.snapshot(self),
|
||||||
y: popup_window.y.snapshot(self),
|
y: popup_window.y.snapshot(self),
|
||||||
close_on_click: popup_window.close_on_click,
|
close_policy: popup_window.close_policy.clone(),
|
||||||
parent_element: self.use_element(&popup_window.parent_element),
|
parent_element: self.use_element(&popup_window.parent_element),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -369,6 +369,9 @@ impl TypeRegister {
|
||||||
|
|
||||||
popup.properties.get_mut("close-on-click").unwrap().property_visibility =
|
popup.properties.get_mut("close-on-click").unwrap().property_visibility =
|
||||||
PropertyVisibility::Constexpr;
|
PropertyVisibility::Constexpr;
|
||||||
|
|
||||||
|
popup.properties.get_mut("close-policy").unwrap().property_visibility =
|
||||||
|
PropertyVisibility::Constexpr;
|
||||||
}
|
}
|
||||||
|
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
|
|
|
@ -19,7 +19,7 @@ export component DatePickerPopup inherits PopupWindow {
|
||||||
|
|
||||||
width: 360px;
|
width: 360px;
|
||||||
height: 524px;
|
height: 524px;
|
||||||
close-on-click: false;
|
close-policy: PopupClosePolicy.no-auto-close;
|
||||||
|
|
||||||
background-layer := MenuBorder {
|
background-layer := MenuBorder {
|
||||||
width: dialog.width;
|
width: dialog.width;
|
||||||
|
|
|
@ -19,7 +19,7 @@ export component TimePickerPopup inherits PopupWindow {
|
||||||
callback canceled();
|
callback canceled();
|
||||||
callback accepted(/* current-time */ Time);
|
callback accepted(/* current-time */ Time);
|
||||||
|
|
||||||
close-on-click: false;
|
close-policy: PopupClosePolicy.no-auto-close;
|
||||||
|
|
||||||
background-layer := MenuBorder {
|
background-layer := MenuBorder {
|
||||||
width: dialog.width;
|
width: dialog.width;
|
||||||
|
|
|
@ -19,7 +19,7 @@ export component DatePickerPopup inherits PopupWindow {
|
||||||
|
|
||||||
width: 360px;
|
width: 360px;
|
||||||
height: 524px;
|
height: 524px;
|
||||||
close-on-click: false;
|
close-policy: PopupClosePolicy.no-auto-close;
|
||||||
|
|
||||||
background-layer := MenuBorder {
|
background-layer := MenuBorder {
|
||||||
width: dialog.width;
|
width: dialog.width;
|
||||||
|
|
|
@ -18,7 +18,7 @@ export component TimePickerPopup inherits PopupWindow {
|
||||||
callback canceled();
|
callback canceled();
|
||||||
callback accepted(/* current-time */ Time);
|
callback accepted(/* current-time */ Time);
|
||||||
|
|
||||||
close-on-click: false;
|
close-policy: PopupClosePolicy.no-auto-close;
|
||||||
|
|
||||||
background-layer := MenuBorder {
|
background-layer := MenuBorder {
|
||||||
width: dialog.width;
|
width: dialog.width;
|
||||||
|
|
|
@ -19,7 +19,7 @@ export component DatePickerPopup inherits PopupWindow {
|
||||||
|
|
||||||
width: 368px;
|
width: 368px;
|
||||||
height: 524px;
|
height: 524px;
|
||||||
close-on-click: false;
|
close-policy: PopupClosePolicy.no-auto-close;
|
||||||
|
|
||||||
background-layer := MenuBorder {
|
background-layer := MenuBorder {
|
||||||
width: dialog.width;
|
width: dialog.width;
|
||||||
|
|
|
@ -18,7 +18,7 @@ export component TimePickerPopup inherits PopupWindow {
|
||||||
callback canceled();
|
callback canceled();
|
||||||
callback accepted(/* current-time */ Time);
|
callback accepted(/* current-time */ Time);
|
||||||
|
|
||||||
close-on-click: false;
|
close-policy: PopupClosePolicy.no-auto-close;
|
||||||
|
|
||||||
background-layer := MenuBorder {
|
background-layer := MenuBorder {
|
||||||
width: dialog.width;
|
width: dialog.width;
|
||||||
|
|
|
@ -17,7 +17,7 @@ export component DatePickerPopup inherits PopupWindow {
|
||||||
|
|
||||||
width: 360px;
|
width: 360px;
|
||||||
height: 524px;
|
height: 524px;
|
||||||
close-on-click: false;
|
close-policy: PopupClosePolicy.no-auto-close;
|
||||||
|
|
||||||
background-layer := Rectangle {
|
background-layer := Rectangle {
|
||||||
width: dialog.width;
|
width: dialog.width;
|
||||||
|
|
|
@ -17,7 +17,7 @@ export component TimePickerPopup inherits PopupWindow {
|
||||||
callback canceled();
|
callback canceled();
|
||||||
callback accepted(/* current-time */ Time);
|
callback accepted(/* current-time */ Time);
|
||||||
|
|
||||||
close-on-click: false;
|
close-policy: PopupClosePolicy.no-auto-close;
|
||||||
|
|
||||||
background-layer := Rectangle {
|
background-layer := Rectangle {
|
||||||
width: dialog.width;
|
width: dialog.width;
|
||||||
|
|
|
@ -21,7 +21,7 @@ export component DatePickerPopup inherits PopupWindow {
|
||||||
|
|
||||||
width: 360px;
|
width: 360px;
|
||||||
height: 524px;
|
height: 524px;
|
||||||
close-on-click: false;
|
close-policy: PopupClosePolicy.no-auto-close;
|
||||||
|
|
||||||
background-layer := Rectangle {
|
background-layer := Rectangle {
|
||||||
border-radius: 8px;
|
border-radius: 8px;
|
||||||
|
|
|
@ -18,7 +18,7 @@ export component TimePickerPopup inherits PopupWindow {
|
||||||
callback canceled();
|
callback canceled();
|
||||||
callback accepted(/* current-time */ Time);
|
callback accepted(/* current-time */ Time);
|
||||||
|
|
||||||
close-on-click: false;
|
close-policy: PopupClosePolicy.no-auto-close;
|
||||||
|
|
||||||
background-layer := Rectangle {
|
background-layer := Rectangle {
|
||||||
width: dialog.width;
|
width: dialog.width;
|
||||||
|
|
|
@ -17,6 +17,7 @@ use crate::input::{
|
||||||
};
|
};
|
||||||
use crate::item_tree::ItemRc;
|
use crate::item_tree::ItemRc;
|
||||||
use crate::item_tree::{ItemTreeRc, ItemTreeRef, ItemTreeVTable, ItemTreeWeak};
|
use crate::item_tree::{ItemTreeRc, ItemTreeRef, ItemTreeVTable, ItemTreeWeak};
|
||||||
|
use crate::items::PopupClosePolicy;
|
||||||
use crate::items::{ColorScheme, InputType, ItemRef, MouseCursor};
|
use crate::items::{ColorScheme, InputType, ItemRef, MouseCursor};
|
||||||
use crate::lengths::{LogicalLength, LogicalPoint, LogicalRect, SizeLengths};
|
use crate::lengths::{LogicalLength, LogicalPoint, LogicalRect, SizeLengths};
|
||||||
use crate::properties::{Property, PropertyTracker};
|
use crate::properties::{Property, PropertyTracker};
|
||||||
|
@ -386,9 +387,8 @@ struct PopupWindow {
|
||||||
location: PopupWindowLocation,
|
location: PopupWindowLocation,
|
||||||
/// The component that is responsible for providing the popup content.
|
/// The component that is responsible for providing the popup content.
|
||||||
component: ItemTreeRc,
|
component: ItemTreeRc,
|
||||||
/// If true, Slint will close the popup after any mouse click within the popup.
|
//// Defines the close behaviour of the popup.
|
||||||
/// Set to false and call close() on the PopupWindow to close it manually.
|
close_policy: PopupClosePolicy,
|
||||||
close_on_click: bool,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[pin_project::pin_project]
|
#[pin_project::pin_project]
|
||||||
|
@ -578,7 +578,7 @@ impl WindowInner {
|
||||||
self.had_popup_on_press.set(self.active_popup.borrow().is_some());
|
self.had_popup_on_press.set(self.active_popup.borrow().is_some());
|
||||||
}
|
}
|
||||||
|
|
||||||
let close_popup_on_click = self.close_popup_on_click();
|
let close_policy = self.close_policy();
|
||||||
let mut mouse_inside_popup = false;
|
let mut mouse_inside_popup = false;
|
||||||
|
|
||||||
mouse_input_state = if let Some(mut event) =
|
mouse_input_state = if let Some(mut event) =
|
||||||
|
@ -637,12 +637,21 @@ impl WindowInner {
|
||||||
|
|
||||||
self.mouse_input_state.set(mouse_input_state);
|
self.mouse_input_state.set(mouse_input_state);
|
||||||
|
|
||||||
if close_popup_on_click
|
match close_policy {
|
||||||
&& ((mouse_inside_popup && released_event && self.had_popup_on_press.get())
|
PopupClosePolicy::CloseOnClick => {
|
||||||
|| (!mouse_inside_popup && pressed_event))
|
if (mouse_inside_popup && released_event && self.had_popup_on_press.get())
|
||||||
{
|
|| (!mouse_inside_popup && pressed_event)
|
||||||
self.close_popup();
|
{
|
||||||
}
|
self.close_popup();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
PopupClosePolicy::CloseOnClickOutside => {
|
||||||
|
if !mouse_inside_popup && pressed_event {
|
||||||
|
self.close_popup();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
PopupClosePolicy::NoAutoClose => {}
|
||||||
|
};
|
||||||
|
|
||||||
crate::properties::ChangeTracker::run_change_handlers();
|
crate::properties::ChangeTracker::run_change_handlers();
|
||||||
}
|
}
|
||||||
|
@ -968,7 +977,7 @@ impl WindowInner {
|
||||||
&self,
|
&self,
|
||||||
popup_componentrc: &ItemTreeRc,
|
popup_componentrc: &ItemTreeRc,
|
||||||
position: Point,
|
position: Point,
|
||||||
close_on_click: bool,
|
close_policy: PopupClosePolicy,
|
||||||
parent_item: &ItemRc,
|
parent_item: &ItemRc,
|
||||||
) {
|
) {
|
||||||
let position = parent_item.map_to_window(
|
let position = parent_item.map_to_window(
|
||||||
|
@ -1036,7 +1045,7 @@ impl WindowInner {
|
||||||
self.active_popup.replace(Some(PopupWindow {
|
self.active_popup.replace(Some(PopupWindow {
|
||||||
location,
|
location,
|
||||||
component: popup_componentrc.clone(),
|
component: popup_componentrc.clone(),
|
||||||
close_on_click,
|
close_policy,
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1066,9 +1075,12 @@ impl WindowInner {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns true if the currently active popup is configured to close on click. None if there is no active popup.
|
/// Returns the close policy of the active popup. PopupClosePolicy::NoAutoClose if there is no active popup.
|
||||||
pub fn close_popup_on_click(&self) -> bool {
|
pub fn close_policy(&self) -> PopupClosePolicy {
|
||||||
self.active_popup.borrow().as_ref().map_or(false, |popup| popup.close_on_click)
|
self.active_popup
|
||||||
|
.borrow()
|
||||||
|
.as_ref()
|
||||||
|
.map_or(PopupClosePolicy::NoAutoClose, |popup| popup.close_policy)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the scale factor set on the window, as provided by the windowing system.
|
/// Returns the scale factor set on the window, as provided by the windowing system.
|
||||||
|
@ -1329,14 +1341,14 @@ pub mod ffi {
|
||||||
handle: *const WindowAdapterRcOpaque,
|
handle: *const WindowAdapterRcOpaque,
|
||||||
popup: &ItemTreeRc,
|
popup: &ItemTreeRc,
|
||||||
position: crate::graphics::Point,
|
position: crate::graphics::Point,
|
||||||
close_on_click: bool,
|
close_policy: PopupClosePolicy,
|
||||||
parent_item: &ItemRc,
|
parent_item: &ItemRc,
|
||||||
) {
|
) {
|
||||||
let window_adapter = &*(handle as *const Rc<dyn WindowAdapter>);
|
let window_adapter = &*(handle as *const Rc<dyn WindowAdapter>);
|
||||||
WindowInner::from_pub(window_adapter.window()).show_popup(
|
WindowInner::from_pub(window_adapter.window()).show_popup(
|
||||||
popup,
|
popup,
|
||||||
position,
|
position,
|
||||||
close_on_click,
|
close_policy,
|
||||||
parent_item,
|
parent_item,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,7 +22,9 @@ use i_slint_core::item_tree::{
|
||||||
ItemRc, ItemTreeNode, ItemVisitorRefMut, ItemVisitorVTable, ItemWeak, TraversalOrder,
|
ItemRc, ItemTreeNode, ItemVisitorRefMut, ItemVisitorVTable, ItemWeak, TraversalOrder,
|
||||||
VisitChildrenResult,
|
VisitChildrenResult,
|
||||||
};
|
};
|
||||||
use i_slint_core::items::{AccessibleRole, ItemRef, ItemVTable, PropertyAnimation};
|
use i_slint_core::items::{
|
||||||
|
AccessibleRole, ItemRef, ItemVTable, PopupClosePolicy, PropertyAnimation,
|
||||||
|
};
|
||||||
use i_slint_core::layout::{BoxLayoutCellData, LayoutInfo, Orientation};
|
use i_slint_core::layout::{BoxLayoutCellData, LayoutInfo, Orientation};
|
||||||
use i_slint_core::lengths::{LogicalLength, LogicalRect};
|
use i_slint_core::lengths::{LogicalLength, LogicalRect};
|
||||||
use i_slint_core::model::RepeatedItemTree;
|
use i_slint_core::model::RepeatedItemTree;
|
||||||
|
@ -2328,7 +2330,7 @@ impl<'a, 'id> InstanceRef<'a, 'id> {
|
||||||
pub fn show_popup(
|
pub fn show_popup(
|
||||||
popup: &object_tree::PopupWindow,
|
popup: &object_tree::PopupWindow,
|
||||||
pos_getter: impl FnOnce(InstanceRef<'_, '_>) -> i_slint_core::graphics::Point,
|
pos_getter: impl FnOnce(InstanceRef<'_, '_>) -> i_slint_core::graphics::Point,
|
||||||
close_on_click: bool,
|
close_policy: PopupClosePolicy,
|
||||||
parent_comp: ErasedItemTreeBoxWeak,
|
parent_comp: ErasedItemTreeBoxWeak,
|
||||||
parent_window_adapter: WindowAdapterRc,
|
parent_window_adapter: WindowAdapterRc,
|
||||||
parent_item: &ItemRc,
|
parent_item: &ItemRc,
|
||||||
|
@ -2354,7 +2356,7 @@ pub fn show_popup(
|
||||||
WindowInner::from_pub(parent_window_adapter.window()).show_popup(
|
WindowInner::from_pub(parent_window_adapter.window()).show_popup(
|
||||||
&vtable::VRc::into_dyn(inst),
|
&vtable::VRc::into_dyn(inst),
|
||||||
pos,
|
pos,
|
||||||
close_on_click,
|
close_policy,
|
||||||
parent_item,
|
parent_item,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -606,6 +606,13 @@ fn call_builtin_function(
|
||||||
parent_item_info.item_index(),
|
parent_item_info.item_index(),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
let close_policy = Value::EnumerationValue(
|
||||||
|
popup.close_policy.enumeration.name.to_string(),
|
||||||
|
popup.close_policy.to_string(),
|
||||||
|
)
|
||||||
|
.try_into()
|
||||||
|
.expect("Invalid internal enumeration representation for close policy");
|
||||||
|
|
||||||
crate::dynamic_item_tree::show_popup(
|
crate::dynamic_item_tree::show_popup(
|
||||||
popup,
|
popup,
|
||||||
|instance_ref| {
|
|instance_ref| {
|
||||||
|
@ -619,7 +626,7 @@ fn call_builtin_function(
|
||||||
y.try_into().unwrap(),
|
y.try_into().unwrap(),
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
popup.close_on_click,
|
close_policy,
|
||||||
enclosing_component.self_weak().get().unwrap().clone(),
|
enclosing_component.self_weak().get().unwrap().clone(),
|
||||||
component.window_adapter(),
|
component.window_adapter(),
|
||||||
&parent_item,
|
&parent_item,
|
||||||
|
|
455
tests/cases/elements/popupwindow_close_policy.slint
Normal file
455
tests/cases/elements/popupwindow_close_policy.slint
Normal file
|
@ -0,0 +1,455 @@
|
||||||
|
// 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
|
||||||
|
|
||||||
|
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 := PopupWindow {
|
||||||
|
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 := PopupWindow {
|
||||||
|
close-policy: no-auto-close;
|
||||||
|
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 := PopupWindow {
|
||||||
|
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 := PopupWindow {
|
||||||
|
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);
|
||||||
|
|
||||||
|
// 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, 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(), 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);
|
||||||
|
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
```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);
|
||||||
|
```
|
||||||
|
|
||||||
|
```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);
|
||||||
|
```
|
||||||
|
|
||||||
|
*/
|
|
@ -18,7 +18,7 @@ component MyPopup inherits PopupWindow {
|
||||||
}
|
}
|
||||||
|
|
||||||
component MyPopup2 inherits MyPopup {
|
component MyPopup2 inherits MyPopup {
|
||||||
close-on-click: false;
|
close-policy: no-auto-close;
|
||||||
}
|
}
|
||||||
|
|
||||||
export component TestCase {
|
export component TestCase {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue