Add the MenuItem Element type to be added to MenuBar and ContextMenu

This commit is contained in:
Olivier Goffart 2025-01-23 16:26:45 +01:00
parent 8cf6f97962
commit c0fe0be643
5 changed files with 64 additions and 6 deletions

View file

@ -183,6 +183,17 @@ export component SwipeGestureHandler {
//-default_size_binding:expands_to_parent_geometry
}
// Fake
component MenuItem {
in property <string> title;
callback activated();
MenuItem {}
//-disallow_global_types_as_child_elements
//-is_non_item_type
}
// Lowered in lower_menus pass. See that pass documentation for more info
component MenuBar {
//-is_non_item_type
@ -192,6 +203,8 @@ component MenuBar {
callback activated(entry: MenuEntry);
callback sub-menu(entry: MenuEntry) -> [MenuEntry];
MenuItem {}
// Currently experimental
}
@ -205,6 +218,8 @@ export component ContextMenu {
callback sub-menu(entry: MenuEntry) -> [MenuEntry];
//-default_size_binding:expands_to_parent_geometry
MenuItem {}
// Currently experimental
}

View file

@ -521,9 +521,14 @@ impl ElementType {
if builtin.disallow_global_types_as_child_elements {
if let Some(child_type) = builtin.additional_accepted_child_types.get(name) {
return Ok(child_type.clone().into());
} else if builtin.additional_accept_self && name == builtin.native_class.class_name {
return Ok(builtin.clone().into());
}
let mut valid_children: Vec<_> =
builtin.additional_accepted_child_types.keys().cloned().collect();
if builtin.additional_accept_self {
valid_children.push(builtin.native_class.class_name.clone());
}
valid_children.sort();
let err = if valid_children.is_empty() {
@ -552,6 +557,8 @@ impl ElementType {
};
if let Some(child_type) = builtin.additional_accepted_child_types.get(name) {
return Ok(child_type.clone().into());
} else if builtin.additional_accept_self && name == builtin.native_class.class_name {
return Ok(builtin.clone().into());
}
match tr.lookup(name) {
Type::Invalid => Err(err),
@ -714,7 +721,11 @@ pub struct BuiltinElement {
pub name: SmolStr,
pub native_class: Rc<NativeClass>,
pub properties: BTreeMap<SmolStr, BuiltinPropertyInfo>,
/// Additional builtin element that can be accpeted as child of this element
/// (example `Tab` in `TabWidget`, `Row` in `GridLayout` and the path elements in `Path`)
pub additional_accepted_child_types: HashMap<SmolStr, Rc<BuiltinElement>>,
/// `Self` is conceptually in `additional_accepted_child_types` (which it can't otherwise that'd make a Rc loop)
pub additional_accept_self: bool,
pub disallow_global_types_as_child_elements: bool,
/// Non-item type do not have reserved properties (x/width/rowspan/...) added to them (eg: PropertyAnimation)
pub is_non_item_type: bool,

View file

@ -152,6 +152,10 @@ pub(crate) fn load_builtins(register: &mut TypeRegister) {
} else if let Some(base) = e.QualifiedName() {
let base = QualifiedTypeName::from_node(base).to_smolstr();
let base = natives.get(&base).unwrap().clone();
// because they are not taken from if we inherit from it
assert!(
base.additional_accepted_child_types.is_empty() && !base.additional_accept_self
);
n.parent = Some(base.native_class.clone());
Base::NativeParent(base)
} else {
@ -195,10 +199,15 @@ pub(crate) fn load_builtins(register: &mut TypeRegister) {
.unwrap_or(DefaultSizeBinding::None);
builtin.additional_accepted_child_types = e
.SubElement()
.map(|s| {
.filter_map(|s| {
let a = identifier_text(&s.Element().QualifiedName().unwrap()).unwrap();
let t = natives[&a].clone();
(a, t)
if a == builtin.native_class.class_name {
builtin.additional_accept_self = true;
None
} else {
let t = natives[&a].clone();
Some((a, t))
}
})
.collect();
if let Some(builtin_name) = exports.get(&id) {
@ -218,8 +227,6 @@ pub(crate) fn load_builtins(register: &mut TypeRegister) {
register.add(glob);
}
} else {
// because they are not taken from if we inherit from it
assert!(builtin.additional_accepted_child_types.is_empty());
natives.insert(id, Rc::new(builtin));
}
}

View file

@ -9,7 +9,7 @@ export component MyMenu inherits MenuBar {
export component A inherits Window {
MenuBar {
Rectangle {}
// ^error{MenuBar cannot have children elements}
// ^error{Rectangle is not allowed within MenuBar. Only MenuItem are valid children}
x: 45px;
// ^error{Unknown property x in MenuBar}
width: 45px;
@ -17,6 +17,24 @@ export component A inherits Window {
entries: [];
init => {}
// ^error{'init' is not a callback in MenuBar}
MenuItem {
title: "hello";
x: 0px;
// ^error{Unknown property x in MenuItem}
max-height: 13px;
// ^error{Unknown property max-height in MenuItem}
opacity: 0.4;
// ^error{Unknown property opacity in MenuItem}
Rectangle {
// ^error{Rectangle is not allowed within MenuItem. Only MenuItem are valid children}
}
MenuItem {
}
}
}
Rectangle {

View file

@ -457,6 +457,13 @@ impl TypeRegister {
.or_default()
.insert(b.native_class.class_name.clone());
}
if b.additional_accept_self {
register
.context_restricted_types
.entry(b.native_class.class_name.clone())
.or_default()
.insert(b.native_class.class_name.clone());
}
}
}