Skip to content
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions docs/astro/src/content/docs/reference/window/contextmenuarea.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,18 @@ The title shown for this menu item.
When disabled, the `MenuItem` can be selected but not activated.
</SlintProperty>

#### checkable

<SlintProperty propName="checkable" typeName="bool" defaultValue="true">
When true, the `MenuItem` can be checked.
</SlintProperty>

#### checked

<SlintProperty propName="checked" typeName="bool" defaultValue="true">
When true, a checkmark will be shown next to the title of the `MenuItem`.
</SlintProperty>

### icon
<SlintProperty propName="icon" typeName="image">
The icon shown next to the title.
Expand Down
40 changes: 25 additions & 15 deletions internal/backends/winit/muda.rs
Original file line number Diff line number Diff line change
Expand Up @@ -137,21 +137,31 @@ impl MudaAdapter {
Box::new(muda::PredefinedMenuItem::separator())
} else if !entry.has_sub_menu {
// the top level always has a sub menu regardless of entry.has_sub_menu
let icon = entry
.icon
.to_rgba8()
.map(|rgba| {
muda::Icon::from_rgba(rgba.as_bytes().to_vec(), rgba.width(), rgba.height())
.ok()
})
.flatten();
Box::new(muda::IconMenuItem::with_id(
id.clone(),
&entry.title,
entry.enabled,
icon,
None,
))
if entry.checkable {
Box::new(muda::CheckMenuItem::with_id(
id.clone(),
&entry.title,
entry.enabled,
entry.checked,
None,
))
} else if let Some(rgba) = entry.icon.to_rgba8() {
let icon = muda::Icon::from_rgba(
rgba.as_bytes().to_vec(),
rgba.width(),
rgba.height(),
)
.ok();
Box::new(muda::IconMenuItem::with_id(
id.clone(),
&entry.title,
entry.enabled,
icon,
None,
))
} else {
Box::new(muda::MenuItem::with_id(id.clone(), &entry.title, entry.enabled, None))
}
} else {
let sub_menu = muda::Submenu::with_id(id.clone(), &entry.title, entry.enabled);
if depth < 15 {
Expand Down
4 changes: 4 additions & 0 deletions internal/common/builtin_structs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -211,6 +211,10 @@ macro_rules! for_each_builtin_structs {
// keyboard_shortcut: KeySequence,
/// whether the menu entry is enabled
enabled: bool,
/// whether the menu entry is checkable
checkable: bool,
/// whether the menu entry is checked
checked: bool,
/// Sub menu
has_sub_menu: bool,
/// The menu entry is a separator
Expand Down
2 changes: 2 additions & 0 deletions internal/compiler/builtins.slint
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,8 @@ component MenuItem {
in property <string> title;
callback activated();
in property <bool> enabled: true;
in property <bool> checkable: false;
in property <bool> checked: false;
in property <image> icon;
//-disallow_global_types_as_child_elements
//-is_non_item_type
Expand Down
13 changes: 10 additions & 3 deletions internal/compiler/widgets/common/menu-base.slint
Original file line number Diff line number Diff line change
Expand Up @@ -128,11 +128,18 @@ export component MenuItemBase {

spacing: 10px;

Image {
Rectangle {
width: root.icon-size;
y: (parent.height - self.height) / 2;
source: entry.icon;
accessible-role: none;

if entry.checked: Text {
text: "✓";
}

Image {
source: entry.icon;
accessible-role: none;
}
}

label := Text {
Expand Down
19 changes: 18 additions & 1 deletion internal/core/menus.rs
Original file line number Diff line number Diff line change
Expand Up @@ -90,12 +90,23 @@ impl MenuFromItemTree {
let children = self.update_shadow_tree_recursive(&item);
let has_sub_menu = !children.is_empty();
let enabled = menu_item.enabled();
let checkable = menu_item.checkable();
let checked = menu_item.checked();
let icon = menu_item.icon();
self.item_cache.borrow_mut().insert(
id.clone(),
ShadowTreeNode { item: ItemRc::downgrade(&item), children },
);
result.push(MenuEntry { title, id, has_sub_menu, is_separator, enabled, icon });
result.push(MenuEntry {
title,
id,
has_sub_menu,
is_separator,
enabled,
checkable,
checked,
icon,
});
}
VisitChildrenResult::CONTINUE
};
Expand Down Expand Up @@ -133,6 +144,10 @@ impl Menu for MenuFromItemTree {
self.item_cache.borrow().get(entry.id.as_str()).and_then(|e| e.item.upgrade())
{
if let Some(menu_item) = menu_item.downcast::<MenuItem>() {
if menu_item.checkable.get_internal() {
menu_item.checked.set(!menu_item.checked.get_internal());
}

menu_item.activated.call(&());
}
}
Expand All @@ -150,6 +165,8 @@ pub struct MenuItem {
pub title: Property<SharedString>,
pub activated: Callback<VoidArg>,
pub enabled: Property<bool>,
pub checkable: Property<bool>,
pub checked: Property<bool>,
pub icon: Property<Image>,
}

Expand Down
Loading