refactor: remove menu tree changes
This commit is contained in:
parent
93e3d4fd42
commit
5a5670eda5
9 changed files with 221 additions and 197 deletions
|
|
@ -390,7 +390,7 @@ impl Core {
|
|||
pub fn responsive_menu_bar<'a, Message: Clone + From<SurfaceMessage> + 'static>(
|
||||
&self,
|
||||
id: crate::widget::Id,
|
||||
roots: Vec<Tree<'a, Message, Renderer>>,
|
||||
roots: Vec<Tree<'a, Message>>,
|
||||
) -> crate::Element<'a, Message> {
|
||||
let menu_bar_size = self.menu_bars.get(&id);
|
||||
if !menu_bar_size.is_some_and(|(limits, size)| {
|
||||
|
|
@ -405,10 +405,12 @@ impl Core {
|
|||
} else {
|
||||
crate::Element::from(
|
||||
responsive_container::responsive_container(
|
||||
menu::bar(vec![menu::Tree::<'a, _, _>::with_children(
|
||||
button::icon(icon::from_name("open-menu-symbolic"))
|
||||
.padding([4, 12])
|
||||
.class(crate::theme::Button::MenuRoot),
|
||||
menu::bar(vec![menu::Tree::<_>::with_children(
|
||||
Element::from(
|
||||
button::icon(icon::from_name("open-menu-symbolic"))
|
||||
.padding([4, 12])
|
||||
.class(crate::theme::Button::MenuRoot),
|
||||
),
|
||||
roots,
|
||||
)]),
|
||||
id,
|
||||
|
|
|
|||
|
|
@ -6,30 +6,24 @@
|
|||
use crate::widget::menu::{
|
||||
self, CloseCondition, ItemHeight, ItemWidth, MenuBarState, PathHighlight,
|
||||
};
|
||||
use crate::widget::ArcElementWrapper;
|
||||
use derive_setters::Setters;
|
||||
use iced::touch::Finger;
|
||||
use iced::{Event, Vector};
|
||||
use iced_core::widget::{tree, Tree, Widget};
|
||||
use iced_core::{event, mouse, touch, Length, Point, Size};
|
||||
use std::collections::HashSet;
|
||||
use std::sync::{Arc, Mutex};
|
||||
|
||||
use super::dropdown;
|
||||
|
||||
/// A context menu is a menu in a graphical user interface that appears upon user interaction, such as a right-click mouse operation.
|
||||
pub fn context_menu<Message: Clone + 'static>(
|
||||
content: impl Into<crate::Element<'static, Message>> + 'static,
|
||||
pub fn context_menu<'a, Message: 'a>(
|
||||
content: impl Into<crate::Element<'a, Message>> + 'a,
|
||||
// on_context: Message,
|
||||
context_menu: Option<Vec<menu::Tree<Message>>>,
|
||||
) -> ContextMenu<'static, Message> {
|
||||
context_menu: Option<Vec<menu::Tree<'a, Message>>>,
|
||||
) -> ContextMenu<'a, Message> {
|
||||
let mut this = ContextMenu {
|
||||
content: content.into(),
|
||||
context_menu: context_menu.map(|menus| {
|
||||
vec![menu::Tree::with_children(
|
||||
ArcElementWrapper(Arc::new(Mutex::new(crate::Element::from(
|
||||
crate::widget::row::<'static, Message>(),
|
||||
)))),
|
||||
crate::widget::row::<'static, Message>(),
|
||||
menus,
|
||||
)]
|
||||
}),
|
||||
|
|
@ -49,10 +43,10 @@ pub struct ContextMenu<'a, Message> {
|
|||
#[setters(skip)]
|
||||
content: crate::Element<'a, Message>,
|
||||
#[setters(skip)]
|
||||
context_menu: Option<Vec<menu::Tree<Message>>>,
|
||||
context_menu: Option<Vec<menu::Tree<'a, Message>>>,
|
||||
}
|
||||
|
||||
impl<'a, Message: Clone + 'static> Widget<Message, crate::Theme, crate::Renderer>
|
||||
impl<'a, Message: Clone> Widget<Message, crate::Theme, crate::Renderer>
|
||||
for ContextMenu<'a, Message>
|
||||
{
|
||||
fn tag(&self) -> tree::Tag {
|
||||
|
|
@ -64,7 +58,6 @@ impl<'a, Message: Clone + 'static> Widget<Message, crate::Theme, crate::Renderer
|
|||
tree::State::new(LocalState {
|
||||
context_cursor: Point::default(),
|
||||
fingers_pressed: Default::default(),
|
||||
menu_state: Default::default(),
|
||||
})
|
||||
}
|
||||
|
||||
|
|
@ -82,12 +75,9 @@ impl<'a, Message: Clone + 'static> Widget<Message, crate::Theme, crate::Renderer
|
|||
.map(|root| {
|
||||
let mut tree = Tree::empty();
|
||||
let flat = root
|
||||
.flatten()
|
||||
.flattern()
|
||||
.iter()
|
||||
.map(|mt| {
|
||||
let guard = mt.item.0.lock().unwrap();
|
||||
Tree::new(guard.as_widget())
|
||||
})
|
||||
.map(|mt| Tree::new(mt.item.as_widget()))
|
||||
.collect();
|
||||
tree.children = flat;
|
||||
tree
|
||||
|
|
@ -224,7 +214,7 @@ impl<'a, Message: Clone + 'static> Widget<Message, crate::Theme, crate::Renderer
|
|||
translation: Vector,
|
||||
) -> Option<iced_core::overlay::Element<'b, Message, crate::Theme, crate::Renderer>> {
|
||||
let state = tree.state.downcast_ref::<LocalState>();
|
||||
let menu_state = state.menu_state.clone();
|
||||
|
||||
let Some(context_menu) = self.context_menu.as_mut() else {
|
||||
return None;
|
||||
};
|
||||
|
|
@ -239,8 +229,8 @@ impl<'a, Message: Clone + 'static> Widget<Message, crate::Theme, crate::Renderer
|
|||
|
||||
Some(
|
||||
crate::widget::menu::Menu {
|
||||
tree: menu_state,
|
||||
menu_roots: std::borrow::Cow::Borrowed(context_menu),
|
||||
tree: &mut tree.children[1],
|
||||
menu_roots: context_menu,
|
||||
bounds_expand: 16,
|
||||
menu_overlays_parent: true,
|
||||
close_condition: CloseCondition {
|
||||
|
|
@ -255,7 +245,7 @@ impl<'a, Message: Clone + 'static> Widget<Message, crate::Theme, crate::Renderer
|
|||
cross_offset: 0,
|
||||
root_bounds_list: vec![bounds],
|
||||
path_highlight: Some(PathHighlight::MenuActive),
|
||||
style: std::borrow::Cow::Owned(crate::theme::menu_bar::MenuBarStyle::Default),
|
||||
style: &crate::theme::menu_bar::MenuBarStyle::Default,
|
||||
position: Point::new(translation.x, translation.y),
|
||||
}
|
||||
.overlay(),
|
||||
|
|
@ -275,10 +265,8 @@ impl<'a, Message: Clone + 'static> Widget<Message, crate::Theme, crate::Renderer
|
|||
}
|
||||
}
|
||||
|
||||
impl<Message: Clone + 'static> From<ContextMenu<'static, Message>>
|
||||
for crate::Element<'static, Message>
|
||||
{
|
||||
fn from(widget: ContextMenu<'static, Message>) -> Self {
|
||||
impl<'a, Message: Clone + 'a> From<ContextMenu<'a, Message>> for crate::Element<'a, Message> {
|
||||
fn from(widget: ContextMenu<'a, Message>) -> Self {
|
||||
Self::new(widget)
|
||||
}
|
||||
}
|
||||
|
|
@ -297,5 +285,4 @@ fn touch_lifted(event: &Event) -> bool {
|
|||
pub struct LocalState {
|
||||
context_cursor: Point,
|
||||
fingers_pressed: HashSet<Finger>,
|
||||
menu_state: dropdown::menu::State,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -130,6 +130,7 @@ pub struct State {
|
|||
pub(crate) tree: Arc<Mutex<Tree>>,
|
||||
}
|
||||
|
||||
// TODO use the Rc wrapper instead
|
||||
// XXX The tree is only used on one thread, but this is needed to make a message
|
||||
unsafe impl Send for State {}
|
||||
unsafe impl Sync for State {}
|
||||
|
|
|
|||
|
|
@ -84,7 +84,7 @@ where
|
|||
.map(|root| {
|
||||
let mut tree = Tree::empty();
|
||||
let flat = root
|
||||
.flatten()
|
||||
.flattern()
|
||||
.iter()
|
||||
.map(|mt| Tree::new(mt.item.as_widget()))
|
||||
.collect();
|
||||
|
|
@ -110,7 +110,7 @@ pub(crate) fn menu_roots_diff<'a, Message, Renderer>(
|
|||
.zip(menu_roots.iter())
|
||||
.for_each(|(t, root)| {
|
||||
let mut flat = root
|
||||
.flatten()
|
||||
.flattern()
|
||||
.iter()
|
||||
.map(|mt| {
|
||||
let widget = mt.item.as_widget();
|
||||
|
|
@ -129,7 +129,7 @@ pub(crate) fn menu_roots_diff<'a, Message, Renderer>(
|
|||
let extended = menu_roots[tree.children.len()..].iter().map(|root| {
|
||||
let mut tree = Tree::empty();
|
||||
let flat = root
|
||||
.flatten()
|
||||
.flattern()
|
||||
.iter()
|
||||
.map(|mt| Tree::new(mt.item.as_widget()))
|
||||
.collect();
|
||||
|
|
|
|||
|
|
@ -1,13 +1,8 @@
|
|||
// From iced_aw, license MIT
|
||||
|
||||
//! Menu tree overlay
|
||||
use std::{
|
||||
borrow::Cow,
|
||||
sync::{Arc, Mutex},
|
||||
};
|
||||
|
||||
use super::{menu_bar::MenuBarState, menu_tree::MenuTree};
|
||||
use crate::{style::menu_bar::StyleSheet, widget::dropdown};
|
||||
use crate::style::menu_bar::StyleSheet;
|
||||
|
||||
use iced_core::{Border, Shadow};
|
||||
use iced_widget::core::{
|
||||
|
|
@ -245,7 +240,7 @@ struct MenuBounds {
|
|||
impl MenuBounds {
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
fn new<Message, Renderer>(
|
||||
menu_tree: &MenuTree<Message>,
|
||||
menu_tree: &MenuTree<'_, Message, Renderer>,
|
||||
renderer: &Renderer,
|
||||
item_width: ItemWidth,
|
||||
item_height: ItemHeight,
|
||||
|
|
@ -305,7 +300,7 @@ impl MenuState {
|
|||
overlay_offset: Vector,
|
||||
slice: MenuSlice,
|
||||
renderer: &Renderer,
|
||||
menu_tree: &MenuTree<Message>,
|
||||
menu_tree: &MenuTree<'_, Message, Renderer>,
|
||||
tree: &mut [Tree],
|
||||
) -> Node
|
||||
where
|
||||
|
|
@ -359,7 +354,7 @@ impl MenuState {
|
|||
overlay_offset: Vector,
|
||||
index: usize,
|
||||
renderer: &Renderer,
|
||||
menu_tree: &MenuTree<Message>,
|
||||
menu_tree: &MenuTree<'_, Message, Renderer>,
|
||||
tree: &mut Tree,
|
||||
) -> Node
|
||||
where
|
||||
|
|
@ -432,9 +427,12 @@ impl MenuState {
|
|||
}
|
||||
}
|
||||
|
||||
pub(crate) struct Menu<'b, Message: std::clone::Clone> {
|
||||
pub(crate) tree: dropdown::menu::State,
|
||||
pub(crate) menu_roots: Cow<'b, Vec<MenuTree<Message>>>,
|
||||
pub(crate) struct Menu<'a, 'b, Message, Renderer>
|
||||
where
|
||||
Renderer: renderer::Renderer,
|
||||
{
|
||||
pub(crate) tree: &'b mut Tree,
|
||||
pub(crate) menu_roots: &'b mut Vec<MenuTree<'a, Message, Renderer>>,
|
||||
pub(crate) bounds_expand: u16,
|
||||
/// Allows menu overlay items to overlap the parent
|
||||
pub(crate) menu_overlays_parent: bool,
|
||||
|
|
@ -446,10 +444,10 @@ pub(crate) struct Menu<'b, Message: std::clone::Clone> {
|
|||
pub(crate) cross_offset: i32,
|
||||
pub(crate) root_bounds_list: Vec<Rectangle>,
|
||||
pub(crate) path_highlight: Option<PathHighlight>,
|
||||
pub(crate) style: Cow<'b, <crate::Theme as StyleSheet>::Style>,
|
||||
pub(crate) style: &'b <crate::Theme as StyleSheet>::Style,
|
||||
pub(crate) position: Point,
|
||||
}
|
||||
impl<'b, Message: Clone + 'static, Renderer> Menu<'b, Message>
|
||||
impl<'a, 'b, Message, Renderer> Menu<'a, 'b, Message, Renderer>
|
||||
where
|
||||
Renderer: renderer::Renderer,
|
||||
{
|
||||
|
|
@ -753,7 +751,7 @@ fn pad_rectangle(rect: Rectangle, padding: Padding) -> Rectangle {
|
|||
}
|
||||
|
||||
pub(super) fn init_root_menu<Message, Renderer>(
|
||||
menu: &mut Menu<'_, Message>,
|
||||
menu: &mut Menu<'_, '_, Message, Renderer>,
|
||||
renderer: &Renderer,
|
||||
shell: &mut Shell<'_, Message>,
|
||||
overlay_cursor: Point,
|
||||
|
|
@ -831,7 +829,7 @@ pub(super) fn init_root_menu<Message, Renderer>(
|
|||
#[allow(clippy::too_many_arguments)]
|
||||
fn process_menu_events<'b, Message, Renderer>(
|
||||
tree: &'b mut Tree,
|
||||
menu_roots: &'b mut [MenuTree<Message>],
|
||||
menu_roots: &'b mut [MenuTree<'_, Message, Renderer>],
|
||||
event: event::Event,
|
||||
view_cursor: Cursor,
|
||||
renderer: &Renderer,
|
||||
|
|
@ -889,7 +887,7 @@ where
|
|||
|
||||
#[allow(unused_results)]
|
||||
fn process_overlay_events<Message, Renderer>(
|
||||
menu: &mut Menu<'_, Message>,
|
||||
menu: &mut Menu<'_, '_, Message, Renderer>,
|
||||
renderer: &Renderer,
|
||||
viewport_size: Size,
|
||||
overlay_offset: Vector,
|
||||
|
|
@ -899,7 +897,6 @@ fn process_overlay_events<Message, Renderer>(
|
|||
) -> event::Status
|
||||
where
|
||||
Renderer: renderer::Renderer,
|
||||
Message: std::clone::Clone,
|
||||
{
|
||||
use event::Status::{Captured, Ignored};
|
||||
/*
|
||||
|
|
@ -1080,13 +1077,16 @@ where
|
|||
Captured
|
||||
}
|
||||
|
||||
fn process_scroll_events<Message: Clone>(
|
||||
menu: &mut Menu<'_, Message>,
|
||||
fn process_scroll_events<Message, Renderer>(
|
||||
menu: &mut Menu<'_, '_, Message, Renderer>,
|
||||
delta: mouse::ScrollDelta,
|
||||
overlay_cursor: Point,
|
||||
viewport_size: Size,
|
||||
overlay_offset: Vector,
|
||||
) -> event::Status {
|
||||
) -> event::Status
|
||||
where
|
||||
Renderer: renderer::Renderer,
|
||||
{
|
||||
use event::Status::{Captured, Ignored};
|
||||
use mouse::ScrollDelta;
|
||||
|
||||
|
|
@ -1155,13 +1155,16 @@ fn process_scroll_events<Message: Clone>(
|
|||
|
||||
#[allow(clippy::pedantic)]
|
||||
/// Returns (children_size, child_positions, child_sizes)
|
||||
fn get_children_layout<Message>(
|
||||
menu_tree: &MenuTree<Message>,
|
||||
renderer: &crate::Renderer,
|
||||
fn get_children_layout<Message, Renderer>(
|
||||
menu_tree: &MenuTree<'_, Message, Renderer>,
|
||||
renderer: &Renderer,
|
||||
item_width: ItemWidth,
|
||||
item_height: ItemHeight,
|
||||
tree: &mut [Tree],
|
||||
) -> (Size, Vec<f32>, Vec<Size>) {
|
||||
) -> (Size, Vec<f32>, Vec<Size>)
|
||||
where
|
||||
Renderer: renderer::Renderer,
|
||||
{
|
||||
let width = match item_width {
|
||||
ItemWidth::Uniform(u) => f32::from(u),
|
||||
ItemWidth::Static(s) => f32::from(menu_tree.width.unwrap_or(s)),
|
||||
|
|
@ -1181,8 +1184,7 @@ fn get_children_layout<Message>(
|
|||
.children
|
||||
.iter()
|
||||
.map(|mt| {
|
||||
let guard = mt.item.0.lock().unwrap();
|
||||
let w = guard.as_widget();
|
||||
let w = mt.item.as_widget();
|
||||
match w.size().height {
|
||||
Length::Fixed(f) => Size::new(width, f),
|
||||
Length::Shrink => {
|
||||
|
|
|
|||
|
|
@ -5,14 +5,13 @@
|
|||
use std::borrow::Cow;
|
||||
use std::collections::HashMap;
|
||||
use std::rc::Rc;
|
||||
use std::sync::{Arc, Mutex};
|
||||
|
||||
use iced_widget::core::{renderer, Element};
|
||||
|
||||
use crate::iced_core::{Alignment, Length};
|
||||
use crate::widget::icon;
|
||||
use crate::widget::menu::action::MenuAction;
|
||||
use crate::widget::menu::key_bind::KeyBind;
|
||||
use crate::widget::{icon, ArcElementWrapper};
|
||||
use crate::{theme, widget};
|
||||
|
||||
/// Nested menu is essentially a tree of items, a menu is a collection of items
|
||||
|
|
@ -24,27 +23,27 @@ use crate::{theme, widget};
|
|||
/// but there's no need to explicitly distinguish them here, if a menu tree
|
||||
/// has children, it's a menu, otherwise it's an item
|
||||
#[allow(missing_debug_implementations)]
|
||||
#[derive(Clone)]
|
||||
|
||||
pub struct MenuTree<Message> {
|
||||
pub struct MenuTree<'a, Message, Renderer = crate::Renderer> {
|
||||
/// The menu tree will be flatten into a vector to build a linear widget tree,
|
||||
/// the `index` field is the index of the item in that vector
|
||||
pub(crate) index: usize,
|
||||
|
||||
// TODO needs to be wrapped in Arc<Mutex kinda like in cosmic-files. Check the widget there for details
|
||||
/// The item of the menu tree
|
||||
pub(crate) item: ArcElementWrapper<Message>,
|
||||
pub(crate) item: Element<'a, Message, crate::Theme, Renderer>,
|
||||
/// The children of the menu tree
|
||||
pub(crate) children: Vec<MenuTree<Message>>,
|
||||
pub(crate) children: Vec<MenuTree<'a, Message, Renderer>>,
|
||||
/// The width of the menu tree
|
||||
pub(crate) width: Option<u16>,
|
||||
/// The height of the menu tree
|
||||
pub(crate) height: Option<u16>,
|
||||
}
|
||||
|
||||
impl<Message: Clone + 'static> MenuTree<Message> {
|
||||
impl<'a, Message, Renderer> MenuTree<'a, Message, Renderer>
|
||||
where
|
||||
Renderer: renderer::Renderer,
|
||||
{
|
||||
/// Create a new menu tree from a widget
|
||||
pub fn new(item: impl Into<ArcElementWrapper<Message>>) -> Self {
|
||||
pub fn new(item: impl Into<Element<'a, Message, crate::Theme, Renderer>>) -> Self {
|
||||
Self {
|
||||
index: 0,
|
||||
item: item.into(),
|
||||
|
|
@ -56,8 +55,8 @@ impl<Message: Clone + 'static> MenuTree<Message> {
|
|||
|
||||
/// Create a menu tree from a widget and a vector of sub trees
|
||||
pub fn with_children(
|
||||
item: impl Into<ArcElementWrapper<Message>>,
|
||||
children: Vec<impl Into<MenuTree<Message>>>,
|
||||
item: impl Into<Element<'a, Message, crate::Theme, Renderer>>,
|
||||
children: Vec<impl Into<MenuTree<'a, Message, Renderer>>>,
|
||||
) -> Self {
|
||||
Self {
|
||||
index: 0,
|
||||
|
|
@ -93,7 +92,7 @@ impl<Message: Clone + 'static> MenuTree<Message> {
|
|||
/// Set the index of each item
|
||||
pub(crate) fn set_index(&mut self) {
|
||||
/// inner counting function.
|
||||
fn rec<Message: Clone + 'static>(mt: &mut MenuTree<Message>, count: &mut usize) {
|
||||
fn rec<Message, Renderer>(mt: &mut MenuTree<'_, Message, Renderer>, count: &mut usize) {
|
||||
// keep items under the same menu line up
|
||||
mt.children.iter_mut().for_each(|c| {
|
||||
c.index = *count;
|
||||
|
|
@ -110,32 +109,36 @@ impl<Message: Clone + 'static> MenuTree<Message> {
|
|||
}
|
||||
|
||||
/// Flatten the menu tree
|
||||
pub(crate) fn flatten(&self) -> Vec<Self> {
|
||||
pub(crate) fn flattern(&'a self) -> Vec<&Self> {
|
||||
/// Inner flattening function
|
||||
fn rec<Message: Clone + 'static>(
|
||||
mt: &MenuTree<Message>,
|
||||
flat: &mut Vec<MenuTree<Message>>,
|
||||
fn rec<'a, Message, Renderer>(
|
||||
mt: &'a MenuTree<'a, Message, Renderer>,
|
||||
flat: &mut Vec<&MenuTree<'a, Message, Renderer>>,
|
||||
) {
|
||||
mt.children.clone().into_iter().for_each(|c| {
|
||||
mt.children.iter().for_each(|c| {
|
||||
flat.push(c);
|
||||
});
|
||||
|
||||
mt.children.iter().for_each(|c| {
|
||||
rec(&c, flat);
|
||||
rec(c, flat);
|
||||
});
|
||||
}
|
||||
|
||||
let mut flat = Vec::new();
|
||||
flat.push(self.clone());
|
||||
flat.push(self);
|
||||
rec(self, &mut flat);
|
||||
|
||||
flat
|
||||
}
|
||||
}
|
||||
|
||||
impl<Message: Clone + 'static> From<crate::Element<'static, Message>> for MenuTree<Message> {
|
||||
fn from(value: crate::Element<'static, Message>) -> Self {
|
||||
Self::new(ArcElementWrapper(Arc::new(Mutex::new(value))))
|
||||
impl<'a, Message, Renderer> From<Element<'a, Message, crate::Theme, Renderer>>
|
||||
for MenuTree<'a, Message, Renderer>
|
||||
where
|
||||
Renderer: renderer::Renderer,
|
||||
{
|
||||
fn from(value: Element<'a, Message, crate::Theme, Renderer>) -> Self {
|
||||
Self::new(value)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -154,7 +157,6 @@ pub fn menu_button<'a, Message: 'a>(
|
|||
.class(theme::Button::MenuItem)
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
/// Represents a menu item that performs an action when selected or a separator between menu items.
|
||||
///
|
||||
/// - `Action` - Represents a menu item that performs an action when selected.
|
||||
|
|
@ -211,13 +213,18 @@ where
|
|||
/// # Returns
|
||||
/// - A vector of `MenuTree`.
|
||||
pub fn menu_items<
|
||||
'a,
|
||||
A: MenuAction<Message = Message>,
|
||||
L: Into<Cow<'static, str>> + 'static,
|
||||
Message: 'static + std::clone::Clone,
|
||||
Message: 'a,
|
||||
Renderer: renderer::Renderer + 'a,
|
||||
>(
|
||||
key_binds: &HashMap<KeyBind, A>,
|
||||
children: Vec<MenuItem<A, L>>,
|
||||
) -> Vec<MenuTree<Message>> {
|
||||
) -> Vec<MenuTree<'a, Message, Renderer>>
|
||||
where
|
||||
Element<'a, Message, crate::Theme, Renderer>: From<widget::button::Button<'a, Message>>,
|
||||
{
|
||||
fn find_key<A: MenuAction>(action: &A, key_binds: &HashMap<KeyBind, A>) -> String {
|
||||
for (key_bind, key_action) in key_binds {
|
||||
if action == key_action {
|
||||
|
|
@ -252,7 +259,7 @@ pub fn menu_items<
|
|||
|
||||
let menu_button = menu_button(items).on_press(action.message());
|
||||
|
||||
trees.push(MenuTree::<Message>::from(Element::from(menu_button)));
|
||||
trees.push(MenuTree::<Message, Renderer>::new(menu_button));
|
||||
}
|
||||
MenuItem::ButtonDisabled(label, icon, action) => {
|
||||
let key = find_key(&action, key_binds);
|
||||
|
|
@ -270,7 +277,7 @@ pub fn menu_items<
|
|||
|
||||
let menu_button = menu_button(items);
|
||||
|
||||
trees.push(MenuTree::<Message>::from(Element::from(menu_button)));
|
||||
trees.push(MenuTree::<Message, Renderer>::new(menu_button));
|
||||
}
|
||||
MenuItem::CheckBox(label, icon, value, action) => {
|
||||
let key = find_key(&action, key_binds);
|
||||
|
|
@ -300,40 +307,36 @@ pub fn menu_items<
|
|||
items.insert(2, widget::icon::icon(icon).size(14).into());
|
||||
}
|
||||
|
||||
trees.push(MenuTree::from(Element::from(
|
||||
menu_button(items).on_press(action.message()),
|
||||
)));
|
||||
trees.push(MenuTree::new(menu_button(items).on_press(action.message())));
|
||||
}
|
||||
MenuItem::Folder(label, children) => {
|
||||
trees.push(MenuTree::<Message>::with_children(
|
||||
ArcElementWrapper(Arc::new(Mutex::new(crate::Element::from(
|
||||
menu_button::<'static, _>(vec![
|
||||
widget::text(label).into(),
|
||||
widget::horizontal_space().into(),
|
||||
widget::icon::from_name("pan-end-symbolic")
|
||||
.size(16)
|
||||
.icon()
|
||||
.into(),
|
||||
])
|
||||
.class(
|
||||
// Menu folders have no on_press so they take on the disabled style by default
|
||||
if children.is_empty() {
|
||||
// This will make the folder use the disabled style if it has no children
|
||||
theme::Button::MenuItem
|
||||
} else {
|
||||
// This will make the folder use the enabled style if it has children
|
||||
theme::Button::MenuFolder
|
||||
},
|
||||
),
|
||||
)))),
|
||||
trees.push(MenuTree::<Message, Renderer>::with_children(
|
||||
menu_button(vec![
|
||||
widget::text(label).into(),
|
||||
widget::horizontal_space().into(),
|
||||
widget::icon::from_name("pan-end-symbolic")
|
||||
.size(16)
|
||||
.icon()
|
||||
.into(),
|
||||
])
|
||||
.class(
|
||||
// Menu folders have no on_press so they take on the disabled style by default
|
||||
if children.is_empty() {
|
||||
// This will make the folder use the disabled style if it has no children
|
||||
theme::Button::MenuItem
|
||||
} else {
|
||||
// This will make the folder use the enabled style if it has children
|
||||
theme::Button::MenuFolder
|
||||
},
|
||||
),
|
||||
menu_items(key_binds, children),
|
||||
));
|
||||
}
|
||||
MenuItem::Divider => {
|
||||
if i != size - 1 {
|
||||
trees.push(MenuTree::<Message>::from(Element::from(
|
||||
trees.push(MenuTree::<Message, Renderer>::new(
|
||||
widget::divider::horizontal::light(),
|
||||
)));
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -67,7 +67,7 @@ impl<'a, Message: Clone + 'static> NavBar<'a, Message> {
|
|||
self
|
||||
}
|
||||
|
||||
pub fn context_menu(mut self, context_menu: Option<Vec<menu::Tree<Message>>>) -> Self {
|
||||
pub fn context_menu(mut self, context_menu: Option<Vec<menu::Tree<'a, Message>>>) -> Self {
|
||||
self.segmented_button = self.segmented_button.context_menu(context_menu);
|
||||
self
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ use crate::widget::menu::{
|
|||
self, menu_roots_children, menu_roots_diff, CloseCondition, ItemHeight, ItemWidth,
|
||||
MenuBarState, PathHighlight,
|
||||
};
|
||||
use crate::widget::{dropdown, icon, Icon};
|
||||
use crate::widget::{icon, Icon};
|
||||
use crate::{Element, Renderer};
|
||||
use derive_setters::Setters;
|
||||
use iced::clipboard::dnd::{self, DndAction, DndDestinationRectangle, DndEvent, OfferEvent};
|
||||
|
|
@ -127,7 +127,7 @@ where
|
|||
pub(super) style: Style,
|
||||
/// The context menu to display when a context is activated
|
||||
#[setters(skip)]
|
||||
pub(super) context_menu: Option<Vec<menu::Tree<Message>>>,
|
||||
pub(super) context_menu: Option<Vec<menu::Tree<'a, Message, crate::Renderer>>>,
|
||||
/// Emits the ID of the item that was activated.
|
||||
#[setters(skip)]
|
||||
pub(super) on_activate: Option<Box<dyn Fn(Entity) -> Message + 'static>>,
|
||||
|
|
@ -197,13 +197,13 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
pub fn context_menu(mut self, context_menu: Option<Vec<menu::Tree<Message>>>) -> Self
|
||||
pub fn context_menu(mut self, context_menu: Option<Vec<menu::Tree<'a, Message>>>) -> Self
|
||||
where
|
||||
Message: Clone + 'static,
|
||||
Message: 'static,
|
||||
{
|
||||
self.context_menu = context_menu.map(|menus| {
|
||||
vec![menu::Tree::with_children(
|
||||
crate::Element::from(crate::widget::row::<'static, Message>()),
|
||||
crate::widget::row::<'static, Message>(),
|
||||
menus,
|
||||
)]
|
||||
});
|
||||
|
|
@ -593,7 +593,6 @@ where
|
|||
dnd_state: Default::default(),
|
||||
fingers_pressed: Default::default(),
|
||||
pressed_item: None,
|
||||
menu_state: Default::default(),
|
||||
})
|
||||
}
|
||||
|
||||
|
|
@ -1553,7 +1552,7 @@ where
|
|||
translation: Vector,
|
||||
) -> Option<iced_core::overlay::Element<'b, Message, crate::Theme, Renderer>> {
|
||||
let state = tree.state.downcast_ref::<LocalState>();
|
||||
let menu_state = state.menu_state.clone();
|
||||
|
||||
let Some(entity) = state.show_context else {
|
||||
return None;
|
||||
};
|
||||
|
|
@ -1581,8 +1580,8 @@ where
|
|||
|
||||
Some(
|
||||
crate::widget::menu::Menu {
|
||||
tree: menu_state,
|
||||
menu_roots: Cow::Borrowed(context_menu),
|
||||
tree: &mut tree.children[0],
|
||||
menu_roots: context_menu,
|
||||
bounds_expand: 16,
|
||||
menu_overlays_parent: true,
|
||||
close_condition: CloseCondition {
|
||||
|
|
@ -1597,7 +1596,7 @@ where
|
|||
cross_offset: 0,
|
||||
root_bounds_list: vec![bounds],
|
||||
path_highlight: Some(PathHighlight::MenuActive),
|
||||
style: Cow::Owned(crate::theme::menu_bar::MenuBarStyle::Default),
|
||||
style: &crate::theme::menu_bar::MenuBarStyle::Default,
|
||||
position: Point::new(translation.x, translation.y),
|
||||
}
|
||||
.overlay(),
|
||||
|
|
@ -1684,8 +1683,6 @@ pub struct LocalState {
|
|||
fingers_pressed: HashSet<Finger>,
|
||||
/// The currently pressed item
|
||||
pressed_item: Option<Item>,
|
||||
/// Menu state
|
||||
pub(crate) menu_state: dropdown::menu::State,
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, PartialEq)]
|
||||
|
|
|
|||
|
|
@ -1,19 +1,55 @@
|
|||
use std::sync::{Arc, Mutex};
|
||||
use std::{
|
||||
cell::RefCell,
|
||||
rc::Rc,
|
||||
thread::{self, ThreadId},
|
||||
};
|
||||
|
||||
use crate::Element;
|
||||
use iced::{event, Length, Rectangle, Size};
|
||||
use iced_core::{id::Id, widget, widget::tree, Widget};
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct ArcElementWrapper<M>(pub Arc<Mutex<Element<'static, M>>>);
|
||||
pub struct RcElementWrapper<M> {
|
||||
pub(crate) element: Rc<RefCell<Element<'static, M>>>,
|
||||
pub(crate) thread_id: ThreadId,
|
||||
}
|
||||
|
||||
impl<M> Widget<M, crate::Theme, crate::Renderer> for ArcElementWrapper<M> {
|
||||
impl<M> RcElementWrapper<M> {
|
||||
pub fn new(element: Element<'static, M>) -> Self {
|
||||
Self {
|
||||
element: Rc::new(RefCell::new(element)),
|
||||
thread_id: thread::current().id(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn with_element<T>(&self, f: impl FnOnce(&Element<'static, M>) -> T) -> T {
|
||||
assert_eq!(self.thread_id, thread::current().id());
|
||||
let my_ref: &Element<'static, M> = &RefCell::borrow(self.element.as_ref());
|
||||
f(my_ref)
|
||||
}
|
||||
|
||||
pub fn with_element_mut<T>(&self, f: impl FnOnce(&mut Element<'static, M>) -> T) -> T {
|
||||
assert_eq!(self.thread_id, thread::current().id());
|
||||
let my_refmut: &mut Element<'static, M> = &mut RefCell::borrow_mut(self.element.as_ref());
|
||||
f(my_refmut)
|
||||
}
|
||||
|
||||
pub(crate) unsafe fn as_ptr(&self) -> *mut Element<'static, M> {
|
||||
assert_eq!(self.thread_id, thread::current().id());
|
||||
RefCell::as_ptr(self.element.as_ref())
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl<M: 'static> Send for RcElementWrapper<M> {}
|
||||
unsafe impl<M: 'static> Sync for RcElementWrapper<M> {}
|
||||
|
||||
impl<M> Widget<M, crate::Theme, crate::Renderer> for RcElementWrapper<M> {
|
||||
fn size(&self) -> Size<Length> {
|
||||
self.0.lock().unwrap().as_widget().size()
|
||||
self.with_element(|e| e.as_widget().size())
|
||||
}
|
||||
|
||||
fn size_hint(&self) -> Size<Length> {
|
||||
self.0.lock().unwrap().as_widget().size_hint()
|
||||
self.element.borrow_mut().as_widget().size_hint()
|
||||
}
|
||||
|
||||
fn layout(
|
||||
|
|
@ -22,11 +58,7 @@ impl<M> Widget<M, crate::Theme, crate::Renderer> for ArcElementWrapper<M> {
|
|||
renderer: &crate::Renderer,
|
||||
limits: &crate::iced_core::layout::Limits,
|
||||
) -> crate::iced_core::layout::Node {
|
||||
self.0
|
||||
.lock()
|
||||
.unwrap()
|
||||
.as_widget_mut()
|
||||
.layout(tree, renderer, limits)
|
||||
self.with_element_mut(|e| e.as_widget_mut().layout(tree, renderer, limits))
|
||||
}
|
||||
|
||||
fn draw(
|
||||
|
|
@ -39,27 +71,26 @@ impl<M> Widget<M, crate::Theme, crate::Renderer> for ArcElementWrapper<M> {
|
|||
cursor: crate::iced_core::mouse::Cursor,
|
||||
viewport: &Rectangle,
|
||||
) {
|
||||
self.0
|
||||
.lock()
|
||||
.unwrap()
|
||||
.as_widget()
|
||||
.draw(tree, renderer, theme, style, layout, cursor, viewport)
|
||||
self.with_element(move |e| {
|
||||
e.as_widget()
|
||||
.draw(tree, renderer, theme, style, layout, cursor, viewport)
|
||||
})
|
||||
}
|
||||
|
||||
fn tag(&self) -> tree::Tag {
|
||||
self.0.lock().unwrap().as_widget().tag()
|
||||
self.with_element(|e| e.as_widget().tag())
|
||||
}
|
||||
|
||||
fn state(&self) -> tree::State {
|
||||
self.0.lock().unwrap().as_widget().state()
|
||||
self.with_element(|e| e.as_widget().state())
|
||||
}
|
||||
|
||||
fn children(&self) -> Vec<tree::Tree> {
|
||||
self.0.lock().unwrap().as_widget().children()
|
||||
self.with_element(|e| e.as_widget().children())
|
||||
}
|
||||
|
||||
fn diff(&mut self, tree: &mut tree::Tree) {
|
||||
self.0.lock().unwrap().as_widget_mut().diff(tree)
|
||||
self.with_element_mut(|e| e.as_widget_mut().diff(tree))
|
||||
}
|
||||
|
||||
fn operate(
|
||||
|
|
@ -69,87 +100,88 @@ impl<M> Widget<M, crate::Theme, crate::Renderer> for ArcElementWrapper<M> {
|
|||
renderer: &crate::Renderer,
|
||||
operation: &mut dyn widget::Operation,
|
||||
) {
|
||||
self.0
|
||||
.lock()
|
||||
.unwrap()
|
||||
.as_widget()
|
||||
.operate(state, layout, renderer, operation)
|
||||
self.with_element(|e| {
|
||||
e.as_widget().operate(state, layout, renderer, operation);
|
||||
})
|
||||
}
|
||||
|
||||
fn on_event(
|
||||
&mut self,
|
||||
_state: &mut tree::Tree,
|
||||
_event: crate::iced::Event,
|
||||
_layout: crate::iced_core::Layout<'_>,
|
||||
_cursor: crate::iced_core::mouse::Cursor,
|
||||
_renderer: &crate::Renderer,
|
||||
_clipboard: &mut dyn crate::iced_core::Clipboard,
|
||||
_shell: &mut crate::iced_core::Shell<'_, M>,
|
||||
_viewport: &Rectangle,
|
||||
state: &mut tree::Tree,
|
||||
event: crate::iced::Event,
|
||||
layout: crate::iced_core::Layout<'_>,
|
||||
cursor: crate::iced_core::mouse::Cursor,
|
||||
renderer: &crate::Renderer,
|
||||
clipboard: &mut dyn crate::iced_core::Clipboard,
|
||||
shell: &mut crate::iced_core::Shell<'_, M>,
|
||||
viewport: &Rectangle,
|
||||
) -> event::Status {
|
||||
self.0.lock().unwrap().as_widget_mut().on_event(
|
||||
_state, _event, _layout, _cursor, _renderer, _clipboard, _shell, _viewport,
|
||||
)
|
||||
self.with_element_mut(|e| {
|
||||
e.as_widget_mut().on_event(
|
||||
state, event, layout, cursor, renderer, clipboard, shell, viewport,
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
fn mouse_interaction(
|
||||
&self,
|
||||
_state: &tree::Tree,
|
||||
_layout: crate::iced_core::Layout<'_>,
|
||||
_cursor: crate::iced_core::mouse::Cursor,
|
||||
_viewport: &Rectangle,
|
||||
_renderer: &crate::Renderer,
|
||||
state: &tree::Tree,
|
||||
layout: crate::iced_core::Layout<'_>,
|
||||
cursor: crate::iced_core::mouse::Cursor,
|
||||
viewport: &Rectangle,
|
||||
renderer: &crate::Renderer,
|
||||
) -> crate::iced_core::mouse::Interaction {
|
||||
self.0
|
||||
.lock()
|
||||
.unwrap()
|
||||
.as_widget()
|
||||
.mouse_interaction(_state, _layout, _cursor, _viewport, _renderer)
|
||||
self.with_element(|e| {
|
||||
e.as_widget()
|
||||
.mouse_interaction(state, layout, cursor, viewport, renderer)
|
||||
})
|
||||
}
|
||||
|
||||
fn overlay<'a>(
|
||||
&'a mut self,
|
||||
_state: &'a mut tree::Tree,
|
||||
_layout: crate::iced_core::Layout<'_>,
|
||||
_renderer: &crate::Renderer,
|
||||
_translation: crate::iced_core::Vector,
|
||||
state: &'a mut tree::Tree,
|
||||
layout: crate::iced_core::Layout<'_>,
|
||||
renderer: &crate::Renderer,
|
||||
translation: crate::iced_core::Vector,
|
||||
) -> Option<crate::iced_core::overlay::Element<'a, M, crate::Theme, crate::Renderer>> {
|
||||
// TODO
|
||||
None
|
||||
assert_eq!(self.thread_id, thread::current().id());
|
||||
Rc::get_mut(&mut self.element).and_then(|e| {
|
||||
e.get_mut()
|
||||
.as_widget_mut()
|
||||
.overlay(state, layout, renderer, translation)
|
||||
})
|
||||
}
|
||||
|
||||
fn id(&self) -> Option<Id> {
|
||||
self.0.lock().unwrap().as_widget().id()
|
||||
self.with_element_mut(|e| e.as_widget_mut().id())
|
||||
}
|
||||
|
||||
fn set_id(&mut self, _id: Id) {
|
||||
self.0.lock().unwrap().as_widget_mut().set_id(_id)
|
||||
fn set_id(&mut self, id: Id) {
|
||||
self.with_element_mut(|e| e.as_widget_mut().set_id(id))
|
||||
}
|
||||
|
||||
fn drag_destinations(
|
||||
&self,
|
||||
_state: &tree::Tree,
|
||||
_layout: crate::iced_core::Layout<'_>,
|
||||
state: &tree::Tree,
|
||||
layout: crate::iced_core::Layout<'_>,
|
||||
renderer: &crate::Renderer,
|
||||
_dnd_rectangles: &mut crate::iced_core::clipboard::DndDestinationRectangles,
|
||||
dnd_rectangles: &mut crate::iced_core::clipboard::DndDestinationRectangles,
|
||||
) {
|
||||
self.0.lock().unwrap().as_widget().drag_destinations(
|
||||
_state,
|
||||
_layout,
|
||||
renderer,
|
||||
_dnd_rectangles,
|
||||
)
|
||||
self.with_element_mut(|e| {
|
||||
e.as_widget_mut()
|
||||
.drag_destinations(state, layout, renderer, dnd_rectangles)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl<Message: 'static> From<ArcElementWrapper<Message>> for Element<'static, Message> {
|
||||
fn from(wrapper: ArcElementWrapper<Message>) -> Self {
|
||||
impl<Message: 'static> From<RcElementWrapper<Message>> for Element<'static, Message> {
|
||||
fn from(wrapper: RcElementWrapper<Message>) -> Self {
|
||||
Element::new(wrapper)
|
||||
}
|
||||
}
|
||||
|
||||
impl<Message: 'static> From<Element<'static, Message>> for ArcElementWrapper<Message> {
|
||||
impl<Message: 'static> From<Element<'static, Message>> for RcElementWrapper<Message> {
|
||||
fn from(e: Element<'static, Message>) -> Self {
|
||||
ArcElementWrapper(Arc::new(Mutex::new(e)))
|
||||
RcElementWrapper::new(e)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue