Skip to content

Commit

Permalink
Implement closing of popup menus
Browse files Browse the repository at this point in the history
  • Loading branch information
ogoffart committed Feb 10, 2025
1 parent 7fe86d2 commit 2e4353d
Show file tree
Hide file tree
Showing 9 changed files with 165 additions and 61 deletions.
45 changes: 27 additions & 18 deletions internal/compiler/generator/cpp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1774,12 +1774,10 @@ fn generate_item_tree(

// Repeaters run their user_init() code from Repeater::ensure_updated() after update() initialized model_data/index.
// And in PopupWindow this is also called by the runtime
if parent_ctx.is_none() {
if parent_ctx.is_none() && !is_popup_menu {
create_code.push("self->user_init();".to_string());
if !is_popup_menu {
// initialize the Window in this point to be consistent with Rust
create_code.push("self->window();".to_string())
}
// initialize the Window in this point to be consistent with Rust
create_code.push("self->window();".to_string())
}

create_code
Expand Down Expand Up @@ -3775,6 +3773,7 @@ fn compile_builtin_function_call(
let access_entries = access_member(&popup.entries, &popup_ctx);
let access_sub_menu = access_member(&popup.sub_menu, &popup_ctx);
let access_activated = access_member(&popup.activated, &popup_ctx);
let access_close = access_member(&popup.close, &popup_ctx);
let init = if let llr::Expression::NumberLiteral(tree_index) = entries {
// We have an MenuItem tree
let current_sub_component = ctx.current_sub_component().unwrap();
Expand All @@ -3787,26 +3786,36 @@ fn compile_builtin_function_call(
")

} else {
let forward_callback = |access, cb| {
let forward_callback = |access, cb, default| {
format!("{access}.set_handler(
[context_menu](const auto &entry) {{
return context_menu->{cb}.call(entry);
[context_menu, parent_weak](const auto &entry) {{
if(auto lock = parent_weak.lock()) {{
return context_menu->{cb}.call(entry);
}} else {{
return {default};
}}
}});")
};
let fw_sub_menu = forward_callback(access_sub_menu, "sub_menu");
let fw_activated = forward_callback(access_activated, "activated");
let fw_sub_menu = forward_callback(access_sub_menu, "sub_menu", "std::shared_ptr<slint::Model<slint::cbindgen_private::MenuEntry>>()");
let fw_activated = forward_callback(access_activated, "activated", "");
let entries = compile_expression(entries, ctx);
format!(r"
const slint::cbindgen_private::ContextMenu *context_menu = &({context_menu});
auto entries = {entries};
{{
auto self = popup_menu;
{access_entries}.set(std::move(entries));
{fw_sub_menu}
{fw_activated}
}}")
const slint::cbindgen_private::ContextMenu *context_menu = &({context_menu});
auto self = popup_menu;
{access_entries}.set(std::move(entries));
{fw_sub_menu}
{fw_activated}
")
};
format!("{window}.close_popup({context_menu}.popup_id); {context_menu}.popup_id = {window}.show_popup_menu<{popup_id}>({globals}, {position}, {{ {context_menu_rc} }}, [self](auto popup_menu) {{ {init} }})", globals = ctx.generator_state.global_access)
format!(r"
{window}.close_popup({context_menu}.popup_id);
{context_menu}.popup_id = {window}.show_popup_menu<{popup_id}>({globals}, {position}, {{ {context_menu_rc} }}, [self](auto popup_menu) {{
auto parent_weak = self->self_weak;
auto self_ = self;
{init}
{access_close}.set_handler([parent_weak,self = self_] {{ if(auto lock = parent_weak.lock()) {{ {window}.close_popup({context_menu}.popup_id); }} }});
}})", globals = ctx.generator_state.global_access)
}
BuiltinFunction::SetSelectionOffsets => {
if let [llr::Expression::PropertyReference(pr), from, to] = arguments {
Expand Down
23 changes: 20 additions & 3 deletions internal/compiler/generator/rust.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2783,6 +2783,13 @@ fn compile_builtin_function_call(
let access_entries = access_member(&popup.entries, &popup_ctx).unwrap();
let access_sub_menu = access_member(&popup.sub_menu, &popup_ctx).unwrap();
let access_activated = access_member(&popup.activated, &popup_ctx).unwrap();
let access_close = access_member(&popup.close, &popup_ctx).unwrap();

let close_popup = context_menu.clone().then(|context_menu| quote!{
if let Some(current_id) = #context_menu.popup_id.take() {
sp::WindowInner::from_pub(#window_adapter_tokens.window()).close_popup(current_id);
}
});

let init_popup = if let Expression::NumberLiteral(tree_index) = entries {
// We have an MenuItem tree
Expand All @@ -2807,6 +2814,12 @@ fn compile_builtin_function_call(
#access_activated.set_handler(move |entry| {
sp::Menu::activate(&*context_menu_item_tree, &entry.0);
});
let self_weak = parent_weak.clone();
#access_close.set_handler(move |()| {
let self_rc = self_weak.upgrade().unwrap();
let _self = self_rc.as_pin_ref();
#close_popup
});
})
} else {
// entries should be an expression of type array of MenuEntry
Expand Down Expand Up @@ -2836,6 +2849,12 @@ fn compile_builtin_function_call(
#access_entries.set(entries);
#fw_sub_menu
#fw_activated
let self_weak = parent_weak.clone();
#access_close.set_handler(move |()| {
let Some(self_rc) = self_weak.upgrade() else { return };
let _self = self_rc.as_pin_ref();
#close_popup
});
}
}
};
Expand All @@ -2846,9 +2865,7 @@ fn compile_builtin_function_call(
let popup_instance_vrc = sp::VRc::map(popup_instance.clone(), |x| x);
let parent_weak = _self.self_weak.get().unwrap().clone();
#init_popup
if let Some(current_id) = #context_menu.popup_id.take() {
sp::WindowInner::from_pub(#window_adapter_tokens.window()).close_popup(current_id);
}
#close_popup
let id = sp::WindowInner::from_pub(#window_adapter_tokens.window()).show_popup(
&sp::VRc::into_dyn(popup_instance.into()),
position,
Expand Down
1 change: 1 addition & 0 deletions internal/compiler/llr/item_tree.rs
Original file line number Diff line number Diff line change
Expand Up @@ -297,6 +297,7 @@ pub struct PopupMenu {
pub item_tree: ItemTree,
pub sub_menu: PropertyReference,
pub activated: PropertyReference,
pub close: PropertyReference,
pub entries: PropertyReference,
}

Expand Down
6 changes: 5 additions & 1 deletion internal/compiler/llr/lower_to_item_tree.rs
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,10 @@ pub fn lower_to_item_tree(
&NamedReference::new(&c.root_element, SmolStr::new_static("activated")),
&state,
);
let close = sc.mapping.map_property_reference(
&NamedReference::new(&c.root_element, SmolStr::new_static("close")),
&state,
);
let entries = sc.mapping.map_property_reference(
&NamedReference::new(&c.root_element, SmolStr::new_static("entries")),
&state,
Expand All @@ -87,7 +91,7 @@ pub fn lower_to_item_tree(
root: state.push_sub_component(sc),
parent_context: None,
};
PopupMenu { item_tree, sub_menu, activated, entries }
PopupMenu { item_tree, sub_menu, activated, close, entries }
});

let root = CompilationUnit {
Expand Down
22 changes: 14 additions & 8 deletions internal/compiler/widgets/common/menus.slint
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ export component PopupMenuImpl inherits Window {
in property <[MenuEntry]> entries: [];
callback sub-menu(MenuEntry) -> [MenuEntry];
callback activated(MenuEntry);
callback close();
private property <int> current: -1;
forward-focus: fs;

Expand Down Expand Up @@ -48,10 +49,17 @@ export component PopupMenuImpl inherits Window {
}
TouchArea {
pointer-event(event) => {
fs.focus();
if event.kind == PointerEventKind.move {
if event.kind == PointerEventKind.move && current != idx {
fs.focus();
current = idx;
open-sub-menu-after-timeout.running = true;
} else if event.kind == PointerEventKind.down && entry.has-sub-menu {
activate(entry, self.absolute-position.y);
} else if event.kind == PointerEventKind.up
&& self.mouse-y > 0 && self.mouse-y < self.height
&& self.mouse-x > 0 && self.mouse-x < self.width {
// can't put this in `clicked` because then the menu would close causing a panic in the pointer-event
activate(entry, self.absolute-position.y);
}
}

Expand All @@ -60,10 +68,6 @@ export component PopupMenuImpl inherits Window {
current = -1
}
}

clicked => {
activate(entry, self.absolute-position.y);
}
}
}
}
Expand Down Expand Up @@ -98,6 +102,7 @@ export component PopupMenuImpl inherits Window {
return accept;
} else if event.text == Key.LeftArrow {
// TODO: should close only if this menu is a sub menu
root.close();
}
return reject;
}
Expand All @@ -121,7 +126,7 @@ export component PopupMenuImpl inherits Window {
subMenu := ContextMenuInternal {
x: 0; y: 0; width: 0; height: 0;
sub-menu(entry) => { root.sub-menu(entry); }
activated(entry) => { root.activated(entry); }
activated(entry) => { root.activated(entry); root.close(); }
}

function activate(entry : MenuEntry, y: length) {
Expand All @@ -134,6 +139,7 @@ export component PopupMenuImpl inherits Window {
});
} else {
activated(entry);
close();
}
}
}
Expand Down Expand Up @@ -185,7 +191,7 @@ export component MenuBarImpl {


cm := ContextMenuInternal {
activated(entry) => { root.activated(entry); }
activated(entry) => { root.activated(entry); self.close(); }
sub-menu(entry) => { root.sub-menu(entry); }
}
}
Expand Down
12 changes: 11 additions & 1 deletion internal/core/window.rs
Original file line number Diff line number Diff line change
Expand Up @@ -598,7 +598,7 @@ impl WindowInner {
self.had_popup_on_press.set(!self.active_popups.borrow().is_empty());
}

let popup_to_close = self.active_popups.borrow().last().and_then(|popup| {
let mut popup_to_close = self.active_popups.borrow().last().and_then(|popup| {
let mouse_inside_popup = || {
if let PopupWindowLocation::ChildWindow(coordinates) = &popup.location {
event.position().map_or(true, |pos| {
Expand Down Expand Up @@ -644,6 +644,9 @@ impl WindowInner {

if !popup.is_menu {
break;
} else if popup_to_close.is_some() {
// clicking outside of a popup menu should close all the menus
popup_to_close = Some(popup.popup_id);
}
}

Expand Down Expand Up @@ -1224,6 +1227,13 @@ impl WindowInner {
let p = active_popups.remove(popup_index);
drop(active_popups);
self.close_popup_impl(&p);
if p.is_menu {
// close all sub-menus
while self.active_popups.borrow().get(popup_index).is_some_and(|p| p.is_menu) {
let p = self.active_popups.borrow_mut().remove(popup_index);
self.close_popup_impl(&p);
}
}
}
}

Expand Down
24 changes: 22 additions & 2 deletions internal/interpreter/eval.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,10 @@ use crate::dynamic_item_tree::{CallbackHandler, InstanceRef};
use core::pin::Pin;
use corelib::graphics::{GradientStop, LinearGradientBrush, PathElement, RadialGradientBrush};
use corelib::items::{ColorScheme, ItemRef, MenuEntry, PropertyAnimation};
use corelib::menus::{Menu, MenuVTable};
use corelib::menus::{Menu, MenuFromItemTree, MenuVTable};
use corelib::model::{Model, ModelExt, ModelRc, VecModel};
use corelib::rtti::AnimatedBindingKind;
use corelib::window::WindowInner;
use corelib::{Brush, Color, PathData, SharedString, SharedVector};
use i_slint_compiler::expression_tree::{
BuiltinFunction, Callable, EasingCurve, Expression, MinMaxOp, Path as ExprPath,
Expand All @@ -18,7 +19,6 @@ use i_slint_compiler::langtype::Type;
use i_slint_compiler::namedreference::NamedReference;
use i_slint_compiler::object_tree::ElementRc;
use i_slint_core as corelib;
use i_slint_core::menus::MenuFromItemTree;
use smol_str::SmolStr;
use std::collections::HashMap;
use std::rc::Rc;
Expand Down Expand Up @@ -762,6 +762,26 @@ fn call_builtin_function(
)
.unwrap();
}
let item_weak = item_rc.downgrade();
compiled
.set_callback_handler(
inst_ref.borrow(),
"close",
Box::new(move |_args: &[Value]| -> Value {
let Some(item_rc) = item_weak.upgrade() else { return Value::Void };
if let Some(id) = item_rc
.downcast::<corelib::items::ContextMenu>()
.unwrap()
.popup_id
.take()
{
WindowInner::from_pub(item_rc.window_adapter().unwrap().window())
.close_popup(id);
}
Value::Void
}),
)
.unwrap();
component.access_window(|window| {
let context_menu_elem = item_rc.downcast::<corelib::items::ContextMenu>().unwrap();
if let Some(old_id) = context_menu_elem.popup_id.take() {
Expand Down
Loading

0 comments on commit 2e4353d

Please sign in to comment.