mirror of
https://github.com/slint-ui/slint.git
synced 2025-11-03 05:12:55 +00:00
Refrersh the menubar when one of the property get changed
Install a PropertyTracker to update the shadow tree if something changes
This commit is contained in:
parent
a3d46a9e88
commit
094ff8f56b
5 changed files with 76 additions and 52 deletions
|
|
@ -1269,11 +1269,13 @@ inline void setup_popup_menu_from_menu_item_tree(
|
|||
using cbindgen_private::MenuVTable;
|
||||
auto shared = std::make_shared<vtable::VBox<MenuVTable>>(nullptr, nullptr);
|
||||
cbindgen_private::slint_menus_create_wrapper(&menu_item_tree, &*shared);
|
||||
SharedVector<MenuEntry> entries_sv;
|
||||
entries.set_binding([shared] {
|
||||
vtable::VRefMut<MenuVTable> ref { shared->vtable, shared->instance };
|
||||
SharedVector<MenuEntry> entries_sv;
|
||||
shared->vtable->sub_menu(ref, nullptr, &entries_sv);
|
||||
std::vector<MenuEntry> entries_vec(entries_sv.begin(), entries_sv.end());
|
||||
entries.set(std::make_shared<VectorModel<MenuEntry>>(std::move(entries_vec)));
|
||||
return std::make_shared<VectorModel<MenuEntry>>(std::move(entries_vec));
|
||||
});
|
||||
sub_menu.set_handler([shared](const auto &entry) {
|
||||
vtable::VRefMut<MenuVTable> ref { shared->vtable, shared->instance };
|
||||
SharedVector<MenuEntry> entries_sv;
|
||||
|
|
|
|||
|
|
@ -3084,9 +3084,12 @@ fn compile_builtin_function_call(
|
|||
sp::WindowInner::from_pub(#window_adapter_tokens.window()).setup_menubar(sp::VBox::new(menu_item_tree));
|
||||
} else {
|
||||
let menu_item_tree = sp::Rc::new(menu_item_tree);
|
||||
let menu_item_tree_ = menu_item_tree.clone();
|
||||
#access_entries.set_binding(move || {
|
||||
let mut entries = sp::SharedVector::default();
|
||||
sp::Menu::sub_menu(&*menu_item_tree, sp::Option::None, &mut entries);
|
||||
#access_entries.set(sp::ModelRc::new(sp::SharedVectorModel::from(entries)));
|
||||
sp::Menu::sub_menu(&*menu_item_tree_, sp::Option::None, &mut entries);
|
||||
sp::ModelRc::new(sp::SharedVectorModel::from(entries))
|
||||
});
|
||||
let menu_item_tree_ = menu_item_tree.clone();
|
||||
#access_sub_menu.set_handler(move |entry| {
|
||||
let mut entries = sp::SharedVector::default();
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@
|
|||
use crate::item_rendering::CachedRenderingData;
|
||||
use crate::item_tree::{ItemTreeRc, ItemWeak, VisitChildrenResult};
|
||||
use crate::items::{ItemRc, ItemRef, MenuEntry, VoidArg};
|
||||
use crate::properties::PropertyTracker;
|
||||
#[cfg(feature = "rtti")]
|
||||
use crate::rtti::*;
|
||||
use crate::string::ToSharedString;
|
||||
|
|
@ -15,6 +16,7 @@ use crate::{Callback, Property, SharedString, SharedVector};
|
|||
use alloc::boxed::Box;
|
||||
use alloc::collections::BTreeMap;
|
||||
use alloc::rc::Rc;
|
||||
use core::cell::{Cell, RefCell};
|
||||
use core::pin::Pin;
|
||||
use i_slint_core_macros::SlintElement;
|
||||
use vtable::{VRef, VRefMut};
|
||||
|
|
@ -38,39 +40,44 @@ struct ShadowTreeNode {
|
|||
|
||||
pub struct MenuFromItemTree {
|
||||
item_tree: ItemTreeRc,
|
||||
item_cache: BTreeMap<SharedString, ShadowTreeNode>,
|
||||
root: SharedVector<MenuEntry>,
|
||||
item_cache: RefCell<BTreeMap<SharedString, ShadowTreeNode>>,
|
||||
root: RefCell<SharedVector<MenuEntry>>,
|
||||
next_id: Cell<usize>,
|
||||
tracker: Pin<Box<PropertyTracker>>,
|
||||
}
|
||||
|
||||
impl MenuFromItemTree {
|
||||
pub fn new(item_tree: ItemTreeRc) -> Self {
|
||||
let mut this = Self { item_tree, item_cache: Default::default(), root: Default::default() };
|
||||
this.update_shadow_tree();
|
||||
this
|
||||
Self {
|
||||
item_tree,
|
||||
item_cache: Default::default(),
|
||||
root: Default::default(),
|
||||
tracker: Box::pin(PropertyTracker::default()),
|
||||
next_id: 0.into(),
|
||||
}
|
||||
pub fn update_shadow_tree(&mut self) {
|
||||
self.root =
|
||||
self.update_shadow_tree_recursive(&ItemRc::new(self.item_tree.clone(), 0), &mut 0);
|
||||
}
|
||||
|
||||
fn update_shadow_tree_recursive(
|
||||
&mut self,
|
||||
parent: &ItemRc,
|
||||
next_id: &mut usize,
|
||||
) -> SharedVector<MenuEntry> {
|
||||
fn update_shadow_tree(&self) {
|
||||
self.tracker.as_ref().evaluate_if_dirty(|| {
|
||||
self.item_cache.replace(Default::default());
|
||||
self.root
|
||||
.replace(self.update_shadow_tree_recursive(&ItemRc::new(self.item_tree.clone(), 0)))
|
||||
});
|
||||
}
|
||||
|
||||
fn update_shadow_tree_recursive(&self, parent: &ItemRc) -> SharedVector<MenuEntry> {
|
||||
let mut result = SharedVector::default();
|
||||
|
||||
let mut actual_visitor = |item_tree: &ItemTreeRc,
|
||||
index: u32,
|
||||
item_pin: core::pin::Pin<ItemRef>|
|
||||
-> VisitChildrenResult {
|
||||
let mut actual_visitor =
|
||||
|item_tree: &ItemTreeRc, index: u32, item_pin: Pin<ItemRef>| -> VisitChildrenResult {
|
||||
if let Some(menu_item) = ItemRef::downcast_pin::<MenuItem>(item_pin) {
|
||||
let next_id = self.next_id.get();
|
||||
self.next_id.set(next_id + 1);
|
||||
let id = next_id.to_shared_string();
|
||||
*next_id += 1;
|
||||
let item = ItemRc::new(item_tree.clone(), index);
|
||||
let children = self.update_shadow_tree_recursive(&item, next_id);
|
||||
let children = self.update_shadow_tree_recursive(&item);
|
||||
let has_sub_menu = !children.is_empty();
|
||||
self.item_cache.insert(
|
||||
self.item_cache.borrow_mut().insert(
|
||||
id.clone(),
|
||||
ShadowTreeNode { item: ItemRc::downgrade(&item), children },
|
||||
);
|
||||
|
|
@ -91,21 +98,22 @@ impl MenuFromItemTree {
|
|||
|
||||
impl Menu for MenuFromItemTree {
|
||||
fn sub_menu(&self, parent: Option<&MenuEntry>, result: &mut SharedVector<MenuEntry>) {
|
||||
self.update_shadow_tree();
|
||||
match parent {
|
||||
Some(parent) => {
|
||||
if let Some(r) = self.item_cache.get(parent.id.as_str()) {
|
||||
if let Some(r) = self.item_cache.borrow().get(parent.id.as_str()) {
|
||||
*result = r.children.clone();
|
||||
}
|
||||
}
|
||||
None => {
|
||||
*result = self.root.clone();
|
||||
*result = self.root.borrow().clone();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn activate(&self, entry: &MenuEntry) {
|
||||
if let Some(menu_item) =
|
||||
self.item_cache.get(entry.id.as_str()).and_then(|e| e.item.upgrade())
|
||||
self.item_cache.borrow().get(entry.id.as_str()).and_then(|e| e.item.upgrade())
|
||||
{
|
||||
if let Some(menu_item) = menu_item.downcast::<MenuItem>() {
|
||||
menu_item.activated.call(&());
|
||||
|
|
|
|||
|
|
@ -550,7 +550,6 @@ impl<'id> ItemTreeDescription<'id> {
|
|||
///
|
||||
/// Returns an error if the instance does not corresponds to this ItemTreeDescription,
|
||||
/// or if the property with this name does not exist in this component
|
||||
#[allow(unused)]
|
||||
pub fn set_binding(
|
||||
&self,
|
||||
component: ItemTreeRefPin,
|
||||
|
|
|
|||
|
|
@ -722,7 +722,7 @@ fn call_builtin_function(
|
|||
&menu_item_tree,
|
||||
&enclosing_component,
|
||||
));
|
||||
compiled.set_property(inst_ref.borrow(), "entries", entries).unwrap();
|
||||
compiled.set_binding(inst_ref.borrow(), "entries", entries).unwrap();
|
||||
compiled.set_callback_handler(inst_ref.borrow(), "sub-menu", sub_menu).unwrap();
|
||||
compiled.set_callback_handler(inst_ref.borrow(), "activated", activated).unwrap();
|
||||
} else {
|
||||
|
|
@ -1172,7 +1172,14 @@ fn call_builtin_function(
|
|||
|
||||
let (entries, sub_menu, activated) = menu_item_tree_properties(menu_item_tree);
|
||||
|
||||
store_property(component, &entries_nr.element(), entries_nr.name(), entries)
|
||||
assert_eq!(
|
||||
entries_nr.element().borrow().id,
|
||||
component.description.original.root_element.borrow().id,
|
||||
"entries need to be in the main element"
|
||||
);
|
||||
component
|
||||
.description
|
||||
.set_binding(component.borrow(), entries_nr.name(), entries)
|
||||
.unwrap();
|
||||
let i = &local_context.component_instance;
|
||||
set_callback_handler(i, &sub_menu_nr.element(), sub_menu_nr.name(), sub_menu)
|
||||
|
|
@ -2011,13 +2018,18 @@ impl Menu for MenuWrapper {
|
|||
}
|
||||
}
|
||||
|
||||
fn menu_item_tree_properties(menu: MenuFromItemTree) -> (Value, CallbackHandler, CallbackHandler) {
|
||||
fn menu_item_tree_properties(
|
||||
menu: MenuFromItemTree,
|
||||
) -> (Box<dyn Fn() -> Value>, CallbackHandler, CallbackHandler) {
|
||||
let context_menu_item_tree = Rc::new(menu);
|
||||
let context_menu_item_tree_ = context_menu_item_tree.clone();
|
||||
let entries = Box::new(move || {
|
||||
let mut entries = SharedVector::default();
|
||||
context_menu_item_tree.sub_menu(None, &mut entries);
|
||||
let entries = Value::Model(ModelRc::new(VecModel::from(
|
||||
context_menu_item_tree_.sub_menu(None, &mut entries);
|
||||
Value::Model(ModelRc::new(VecModel::from(
|
||||
entries.into_iter().map(|x| Value::from(x)).collect::<Vec<_>>(),
|
||||
)));
|
||||
)))
|
||||
});
|
||||
let context_menu_item_tree_ = context_menu_item_tree.clone();
|
||||
let sub_menu = Box::new(move |args: &[Value]| -> Value {
|
||||
let mut entries = SharedVector::default();
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue