mirror of
https://github.com/slint-ui/slint.git
synced 2025-08-04 18:58:36 +00:00
MenuItem with for
and if
This commit is contained in:
parent
e75415554a
commit
010126992e
24 changed files with 889 additions and 258 deletions
|
@ -44,6 +44,11 @@ pub enum BuiltinFunction {
|
|||
ClearFocusItem,
|
||||
ShowPopupWindow,
|
||||
ClosePopupWindow,
|
||||
/// Show a context popup menu.
|
||||
/// Arguments are `(parent, entries, position)`
|
||||
///
|
||||
/// The second argument (entries) can either be of type Array of MenuEntry, or a reference to a MenuItem tree.
|
||||
/// When it is a menu item tree, it is a ElementReference to the root of the tree, and in the LLR, a NumberLiteral to an index in [`crate::llr::SubComponent::menu_item_trees`]
|
||||
ShowPopupMenu,
|
||||
SetSelectionOffsets,
|
||||
/// A function that belongs to an item (such as TextInput's select-all function).
|
||||
|
@ -70,6 +75,10 @@ pub enum BuiltinFunction {
|
|||
Hsv,
|
||||
ColorScheme,
|
||||
SupportsNativeMenuBar,
|
||||
/// Setup the native menu bar, or the item-tree based menu bar
|
||||
/// arguments ate: `(ref entries, ref sub-menu, ref activated, item_tree_root?)`
|
||||
/// When there are 4 arguments, the last one is a reference to the MenuItem tree root (just like the entries in the [`Self::ShowPopupMenu`] call)
|
||||
/// then the code will assign the callback handler and properties
|
||||
SetupNativeMenuBar,
|
||||
Use24HourFormat,
|
||||
MonthDayCount,
|
||||
|
|
|
@ -1306,6 +1306,9 @@ fn generate_public_component(
|
|||
for popup in &sc.popup_windows {
|
||||
add_friends(friends, unit, popup.item_tree.root, false)
|
||||
}
|
||||
for menu in &sc.menu_item_trees {
|
||||
add_friends(friends, unit, menu.root, false)
|
||||
}
|
||||
}
|
||||
|
||||
file.definitions.extend(component_struct.extract_definitions().collect::<Vec<_>>());
|
||||
|
@ -1915,9 +1918,26 @@ fn generate_sub_component(
|
|||
file,
|
||||
conditional_includes,
|
||||
);
|
||||
file.definitions.extend(popup_struct.extract_definitions().collect::<Vec<_>>());
|
||||
file.definitions.extend(popup_struct.extract_definitions());
|
||||
file.declarations.push(Declaration::Struct(popup_struct));
|
||||
});
|
||||
for menu in &component.menu_item_trees {
|
||||
let component_id = ident(&root.sub_components[menu.root].name);
|
||||
let mut menu_struct = Struct { name: component_id.clone(), ..Default::default() };
|
||||
generate_item_tree(
|
||||
&mut menu_struct,
|
||||
menu,
|
||||
root,
|
||||
Some(ParentCtx::new(&ctx, None)),
|
||||
false,
|
||||
component_id,
|
||||
Access::Public,
|
||||
file,
|
||||
conditional_includes,
|
||||
);
|
||||
file.definitions.extend(menu_struct.extract_definitions());
|
||||
file.declarations.push(Declaration::Struct(menu_struct));
|
||||
}
|
||||
|
||||
for property in component.properties.iter().filter(|p| p.use_count.get() > 0) {
|
||||
let cpp_name = ident(&property.name);
|
||||
|
@ -3645,17 +3665,37 @@ fn compile_builtin_function_call(
|
|||
}
|
||||
BuiltinFunction::SetupNativeMenuBar => {
|
||||
let window = access_window_field(ctx);
|
||||
let [entries, llr::Expression::PropertyReference(sub_menu), llr::Expression::PropertyReference(activated)] =
|
||||
arguments
|
||||
else {
|
||||
if let [llr::Expression::PropertyReference(entries_r), llr::Expression::PropertyReference(sub_menu_r), llr::Expression::PropertyReference(activated_r), llr::Expression::NumberLiteral(tree_index)] = arguments {
|
||||
let current_sub_component = ctx.current_sub_component().unwrap();
|
||||
let item_tree_id = ident(&ctx.compilation_unit.sub_components[current_sub_component.menu_item_trees[*tree_index as usize].root].name);
|
||||
let access_entries = access_member(entries_r, ctx);
|
||||
let access_sub_menu = access_member(sub_menu_r, ctx);
|
||||
let access_activated = access_member(activated_r, ctx);
|
||||
format!(r"
|
||||
if ({window}.supports_native_menu_bar()) {{
|
||||
auto item_tree = {item_tree_id}::create(self);
|
||||
auto item_tree_dyn = item_tree.into_dyn();
|
||||
vtable::VBox<slint::cbindgen_private::MenuVTable> box{{}};
|
||||
slint::cbindgen_private::slint_menus_create_wrapper(&item_tree_dyn, &box);
|
||||
slint::cbindgen_private::slint_windowrc_setup_native_menu_bar(&{window}.handle(), const_cast<slint::cbindgen_private::MenuVTable*>(box.vtable), box.instance);
|
||||
// The ownership of the VBox is transferred to slint_windowrc_setup_native_menu_bar
|
||||
box.instance = nullptr;
|
||||
box.vtable = nullptr;
|
||||
}} else {{
|
||||
auto item_tree = {item_tree_id}::create(self);
|
||||
auto item_tree_dyn = item_tree.into_dyn();
|
||||
slint::private_api::setup_popup_menu_from_menu_item_tree(item_tree_dyn, {access_entries}, {access_sub_menu}, {access_activated});
|
||||
}}")
|
||||
} else if let [entries, llr::Expression::PropertyReference(sub_menu), llr::Expression::PropertyReference(activated)] = arguments {
|
||||
let entries = compile_expression(entries, ctx);
|
||||
let sub_menu = access_member(sub_menu, ctx);
|
||||
let activated = access_member(activated, ctx);
|
||||
format!("{window}.setup_native_menu_bar(self,
|
||||
[](auto &self, const slint::cbindgen_private::MenuEntry *parent){{ return parent ? {sub_menu}.call(*parent) : {entries}; }},
|
||||
[](auto &self, const slint::cbindgen_private::MenuEntry &entry){{ {activated}.call(entry); }})")
|
||||
} else {
|
||||
panic!("internal error: incorrect arguments to SetupNativeMenuBar")
|
||||
};
|
||||
let entries = compile_expression(entries, ctx);
|
||||
let sub_menu = access_member(sub_menu, ctx);
|
||||
let activated = access_member(activated, ctx);
|
||||
format!("{window}.setup_native_menu_bar(self,
|
||||
[](auto &self, const slint::cbindgen_private::MenuEntry *parent){{ return parent ? {sub_menu}.call(*parent) : {entries}; }},
|
||||
[](auto &self, const slint::cbindgen_private::MenuEntry &entry){{ {activated}.call(entry); }})")
|
||||
}
|
||||
}
|
||||
BuiltinFunction::Use24HourFormat => {
|
||||
format!("slint::cbindgen_private::slint_date_time_use_24_hour_format()")
|
||||
|
@ -3754,7 +3794,6 @@ fn compile_builtin_function_call(
|
|||
let context_menu = access_member(context_menu_ref, ctx);
|
||||
let context_menu_rc = access_item_rc(context_menu_ref, ctx);
|
||||
let position = compile_expression(position, ctx);
|
||||
let entries = compile_expression(entries, ctx);
|
||||
let popup = ctx
|
||||
.compilation_unit
|
||||
.popup_menu
|
||||
|
@ -3770,25 +3809,39 @@ fn compile_builtin_function_call(
|
|||
None,
|
||||
);
|
||||
let access_entries = access_member(&popup.entries, &popup_ctx);
|
||||
let forward_callback = |pr, cb| {
|
||||
let access = access_member(pr, &popup_ctx);
|
||||
format!("{access}.set_handler(
|
||||
[context_menu](const auto &entry) {{
|
||||
return context_menu->{cb}.call(entry);
|
||||
}});")
|
||||
};
|
||||
let fw_sub_menu = forward_callback(&popup.sub_menu, "sub_menu");
|
||||
let fw_activated = forward_callback(&popup.activated, "activated");
|
||||
let init = format!(r"
|
||||
auto entries = {entries};
|
||||
const slint::cbindgen_private::ContextMenu *context_menu = &({context_menu});
|
||||
{{
|
||||
let access_sub_menu = access_member(&popup.sub_menu, &popup_ctx);
|
||||
let access_activated = access_member(&popup.activated, &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();
|
||||
let item_tree_id = ident(&ctx.compilation_unit.sub_components[current_sub_component.menu_item_trees[*tree_index as usize].root].name);
|
||||
format!(r"
|
||||
auto item_tree = {item_tree_id}::create(self);
|
||||
auto item_tree_dyn = item_tree.into_dyn();
|
||||
auto self = popup_menu;
|
||||
{access_entries}.set(std::move(entries));
|
||||
{fw_sub_menu}
|
||||
{fw_activated}
|
||||
}}");
|
||||
slint::private_api::setup_popup_menu_from_menu_item_tree(item_tree_dyn, {access_entries}, {access_sub_menu}, {access_activated});
|
||||
")
|
||||
|
||||
} else {
|
||||
let forward_callback = |access, cb| {
|
||||
format!("{access}.set_handler(
|
||||
[context_menu](const auto &entry) {{
|
||||
return context_menu->{cb}.call(entry);
|
||||
}});")
|
||||
};
|
||||
let fw_sub_menu = forward_callback(access_sub_menu, "sub_menu");
|
||||
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}
|
||||
}}")
|
||||
};
|
||||
format!("{window}.show_popup_menu<{popup_id}>({globals}, {position}, {{ {context_menu_rc} }}, [self](auto popup_menu) {{ {init} }})", globals = ctx.generator_state.global_access)
|
||||
}
|
||||
BuiltinFunction::SetSelectionOffsets => {
|
||||
|
|
|
@ -696,6 +696,9 @@ fn generate_sub_component(
|
|||
false,
|
||||
)
|
||||
})
|
||||
.chain(component.menu_item_trees.iter().map(|tree| {
|
||||
generate_item_tree(&tree, root, Some(ParentCtx::new(&ctx, None)), None, false)
|
||||
}))
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let mut declared_property_vars = vec![];
|
||||
|
@ -2769,7 +2772,7 @@ fn compile_builtin_function_call(
|
|||
let context_menu = access_member(context_menu_ref, ctx);
|
||||
let context_menu_rc = access_item_rc(context_menu_ref, ctx);
|
||||
let position = compile_expression(position, ctx);
|
||||
let entries = compile_expression(entries, ctx);
|
||||
|
||||
let popup = ctx
|
||||
.compilation_unit
|
||||
.popup_menu
|
||||
|
@ -2786,34 +2789,71 @@ fn compile_builtin_function_call(
|
|||
None,
|
||||
);
|
||||
let access_entries = access_member(&popup.entries, &popup_ctx).unwrap();
|
||||
let forward_callback = |pr, cb| {
|
||||
let access = access_member(pr, &popup_ctx).unwrap();
|
||||
let call = context_menu
|
||||
.clone()
|
||||
.map_or_default(|context_menu| quote!(#context_menu.#cb.call(entry)));
|
||||
quote!(
|
||||
let self_weak = parent_weak.clone();
|
||||
#access.set_handler(move |entry| {
|
||||
let self_rc = self_weak.upgrade().unwrap();
|
||||
let _self = self_rc.as_pin_ref();
|
||||
#call
|
||||
let access_sub_menu = access_member(&popup.sub_menu, &popup_ctx).unwrap();
|
||||
let access_activated = access_member(&popup.activated, &popup_ctx).unwrap();
|
||||
|
||||
let init_popup = if let Expression::NumberLiteral(tree_index) = entries {
|
||||
// We have an MenuItem tree
|
||||
let current_sub_component = ctx.current_sub_component().unwrap();
|
||||
let item_tree_id = inner_component_id(
|
||||
&ctx.compilation_unit.sub_components
|
||||
[current_sub_component.menu_item_trees[*tree_index as usize].root],
|
||||
);
|
||||
quote!({
|
||||
let menu_item_tree_instance = #item_tree_id::new(_self.self_weak.get().unwrap().clone()).unwrap();
|
||||
let context_menu_item_tree = sp::Rc::new(sp::MenuFromItemTree::new(sp::VRc::into_dyn(menu_item_tree_instance)));
|
||||
let mut entries = sp::SharedVector::default();
|
||||
sp::Menu::sub_menu(&*context_menu_item_tree, sp::Option::None, &mut entries);
|
||||
let _self = popup_instance_vrc.as_pin_ref();
|
||||
#access_entries.set(sp::ModelRc::new(sp::SharedVectorModel::from(entries)));
|
||||
let context_menu_item_tree_ = context_menu_item_tree.clone();
|
||||
#access_sub_menu.set_handler(move |entry| {
|
||||
let mut entries = sp::SharedVector::default();
|
||||
sp::Menu::sub_menu(&*context_menu_item_tree_, sp::Option::Some(&entry.0), &mut entries);
|
||||
sp::ModelRc::new(sp::SharedVectorModel::from(entries))
|
||||
});
|
||||
#access_activated.set_handler(move |entry| {
|
||||
sp::Menu::activate(&*context_menu_item_tree, &entry.0);
|
||||
});
|
||||
})
|
||||
} else {
|
||||
// entries should be an expression of type array of MenuEntry
|
||||
debug_assert!(
|
||||
matches!(entries.ty(ctx), Type::Array(ty) if matches!(&*ty, Type::Struct{..}))
|
||||
);
|
||||
let entries = compile_expression(entries, ctx);
|
||||
let forward_callback = |access, cb| {
|
||||
let call = context_menu
|
||||
.clone()
|
||||
.map_or_default(|context_menu| quote!(#context_menu.#cb.call(entry)));
|
||||
quote!(
|
||||
let self_weak = parent_weak.clone();
|
||||
#access.set_handler(move |entry| {
|
||||
let self_rc = self_weak.upgrade().unwrap();
|
||||
let _self = self_rc.as_pin_ref();
|
||||
#call
|
||||
});
|
||||
)
|
||||
};
|
||||
let fw_sub_menu = forward_callback(access_sub_menu, quote!(sub_menu));
|
||||
let fw_activated = forward_callback(access_activated, quote!(activated));
|
||||
quote! {
|
||||
let entries = #entries;
|
||||
{
|
||||
let _self = popup_instance_vrc.as_pin_ref();
|
||||
#access_entries.set(entries);
|
||||
#fw_sub_menu
|
||||
#fw_activated
|
||||
}
|
||||
))
|
||||
}
|
||||
};
|
||||
let fw_sub_menu = forward_callback(&popup.sub_menu, quote!(sub_menu));
|
||||
let fw_activated = forward_callback(&popup.activated, quote!(activated));
|
||||
|
||||
quote!({
|
||||
let entries = #entries;
|
||||
let position = #position;
|
||||
let popup_instance = #popup_id::new(_self.globals.get().unwrap().clone()).unwrap();
|
||||
let popup_instance_vrc = sp::VRc::map(popup_instance.clone(), |x| x);
|
||||
let parent_weak = _self.self_weak.get().unwrap().clone();
|
||||
{
|
||||
let _self = popup_instance_vrc.as_pin_ref();
|
||||
#access_entries.set(entries);
|
||||
#fw_sub_menu;
|
||||
#fw_activated;
|
||||
};
|
||||
#init_popup
|
||||
#popup_id::user_init(popup_instance_vrc.clone());
|
||||
sp::WindowInner::from_pub(#window_adapter_tokens.window()).show_popup(
|
||||
&sp::VRc::into_dyn(popup_instance.into()),
|
||||
|
@ -3023,41 +3063,78 @@ fn compile_builtin_function_call(
|
|||
}
|
||||
BuiltinFunction::SetupNativeMenuBar => {
|
||||
let window_adapter_tokens = access_window_adapter_field(ctx);
|
||||
let [entries, Expression::PropertyReference(sub_menu), Expression::PropertyReference(activated)] =
|
||||
if let [Expression::PropertyReference(entries_r), Expression::PropertyReference(sub_menu_r), Expression::PropertyReference(activated_r), Expression::NumberLiteral(tree_index)] =
|
||||
arguments
|
||||
else {
|
||||
panic!("internal error: incorrect arguments to SetupNativeMenuBar")
|
||||
};
|
||||
let entries = compile_expression(entries, ctx);
|
||||
let sub_menu = access_member(sub_menu, ctx).unwrap();
|
||||
let activated = access_member(activated, ctx).unwrap();
|
||||
let inner_component_id = self::inner_component_id(ctx.current_sub_component().unwrap());
|
||||
quote! {
|
||||
if sp::WindowInner::from_pub(#window_adapter_tokens.window()).supports_native_menu_bar() {
|
||||
// May seem overkill to have an instance of the struct for each call, but there should only be one call per component anyway
|
||||
struct MenuBarWrapper(sp::VWeakMapped<sp::ItemTreeVTable, #inner_component_id>);
|
||||
const _ : () = {
|
||||
use slint::private_unstable_api::re_exports::*;
|
||||
MenuVTable_static!(static VT for MenuBarWrapper);
|
||||
};
|
||||
impl sp::Menu for MenuBarWrapper {
|
||||
fn sub_menu(&self, parent: sp::Option<&sp::MenuEntry>, result: &mut sp::SharedVector<sp::MenuEntry>) {
|
||||
let Some(self_rc) = self.0.upgrade() else { return };
|
||||
let _self = self_rc.as_pin_ref();
|
||||
let model = match parent {
|
||||
None => #entries,
|
||||
Some(parent) => #sub_menu.call(&(parent.clone(),))
|
||||
};
|
||||
*result = model.iter().map(|v| v.try_into().unwrap()).collect();
|
||||
}
|
||||
fn activate(&self, entry: &sp::MenuEntry) {
|
||||
let Some(self_rc) = self.0.upgrade() else { return };
|
||||
let _self = self_rc.as_pin_ref();
|
||||
#activated.call(&(entry.clone(),))
|
||||
}
|
||||
{
|
||||
// We have an MenuItem tree
|
||||
let current_sub_component = ctx.current_sub_component().unwrap();
|
||||
let item_tree_id = inner_component_id(
|
||||
&ctx.compilation_unit.sub_components
|
||||
[current_sub_component.menu_item_trees[*tree_index as usize].root],
|
||||
);
|
||||
|
||||
let access_entries = access_member(entries_r, ctx).unwrap();
|
||||
let access_sub_menu = access_member(sub_menu_r, ctx).unwrap();
|
||||
let access_activated = access_member(activated_r, ctx).unwrap();
|
||||
|
||||
quote!({
|
||||
let menu_item_tree_instance = #item_tree_id::new(_self.self_weak.get().unwrap().clone()).unwrap();
|
||||
let menu_item_tree = sp::MenuFromItemTree::new(sp::VRc::into_dyn(menu_item_tree_instance));
|
||||
if sp::WindowInner::from_pub(#window_adapter_tokens.window()).supports_native_menu_bar() {
|
||||
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 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)));
|
||||
let menu_item_tree_ = menu_item_tree.clone();
|
||||
#access_sub_menu.set_handler(move |entry| {
|
||||
let mut entries = sp::SharedVector::default();
|
||||
sp::Menu::sub_menu(&*menu_item_tree_, sp::Option::Some(&entry.0), &mut entries);
|
||||
sp::ModelRc::new(sp::SharedVectorModel::from(entries))
|
||||
});
|
||||
#access_activated.set_handler(move |entry| {
|
||||
sp::Menu::activate(&*menu_item_tree, &entry.0);
|
||||
});
|
||||
}
|
||||
})
|
||||
} else if let [entries, Expression::PropertyReference(sub_menu), Expression::PropertyReference(activated)] =
|
||||
arguments
|
||||
{
|
||||
let entries = compile_expression(entries, ctx);
|
||||
let sub_menu = access_member(sub_menu, ctx).unwrap();
|
||||
let activated = access_member(activated, ctx).unwrap();
|
||||
let inner_component_id =
|
||||
self::inner_component_id(ctx.current_sub_component().unwrap());
|
||||
quote! {
|
||||
if sp::WindowInner::from_pub(#window_adapter_tokens.window()).supports_native_menu_bar() {
|
||||
// May seem overkill to have an instance of the struct for each call, but there should only be one call per component anyway
|
||||
struct MenuBarWrapper(sp::VWeakMapped<sp::ItemTreeVTable, #inner_component_id>);
|
||||
const _ : () = {
|
||||
use slint::private_unstable_api::re_exports::*;
|
||||
MenuVTable_static!(static VT for MenuBarWrapper);
|
||||
};
|
||||
impl sp::Menu for MenuBarWrapper {
|
||||
fn sub_menu(&self, parent: sp::Option<&sp::MenuEntry>, result: &mut sp::SharedVector<sp::MenuEntry>) {
|
||||
let Some(self_rc) = self.0.upgrade() else { return };
|
||||
let _self = self_rc.as_pin_ref();
|
||||
let model = match parent {
|
||||
None => #entries,
|
||||
Some(parent) => #sub_menu.call(&(parent.clone(),))
|
||||
};
|
||||
*result = model.iter().map(|v| v.try_into().unwrap()).collect();
|
||||
}
|
||||
fn activate(&self, entry: &sp::MenuEntry) {
|
||||
let Some(self_rc) = self.0.upgrade() else { return };
|
||||
let _self = self_rc.as_pin_ref();
|
||||
#activated.call(&(entry.clone(),))
|
||||
}
|
||||
}
|
||||
sp::WindowInner::from_pub(#window_adapter_tokens.window()).setup_menubar(sp::VBox::new(MenuBarWrapper(_self.self_weak.get().unwrap().clone())));
|
||||
}
|
||||
sp::WindowInner::from_pub(#window_adapter_tokens.window()).setup_menubar(sp::VBox::new(MenuBarWrapper(_self.self_weak.get().unwrap().clone())));
|
||||
}
|
||||
} else {
|
||||
panic!("internal error: incorrect arguments to SetupNativeMenuBar")
|
||||
}
|
||||
}
|
||||
BuiltinFunction::MonthDayCount => {
|
||||
|
|
|
@ -256,6 +256,8 @@ pub struct SubComponent {
|
|||
pub repeated: TiVec<RepeatedElementIdx, RepeatedElement>,
|
||||
pub component_containers: Vec<ComponentContainerElement>,
|
||||
pub popup_windows: Vec<PopupWindow>,
|
||||
/// The MenuItem trees. The index is stored in a Expression::NumberLiteral in the arguments of BuiltinFunction::ShowPopupMenu and BuiltinFunction::SetupNativeMenuBar
|
||||
pub menu_item_trees: Vec<ItemTree>,
|
||||
pub timers: Vec<Timer>,
|
||||
pub sub_components: TiVec<SubComponentInstanceIdx, SubComponentInstance>,
|
||||
/// The initial value or binding for properties.
|
||||
|
@ -417,6 +419,9 @@ impl CompilationUnit {
|
|||
Some(ParentCtx::new(&ctx, None)),
|
||||
);
|
||||
}
|
||||
for menu_tree in &sc.menu_item_trees {
|
||||
visit_component(root, menu_tree.root, visitor, Some(ParentCtx::new(&ctx, None)));
|
||||
}
|
||||
}
|
||||
for c in &self.used_sub_components {
|
||||
visit_component(self, *c, visitor, None);
|
||||
|
|
|
@ -7,7 +7,6 @@ use std::num::NonZeroUsize;
|
|||
use std::rc::{Rc, Weak};
|
||||
|
||||
use itertools::Either;
|
||||
|
||||
use smol_str::{format_smolstr, SmolStr};
|
||||
|
||||
use super::lower_to_item_tree::{LoweredElement, LoweredSubComponentMapping, LoweringState};
|
||||
|
@ -81,11 +80,25 @@ pub fn lower_expression(
|
|||
llr_Expression::PropertyReference(ctx.map_property_reference(nr))
|
||||
}
|
||||
tree_Expression::ElementReference(e) => {
|
||||
let elem = e.upgrade().unwrap();
|
||||
let enclosing = elem.borrow().enclosing_component.upgrade().unwrap();
|
||||
// When within a ShowPopupMenu builtin function, this is a reference to the root of the menu item tree
|
||||
if Rc::ptr_eq(&elem, &enclosing.root_element) {
|
||||
if let Some(idx) = ctx
|
||||
.component
|
||||
.menu_item_tree
|
||||
.borrow()
|
||||
.iter()
|
||||
.position(|c| Rc::ptr_eq(c, &enclosing))
|
||||
{
|
||||
return llr_Expression::NumberLiteral(idx as _);
|
||||
}
|
||||
}
|
||||
|
||||
// We map an element reference to a reference to the property "" inside that native item
|
||||
llr_Expression::PropertyReference(ctx.map_property_reference(&NamedReference::new(
|
||||
&e.upgrade().unwrap(),
|
||||
SmolStr::default(),
|
||||
)))
|
||||
llr_Expression::PropertyReference(
|
||||
ctx.map_property_reference(&NamedReference::new(&elem, SmolStr::default())),
|
||||
)
|
||||
}
|
||||
tree_Expression::RepeaterIndexReference { element } => {
|
||||
repeater_special_property(element, ctx.component, 1usize.into())
|
||||
|
@ -118,9 +131,11 @@ pub fn lower_expression(
|
|||
llr_Expression::CodeBlock(expr.iter().map(|e| lower_expression(e, ctx)).collect::<_>())
|
||||
}
|
||||
tree_Expression::FunctionCall { function, arguments, .. } => match function {
|
||||
Callable::Builtin(BuiltinFunction::ShowPopupWindow) => lower_show_popup(arguments, ctx),
|
||||
Callable::Builtin(BuiltinFunction::ShowPopupWindow) => {
|
||||
lower_show_popup_window(arguments, ctx)
|
||||
}
|
||||
Callable::Builtin(BuiltinFunction::ClosePopupWindow) => {
|
||||
lower_close_popup(arguments, ctx)
|
||||
lower_close_popup_window(arguments, ctx)
|
||||
}
|
||||
Callable::Builtin(f) => {
|
||||
let mut arguments =
|
||||
|
@ -354,7 +369,10 @@ fn repeater_special_property(
|
|||
llr_Expression::PropertyReference(r)
|
||||
}
|
||||
|
||||
fn lower_show_popup(args: &[tree_Expression], ctx: &mut ExpressionLoweringCtx) -> llr_Expression {
|
||||
fn lower_show_popup_window(
|
||||
args: &[tree_Expression],
|
||||
ctx: &mut ExpressionLoweringCtx,
|
||||
) -> llr_Expression {
|
||||
if let [tree_Expression::ElementReference(e)] = args {
|
||||
let popup_window = e.upgrade().unwrap();
|
||||
let pop_comp = popup_window.borrow().enclosing_component.upgrade().unwrap();
|
||||
|
@ -390,7 +408,10 @@ fn lower_show_popup(args: &[tree_Expression], ctx: &mut ExpressionLoweringCtx) -
|
|||
}
|
||||
}
|
||||
|
||||
fn lower_close_popup(args: &[tree_Expression], ctx: &mut ExpressionLoweringCtx) -> llr_Expression {
|
||||
fn lower_close_popup_window(
|
||||
args: &[tree_Expression],
|
||||
ctx: &mut ExpressionLoweringCtx,
|
||||
) -> llr_Expression {
|
||||
if let [tree_Expression::ElementReference(e)] = args {
|
||||
let popup_window = e.upgrade().unwrap();
|
||||
let pop_comp = popup_window.borrow().enclosing_component.upgrade().unwrap();
|
||||
|
|
|
@ -43,7 +43,7 @@ pub fn lower_to_item_tree(
|
|||
|
||||
for c in &document.used_types.borrow().sub_components {
|
||||
let sc = lower_sub_component(c, &mut state, None, compiler_config);
|
||||
let idx = state.sub_components.push_and_get_key(sc);
|
||||
let idx = state.push_sub_component(sc);
|
||||
state.sub_component_mapping.insert(ByAddress(c.clone()), idx);
|
||||
}
|
||||
|
||||
|
@ -55,7 +55,7 @@ pub fn lower_to_item_tree(
|
|||
sc.sub_component.name = component.id.clone();
|
||||
let item_tree = ItemTree {
|
||||
tree: make_tree(&state, &component.root_element, &sc, &[]),
|
||||
root: state.sub_components.push_and_get_key(sc),
|
||||
root: state.push_sub_component(sc),
|
||||
parent_context: None,
|
||||
};
|
||||
// For C++ codegen, the root component must have the same name as the public component
|
||||
|
@ -84,7 +84,7 @@ pub fn lower_to_item_tree(
|
|||
);
|
||||
let item_tree = ItemTree {
|
||||
tree: make_tree(&state, &c.root_element, &sc, &[]),
|
||||
root: state.sub_components.push_and_get_key(sc),
|
||||
root: state.push_sub_component(sc),
|
||||
parent_context: None,
|
||||
};
|
||||
PopupMenu { item_tree, sub_menu, activated, entries }
|
||||
|
@ -182,7 +182,7 @@ pub struct LoweredSubComponent {
|
|||
pub struct LoweringState {
|
||||
global_properties: HashMap<NamedReference, PropertyReference>,
|
||||
sub_components: TiVec<SubComponentIdx, LoweredSubComponent>,
|
||||
sub_component_mapping: HashMap<ByAddress<Rc<Component>>, SubComponentIdx>,
|
||||
pub sub_component_mapping: HashMap<ByAddress<Rc<Component>>, SubComponentIdx>,
|
||||
#[cfg(feature = "bundle-translations")]
|
||||
pub translation_builder: Option<super::translations::TranslationsBuilder>,
|
||||
}
|
||||
|
@ -252,6 +252,7 @@ fn lower_sub_component(
|
|||
repeated: Default::default(),
|
||||
component_containers: Default::default(),
|
||||
popup_windows: Default::default(),
|
||||
menu_item_trees: Vec::new(),
|
||||
timers: Default::default(),
|
||||
sub_components: Default::default(),
|
||||
property_init: Default::default(),
|
||||
|
@ -402,8 +403,10 @@ fn lower_sub_component(
|
|||
|
||||
Some(element.clone())
|
||||
});
|
||||
|
||||
let inner = ExpressionLoweringCtxInner { mapping: &mapping, parent: parent_context, component };
|
||||
let mut ctx = ExpressionLoweringCtx { inner, state };
|
||||
|
||||
crate::generator::handle_property_bindings_init(component, |e, p, binding| {
|
||||
let nr = NamedReference::new(e, p.clone());
|
||||
let prop = ctx.map_property_reference(&nr);
|
||||
|
@ -498,6 +501,20 @@ fn lower_sub_component(
|
|||
.map(|popup| lower_popup_component(popup, &mut ctx, compiler_config))
|
||||
.collect();
|
||||
|
||||
sub_component.menu_item_trees = component
|
||||
.menu_item_tree
|
||||
.borrow()
|
||||
.iter()
|
||||
.map(|c| {
|
||||
let sc = lower_sub_component(c, ctx.state, Some(&ctx.inner), compiler_config);
|
||||
ItemTree {
|
||||
tree: make_tree(&ctx.state, &c.root_element, &sc, &[]),
|
||||
root: ctx.state.push_sub_component(sc),
|
||||
parent_context: None,
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
|
||||
sub_component.timers =
|
||||
component.timers.borrow().iter().map(|t| lower_timer(t, &mut ctx)).collect();
|
||||
|
||||
|
@ -651,16 +668,17 @@ fn lower_repeated_component(
|
|||
|
||||
let sc = lower_sub_component(&component, ctx.state, Some(&ctx.inner), compiler_config);
|
||||
|
||||
let geom = component.root_element.borrow().geometry_props.clone().unwrap();
|
||||
|
||||
let listview = repeated.is_listview.as_ref().map(|lv| ListViewInfo {
|
||||
viewport_y: ctx.map_property_reference(&lv.viewport_y),
|
||||
viewport_height: ctx.map_property_reference(&lv.viewport_height),
|
||||
viewport_width: ctx.map_property_reference(&lv.viewport_width),
|
||||
listview_height: ctx.map_property_reference(&lv.listview_height),
|
||||
listview_width: ctx.map_property_reference(&lv.listview_width),
|
||||
prop_y: sc.mapping.map_property_reference(&geom.y, ctx.state),
|
||||
prop_height: sc.mapping.map_property_reference(&geom.height, ctx.state),
|
||||
let listview = repeated.is_listview.as_ref().map(|lv| {
|
||||
let geom = component.root_element.borrow().geometry_props.clone().unwrap();
|
||||
ListViewInfo {
|
||||
viewport_y: ctx.map_property_reference(&lv.viewport_y),
|
||||
viewport_height: ctx.map_property_reference(&lv.viewport_height),
|
||||
viewport_width: ctx.map_property_reference(&lv.viewport_width),
|
||||
listview_height: ctx.map_property_reference(&lv.listview_height),
|
||||
listview_width: ctx.map_property_reference(&lv.listview_width),
|
||||
prop_y: sc.mapping.map_property_reference(&geom.y, ctx.state),
|
||||
prop_height: sc.mapping.map_property_reference(&geom.height, ctx.state),
|
||||
}
|
||||
});
|
||||
|
||||
RepeatedElement {
|
||||
|
|
|
@ -103,6 +103,10 @@ impl<'a> PrettyPrinter<'a> {
|
|||
write!(self.writer, "for in {} : ", DisplayExpression(&r.model.borrow(), &ctx))?;
|
||||
self.print_component(root, r.sub_tree.root, Some(ParentCtx::new(&ctx, Some(idx))))?
|
||||
}
|
||||
for t in &sc.menu_item_trees {
|
||||
self.indent()?;
|
||||
self.print_component(root, t.root, Some(ParentCtx::new(&ctx, None)))?
|
||||
}
|
||||
for w in &sc.popup_windows {
|
||||
self.indent()?;
|
||||
self.print_component(root, w.item_tree.root, Some(ParentCtx::new(&ctx, None)))?
|
||||
|
|
|
@ -383,6 +383,7 @@ pub struct Component {
|
|||
|
||||
pub popup_windows: RefCell<Vec<PopupWindow>>,
|
||||
pub timers: RefCell<Vec<Timer>>,
|
||||
pub menu_item_tree: RefCell<Vec<Rc<Component>>>,
|
||||
|
||||
/// This component actually inherits PopupWindow (although that has been changed to a Window by the lower_popups pass)
|
||||
pub inherits_popup_window: Cell<bool>,
|
||||
|
@ -2153,7 +2154,12 @@ pub fn recurse_elem_including_sub_components<State>(
|
|||
.popup_windows
|
||||
.borrow()
|
||||
.iter()
|
||||
.for_each(|p| recurse_elem_including_sub_components(&p.component, state, vis))
|
||||
.for_each(|p| recurse_elem_including_sub_components(&p.component, state, vis));
|
||||
component
|
||||
.menu_item_tree
|
||||
.borrow()
|
||||
.iter()
|
||||
.for_each(|c| recurse_elem_including_sub_components(c, state, vis));
|
||||
}
|
||||
|
||||
/// Same as recurse_elem, but will take the children from the element as to not keep the element borrow
|
||||
|
|
|
@ -30,6 +30,10 @@ pub fn default_geometry(root_component: &Rc<Component>, diag: &mut BuildDiagnost
|
|||
if elem.borrow().repeated.is_some() {
|
||||
return None;
|
||||
}
|
||||
if elem.borrow().geometry_props.is_none() {
|
||||
// Not an element with geometry, skip it
|
||||
return None;
|
||||
}
|
||||
|
||||
// whether the width, or height, is filling the parent
|
||||
let (mut w100, mut h100) = (false, false);
|
||||
|
|
|
@ -41,6 +41,9 @@ pub fn generate_item_indices(component: &Rc<Component>) {
|
|||
for p in component.popup_windows.borrow().iter() {
|
||||
generate_item_indices(&p.component)
|
||||
}
|
||||
for c in component.menu_item_tree.borrow().iter() {
|
||||
generate_item_indices(c);
|
||||
}
|
||||
}
|
||||
|
||||
struct Helper {
|
||||
|
|
|
@ -402,6 +402,7 @@ fn duplicate_sub_component(
|
|||
init_code: component_to_duplicate.init_code.clone(),
|
||||
popup_windows: Default::default(),
|
||||
timers: component_to_duplicate.timers.clone(),
|
||||
menu_item_tree: Default::default(),
|
||||
exported_global_names: component_to_duplicate.exported_global_names.clone(),
|
||||
used: component_to_duplicate.used.clone(),
|
||||
private_properties: Default::default(),
|
||||
|
@ -431,6 +432,16 @@ fn duplicate_sub_component(
|
|||
fixup_reference(&mut t.running, mapping);
|
||||
fixup_reference(&mut t.triggered, mapping);
|
||||
}
|
||||
*new_component.menu_item_tree.borrow_mut() = component_to_duplicate
|
||||
.menu_item_tree
|
||||
.borrow()
|
||||
.iter()
|
||||
.map(|it| {
|
||||
let new_parent =
|
||||
mapping.get(&element_key(it.parent_element.upgrade().unwrap())).unwrap().clone();
|
||||
duplicate_sub_component(it, &new_parent, mapping, priority_delta)
|
||||
})
|
||||
.collect();
|
||||
new_component
|
||||
.root_constraints
|
||||
.borrow_mut()
|
||||
|
|
|
@ -81,7 +81,7 @@ use crate::object_tree::*;
|
|||
use core::cell::RefCell;
|
||||
use smol_str::{format_smolstr, SmolStr};
|
||||
use std::collections::HashMap;
|
||||
use std::rc::Rc;
|
||||
use std::rc::{Rc, Weak};
|
||||
|
||||
const HEIGHT: &str = "height";
|
||||
const ENTRIES: &str = "entries";
|
||||
|
@ -153,7 +153,11 @@ pub async fn lower_menus(
|
|||
None => diag.push_error(format!("PopupMenuImpl doesn't have {prop}"), &*root),
|
||||
}
|
||||
}
|
||||
root.property_analysis.borrow_mut().entry("entries".into()).or_default().is_set = true;
|
||||
root.property_analysis
|
||||
.borrow_mut()
|
||||
.entry(SmolStr::new_static(ENTRIES))
|
||||
.or_default()
|
||||
.is_set = true;
|
||||
}
|
||||
|
||||
recurse_elem_including_sub_components_no_borrow(&popup_menu_impl, &(), &mut |elem, _| {
|
||||
|
@ -173,7 +177,7 @@ fn process_context_menu(
|
|||
) -> bool {
|
||||
let is_internal = matches!(&context_menu_elem.borrow().base_type, ElementType::Builtin(b) if b.name == "ContextMenuInternal");
|
||||
|
||||
if !is_internal {
|
||||
let item_tree_root = if !is_internal {
|
||||
// Lower MenuItem's into entries
|
||||
let menu_item = context_menu_elem
|
||||
.borrow()
|
||||
|
@ -196,9 +200,13 @@ fn process_context_menu(
|
|||
true
|
||||
}
|
||||
});
|
||||
if !items.is_empty() {
|
||||
lower_menu_items(context_menu_elem, items, &components.menu_entry, diag);
|
||||
}
|
||||
|
||||
let item_tree_root = if !items.is_empty() {
|
||||
lower_menu_items(context_menu_elem, items, &components)
|
||||
.map(|c| Expression::ElementReference(Rc::downgrade(&c.root_element)))
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
for (name, _) in &components.context_menu_internal.property_list() {
|
||||
if let Some(decl) = context_menu_elem.borrow().property_declarations.get(name) {
|
||||
|
@ -208,13 +216,25 @@ fn process_context_menu(
|
|||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Materialize the entries property
|
||||
context_menu_elem.borrow_mut().property_declarations.insert(
|
||||
SmolStr::new_static(ENTRIES),
|
||||
Type::Array(components.menu_entry.clone().into()).into(),
|
||||
);
|
||||
item_tree_root
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
let entries = if let Some(item_tree_root) = item_tree_root {
|
||||
item_tree_root
|
||||
} else {
|
||||
// Materialize the entries property
|
||||
context_menu_elem.borrow_mut().property_declarations.insert(
|
||||
SmolStr::new_static(ENTRIES),
|
||||
Type::Array(components.menu_entry.clone().into()).into(),
|
||||
);
|
||||
Expression::PropertyReference(NamedReference::new(
|
||||
&context_menu_elem,
|
||||
SmolStr::new_static(ENTRIES),
|
||||
))
|
||||
};
|
||||
|
||||
// generate the show callback
|
||||
let source_location = Some(context_menu_elem.borrow().to_source_location());
|
||||
|
@ -222,10 +242,7 @@ fn process_context_menu(
|
|||
function: BuiltinFunction::ShowPopupMenu.into(),
|
||||
arguments: vec![
|
||||
Expression::ElementReference(Rc::downgrade(context_menu_elem)),
|
||||
Expression::PropertyReference(NamedReference::new(
|
||||
&context_menu_elem,
|
||||
SmolStr::new_static(ENTRIES),
|
||||
)),
|
||||
entries,
|
||||
Expression::FunctionParameterReference {
|
||||
index: 0,
|
||||
ty: crate::typeregister::logical_point_type(),
|
||||
|
@ -276,9 +293,12 @@ fn process_window(
|
|||
|
||||
// Lower MenuItem's into entries
|
||||
let children = std::mem::take(&mut menu_bar.borrow_mut().children);
|
||||
if !children.is_empty() {
|
||||
lower_menu_items(&menu_bar, children, &components.menu_entry, diag);
|
||||
}
|
||||
let item_tree_root = if !children.is_empty() {
|
||||
lower_menu_items(&menu_bar, children, &components)
|
||||
.map(|c| Expression::ElementReference(Rc::downgrade(&c.root_element)))
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
let menubar_impl = Element {
|
||||
id: format_smolstr!("{}-menulayout", window.id),
|
||||
|
@ -353,22 +373,34 @@ fn process_window(
|
|||
menu_bar.borrow_mut().base_type = components.vertical_layout.clone();
|
||||
menu_bar.borrow_mut().children = vec![menubar_impl, child];
|
||||
|
||||
let mut arguments = vec![
|
||||
Expression::PropertyReference(NamedReference::new(&menu_bar, SmolStr::new_static(ENTRIES))),
|
||||
Expression::PropertyReference(NamedReference::new(
|
||||
&menu_bar,
|
||||
SmolStr::new_static(SUB_MENU),
|
||||
)),
|
||||
Expression::PropertyReference(NamedReference::new(
|
||||
&menu_bar,
|
||||
SmolStr::new_static(ACTIVATED),
|
||||
)),
|
||||
];
|
||||
|
||||
if let Some(item_tree_root) = item_tree_root {
|
||||
arguments.push(item_tree_root.into());
|
||||
for prop in [ENTRIES, SUB_MENU, ACTIVATED] {
|
||||
menu_bar
|
||||
.borrow()
|
||||
.property_analysis
|
||||
.borrow_mut()
|
||||
.entry(SmolStr::new_static(prop))
|
||||
.or_default()
|
||||
.is_set = true;
|
||||
}
|
||||
}
|
||||
|
||||
let setup_menubar = Expression::FunctionCall {
|
||||
function: BuiltinFunction::SetupNativeMenuBar.into(),
|
||||
arguments: vec![
|
||||
Expression::PropertyReference(NamedReference::new(
|
||||
&menu_bar,
|
||||
SmolStr::new_static(ENTRIES),
|
||||
)),
|
||||
Expression::PropertyReference(NamedReference::new(
|
||||
&menu_bar,
|
||||
SmolStr::new_static(SUB_MENU),
|
||||
)),
|
||||
Expression::PropertyReference(NamedReference::new(
|
||||
&menu_bar,
|
||||
SmolStr::new_static(ACTIVATED),
|
||||
)),
|
||||
],
|
||||
arguments,
|
||||
source_location: source_location.clone(),
|
||||
};
|
||||
|
||||
|
@ -390,43 +422,94 @@ fn process_window(
|
|||
true
|
||||
}
|
||||
|
||||
/// Lower the MenuItem to either
|
||||
/// - `entries` and `activated` and `sub-menu` properties/callback, in which cases it returns None
|
||||
/// - or a Component which is a tree of MenuItem, in which case returns the component that is within the enclosing component's menu_item_trees
|
||||
fn lower_menu_items(
|
||||
parent: &ElementRc,
|
||||
children: Vec<ElementRc>,
|
||||
menu_entry: &Type,
|
||||
diag: &mut BuildDiagnostics,
|
||||
) {
|
||||
let mut state = GenMenuState {
|
||||
id: 0,
|
||||
menu_entry: menu_entry.clone(),
|
||||
diag,
|
||||
activate: Vec::new(),
|
||||
sub_menu: Vec::new(),
|
||||
};
|
||||
parent.borrow_mut().bindings.insert(
|
||||
ENTRIES.into(),
|
||||
RefCell::new(
|
||||
Expression::Array {
|
||||
element_ty: menu_entry.clone(),
|
||||
values: generate_menu_entries(children.into_iter(), &mut state),
|
||||
components: &UsefulMenuComponents,
|
||||
) -> Option<Rc<Component>> {
|
||||
let mut has_repeated = false;
|
||||
for i in &children {
|
||||
recurse_elem(&i, &(), &mut |e, _| {
|
||||
if e.borrow().repeated.is_some() {
|
||||
has_repeated = true;
|
||||
}
|
||||
.into(),
|
||||
),
|
||||
);
|
||||
let entry_id = Expression::StructFieldAccess {
|
||||
base: Expression::FunctionParameterReference { index: 0, ty: menu_entry.clone() }.into(),
|
||||
name: SmolStr::new_static("id"),
|
||||
};
|
||||
});
|
||||
if has_repeated {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if !has_repeated {
|
||||
let menu_entry = &components.menu_entry;
|
||||
let mut state = GenMenuState {
|
||||
id: 0,
|
||||
menu_entry: menu_entry.clone(),
|
||||
activate: Vec::new(),
|
||||
sub_menu: Vec::new(),
|
||||
};
|
||||
let entries = generate_menu_entries(children.into_iter(), &mut state);
|
||||
parent.borrow_mut().bindings.insert(
|
||||
ENTRIES.into(),
|
||||
RefCell::new(
|
||||
Expression::Array { element_ty: menu_entry.clone(), values: entries }.into(),
|
||||
),
|
||||
);
|
||||
let entry_id = Expression::StructFieldAccess {
|
||||
base: Expression::FunctionParameterReference { index: 0, ty: menu_entry.clone() }
|
||||
.into(),
|
||||
name: SmolStr::new_static("id"),
|
||||
};
|
||||
|
||||
let sub_entries = build_cases_function(
|
||||
&entry_id,
|
||||
Expression::Array { element_ty: menu_entry.clone(), values: vec![] },
|
||||
state.sub_menu,
|
||||
);
|
||||
parent.borrow_mut().bindings.insert(SUB_MENU.into(), RefCell::new(sub_entries.into()));
|
||||
let sub_entries = build_cases_function(
|
||||
&entry_id,
|
||||
Expression::Array { element_ty: menu_entry.clone(), values: vec![] },
|
||||
state.sub_menu,
|
||||
);
|
||||
parent.borrow_mut().bindings.insert(SUB_MENU.into(), RefCell::new(sub_entries.into()));
|
||||
|
||||
let activated = build_cases_function(&entry_id, Expression::CodeBlock(vec![]), state.activate);
|
||||
parent.borrow_mut().bindings.insert(ACTIVATED.into(), RefCell::new(activated.into()));
|
||||
let activated =
|
||||
build_cases_function(&entry_id, Expression::CodeBlock(vec![]), state.activate);
|
||||
parent.borrow_mut().bindings.insert(ACTIVATED.into(), RefCell::new(activated.into()));
|
||||
None
|
||||
} else {
|
||||
let component = Rc::new_cyclic(|component_weak| {
|
||||
let root_element = Rc::new(RefCell::new(Element {
|
||||
base_type: components.empty.clone(),
|
||||
children,
|
||||
enclosing_component: component_weak.clone(),
|
||||
..Default::default()
|
||||
}));
|
||||
recurse_elem(&root_element, &true, &mut |element: &ElementRc, is_root| {
|
||||
if !is_root {
|
||||
debug_assert!(Weak::ptr_eq(
|
||||
&element.borrow().enclosing_component,
|
||||
&parent.borrow().enclosing_component
|
||||
));
|
||||
element.borrow_mut().enclosing_component = component_weak.clone();
|
||||
element.borrow_mut().geometry_props = None;
|
||||
}
|
||||
false
|
||||
});
|
||||
Component {
|
||||
node: parent.borrow().debug.first().map(|n| n.node.clone().into()),
|
||||
id: SmolStr::default(),
|
||||
root_element,
|
||||
parent_element: Rc::downgrade(&parent),
|
||||
..Default::default()
|
||||
}
|
||||
});
|
||||
parent
|
||||
.borrow()
|
||||
.enclosing_component
|
||||
.upgrade()
|
||||
.unwrap()
|
||||
.menu_item_tree
|
||||
.borrow_mut()
|
||||
.push(component.clone());
|
||||
Some(component)
|
||||
}
|
||||
}
|
||||
|
||||
fn build_cases_function(
|
||||
|
@ -450,7 +533,7 @@ fn build_cases_function(
|
|||
result
|
||||
}
|
||||
|
||||
struct GenMenuState<'a> {
|
||||
struct GenMenuState {
|
||||
id: usize,
|
||||
/// Maps `entry.id` to the callback
|
||||
activate: Vec<(SmolStr, Expression)>,
|
||||
|
@ -458,12 +541,12 @@ struct GenMenuState<'a> {
|
|||
sub_menu: Vec<(SmolStr, Expression)>,
|
||||
|
||||
menu_entry: Type,
|
||||
diag: &'a mut BuildDiagnostics,
|
||||
}
|
||||
|
||||
/// Recursively generate the menu entries for the given menu items
|
||||
fn generate_menu_entries(
|
||||
menu_items: impl Iterator<Item = ElementRc>,
|
||||
state: &mut GenMenuState<'_>,
|
||||
state: &mut GenMenuState,
|
||||
) -> Vec<Expression> {
|
||||
let mut entries = Vec::new();
|
||||
|
||||
|
@ -479,13 +562,7 @@ fn generate_menu_entries(
|
|||
.borrow_mut()
|
||||
.push(item.clone());
|
||||
|
||||
if borrow_mut.repeated.is_some() {
|
||||
state.diag.push_error(
|
||||
"'for' and 'if' in MenuItem is not yet implemented".into(),
|
||||
&*borrow_mut,
|
||||
);
|
||||
continue;
|
||||
}
|
||||
assert!(borrow_mut.repeated.is_none());
|
||||
|
||||
let mut values = HashMap::<SmolStr, Expression>::new();
|
||||
for prop in ["title"] {
|
||||
|
|
|
@ -28,6 +28,7 @@ pub fn move_declarations(component: &Rc<Component>) {
|
|||
fn do_move_declarations(component: &Rc<Component>) {
|
||||
let mut decl = Declarations::take_from_element(&mut component.root_element.borrow_mut());
|
||||
component.popup_windows.borrow().iter().for_each(|f| do_move_declarations(&f.component));
|
||||
component.menu_item_tree.borrow().iter().for_each(|f| do_move_declarations(f));
|
||||
|
||||
let mut new_root_bindings = HashMap::new();
|
||||
let mut new_root_change_callbacks = HashMap::new();
|
||||
|
@ -102,6 +103,9 @@ fn do_move_declarations(component: &Rc<Component>) {
|
|||
fixup_reference(&mut t.running);
|
||||
fixup_reference(&mut t.triggered);
|
||||
});
|
||||
component.menu_item_tree.borrow_mut().iter_mut().for_each(|c| {
|
||||
visit_all_named_references(c, &mut fixup_reference);
|
||||
});
|
||||
component.init_code.borrow_mut().iter_mut().for_each(|expr| {
|
||||
visit_named_references_in_expression(expr, &mut fixup_reference);
|
||||
});
|
||||
|
|
|
@ -98,6 +98,9 @@ fn create_repeater_components(component: &Rc<Component>) {
|
|||
for p in component.popup_windows.borrow().iter() {
|
||||
create_repeater_components(&p.component);
|
||||
}
|
||||
for c in component.menu_item_tree.borrow().iter() {
|
||||
create_repeater_components(c);
|
||||
}
|
||||
}
|
||||
|
||||
/// Make sure that references to property within the repeated element actually point to the reference
|
||||
|
|
|
@ -343,7 +343,13 @@ impl Snapshotter {
|
|||
let root_constraints = RefCell::new(
|
||||
self.snapshot_layout_constraints(&component.root_constraints.borrow()),
|
||||
);
|
||||
|
||||
let menu_item_tree = component
|
||||
.menu_item_tree
|
||||
.borrow()
|
||||
.iter()
|
||||
.map(|it| self.create_component(it))
|
||||
.collect::<Vec<_>>()
|
||||
.into();
|
||||
object_tree::Component {
|
||||
node: component.node.clone(),
|
||||
id: component.id.clone(),
|
||||
|
@ -358,6 +364,7 @@ impl Snapshotter {
|
|||
parent_element,
|
||||
popup_windows,
|
||||
timers,
|
||||
menu_item_tree,
|
||||
private_properties: RefCell::new(component.private_properties.borrow().clone()),
|
||||
root_constraints,
|
||||
root_element,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue