cleanup
This commit is contained in:
parent
3fd6c4f6bc
commit
3d84fb2a89
14 changed files with 203 additions and 177 deletions
|
|
@ -177,7 +177,6 @@ impl cosmic::Application for App {
|
|||
self.hidden = !self.hidden;
|
||||
}
|
||||
Message::Surface(a) => {
|
||||
dbg!("got action...");
|
||||
return cosmic::task::message(cosmic::Action::Cosmic(
|
||||
cosmic::app::Action::Surface(a),
|
||||
));
|
||||
|
|
@ -236,8 +235,6 @@ impl cosmic::Application for App {
|
|||
}
|
||||
|
||||
fn header_start(&self) -> Vec<Element<Self::Message>> {
|
||||
use cosmic::widget::menu::Tree;
|
||||
|
||||
vec![cosmic::widget::responsive_menu_bar().into_element(
|
||||
self.core(),
|
||||
&self.keybinds,
|
||||
|
|
@ -300,6 +297,10 @@ impl cosmic::Application for App {
|
|||
vec![
|
||||
menu::Item::Button("hi 443", None, Action::Hi2),
|
||||
menu::Item::Button("hi 4444", None, Action::Hi),
|
||||
menu::Item::Button("hi 44444", None, Action::Hi3),
|
||||
menu::Item::Button("hi 444445", None, Action::Hi3),
|
||||
menu::Item::Button("hi 4444446", None, Action::Hi3),
|
||||
menu::Item::Button("hi 44444447", None, Action::Hi3),
|
||||
],
|
||||
),
|
||||
],
|
||||
|
|
|
|||
|
|
@ -92,6 +92,7 @@ impl cosmic::Application for App {
|
|||
|date| Message::DateSelected(date),
|
||||
|| Message::PrevMonth,
|
||||
|| Message::NextMonth,
|
||||
chrono::Weekday::Sun,
|
||||
);
|
||||
|
||||
content = content.push(calendar);
|
||||
|
|
|
|||
|
|
@ -11,4 +11,12 @@ tracing-log = "0.2.0"
|
|||
[dependencies.libcosmic]
|
||||
path = "../../"
|
||||
default-features = false
|
||||
features = ["debug", "winit", "tokio", "xdg-portal", "multi-window"]
|
||||
features = [
|
||||
"debug",
|
||||
"winit",
|
||||
"tokio",
|
||||
"xdg-portal",
|
||||
"multi-window",
|
||||
"surface-message",
|
||||
"wayland",
|
||||
]
|
||||
|
|
|
|||
|
|
@ -93,7 +93,7 @@ impl cosmic::Application for App {
|
|||
/// Creates a view after each update.
|
||||
fn view(&self) -> Element<Self::Message> {
|
||||
let widget = cosmic::widget::context_menu(
|
||||
cosmic::widget::button::text(&self.button_label).on_press(Message::Clicked),
|
||||
cosmic::widget::button::text(self.button_label.to_string()).on_press(Message::Clicked),
|
||||
self.context_menu(),
|
||||
);
|
||||
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ use cosmic::widget::menu::action::MenuAction;
|
|||
use cosmic::widget::menu::key_bind::KeyBind;
|
||||
use cosmic::widget::menu::key_bind::Modifier;
|
||||
use cosmic::widget::menu::{self, ItemHeight, ItemWidth};
|
||||
use cosmic::widget::RcElementWrapper;
|
||||
use cosmic::{executor, Element};
|
||||
|
||||
/// Runs application with these settings
|
||||
|
|
@ -155,7 +156,7 @@ impl cosmic::Application for App {
|
|||
|
||||
pub fn menu_bar<'a>(config: &Config, key_binds: &HashMap<KeyBind, Action>) -> Element<'a, Message> {
|
||||
menu::bar(vec![menu::Tree::with_children(
|
||||
menu::root("File"),
|
||||
RcElementWrapper::new(Element::from(menu::root("File"))),
|
||||
menu::items(
|
||||
key_binds,
|
||||
vec![
|
||||
|
|
|
|||
|
|
@ -209,11 +209,11 @@ impl cosmic::Application for App {
|
|||
if size.width < 600.0 {
|
||||
widget::compact_table(&self.table_model)
|
||||
.on_item_left_click(Message::ItemSelect)
|
||||
.item_context(|item| {
|
||||
.item_context(move |item| {
|
||||
Some(widget::menu::items(
|
||||
&HashMap::new(),
|
||||
vec![widget::menu::Item::Button(
|
||||
format!("Action on {}", item.name),
|
||||
format!("Action on {}", item.name.to_string()),
|
||||
None,
|
||||
Action::None,
|
||||
)],
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
//! A context menu is a menu in a graphical user interface that appears upon user interaction, such as a right-click mouse operation.
|
||||
|
||||
use crate::widget::menu::{
|
||||
self, CloseCondition, ItemHeight, ItemWidth, MenuBarState, PathHighlight,
|
||||
self, CloseCondition, ItemHeight, ItemWidth, MenuBarState, PathHighlight, menu_roots_diff,
|
||||
};
|
||||
use derive_setters::Setters;
|
||||
use iced::touch::Finger;
|
||||
|
|
@ -13,8 +13,6 @@ use iced_core::widget::{Tree, Widget, tree};
|
|||
use iced_core::{Length, Point, Size, event, mouse, touch};
|
||||
use std::collections::HashSet;
|
||||
|
||||
use super::dropdown::menu::State;
|
||||
|
||||
/// 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: 'static + Clone>(
|
||||
content: impl Into<crate::Element<'static, Message>> + 'static,
|
||||
|
|
@ -60,7 +58,7 @@ impl<Message: 'static + Clone> Widget<Message, crate::Theme, crate::Renderer>
|
|||
tree::State::new(LocalState {
|
||||
context_cursor: Point::default(),
|
||||
fingers_pressed: Default::default(),
|
||||
menu_state: Default::default(),
|
||||
menu_bar_state: Default::default(),
|
||||
})
|
||||
}
|
||||
|
||||
|
|
@ -72,7 +70,6 @@ impl<Message: 'static + Clone> Widget<Message, crate::Theme, crate::Renderer>
|
|||
// Assign the context menu's elements as this widget's children.
|
||||
if let Some(ref context_menu) = self.context_menu {
|
||||
let mut tree = Tree::empty();
|
||||
tree.state = tree::State::new(MenuBarState::default());
|
||||
tree.children = context_menu
|
||||
.iter()
|
||||
.map(|root| {
|
||||
|
|
@ -95,6 +92,10 @@ impl<Message: 'static + Clone> Widget<Message, crate::Theme, crate::Renderer>
|
|||
|
||||
fn diff(&mut self, tree: &mut Tree) {
|
||||
tree.children[0].diff(self.content.as_widget_mut());
|
||||
let state = tree.state.downcast_mut::<LocalState>();
|
||||
state.menu_bar_state.inner.with_data_mut(|inner| {
|
||||
menu_roots_diff(self.context_menu.as_mut().unwrap(), &mut inner.tree);
|
||||
});
|
||||
|
||||
// if let Some(ref mut context_menus) = self.context_menu {
|
||||
// for (menu, tree) in context_menus
|
||||
|
|
@ -188,9 +189,9 @@ impl<Message: 'static + Clone> Widget<Message, crate::Theme, crate::Renderer>
|
|||
&& (right_button_released(&event) || (touch_lifted(&event) && fingers_pressed == 2))
|
||||
{
|
||||
state.context_cursor = cursor.position().unwrap_or_default();
|
||||
let menu_state = tree.children[1].state.downcast_mut::<MenuBarState>();
|
||||
let state = tree.state.downcast_mut::<LocalState>();
|
||||
|
||||
menu_state.inner.with_data_mut(|state| {
|
||||
state.menu_bar_state.inner.with_data_mut(|state| {
|
||||
state.open = true;
|
||||
state.view_cursor = cursor;
|
||||
});
|
||||
|
|
@ -219,18 +220,10 @@ impl<Message: 'static + Clone> 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;
|
||||
};
|
||||
let context_menu = self.context_menu.as_mut()?;
|
||||
|
||||
if !tree.children[1]
|
||||
.state
|
||||
.downcast_ref::<MenuBarState>()
|
||||
.inner
|
||||
.with_data(|state| state.open)
|
||||
{
|
||||
if !state.menu_bar_state.inner.with_data(|state| state.open) {
|
||||
return None;
|
||||
}
|
||||
|
||||
|
|
@ -239,8 +232,8 @@ impl<Message: 'static + Clone> Widget<Message, crate::Theme, crate::Renderer>
|
|||
bounds.y = state.context_cursor.y;
|
||||
Some(
|
||||
crate::widget::menu::Menu {
|
||||
tree: menu_state,
|
||||
menu_roots: std::borrow::Cow::Borrowed(context_menu),
|
||||
tree: state.menu_bar_state.clone(),
|
||||
menu_roots: std::borrow::Cow::Owned(context_menu.clone()),
|
||||
bounds_expand: 16,
|
||||
menu_overlays_parent: true,
|
||||
close_condition: CloseCondition {
|
||||
|
|
@ -301,5 +294,5 @@ fn touch_lifted(event: &Event) -> bool {
|
|||
pub struct LocalState {
|
||||
context_cursor: Point,
|
||||
fingers_pressed: HashSet<Finger>,
|
||||
menu_state: MenuBarState,
|
||||
menu_bar_state: MenuBarState,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ use crate::{
|
|||
},
|
||||
};
|
||||
|
||||
use iced::{Point, Vector, window};
|
||||
use iced::{Point, Shadow, Vector, window};
|
||||
use iced_core::Border;
|
||||
use iced_widget::core::{
|
||||
Alignment, Clipboard, Element, Layout, Length, Padding, Rectangle, Shell, Widget, event,
|
||||
|
|
@ -429,9 +429,9 @@ where
|
|||
layout.bounds(),
|
||||
self.main_offset as f32,
|
||||
);
|
||||
let anchor_rect = my_state.inner.with_data_mut(|state| {
|
||||
let (anchor_rect, gravity) = my_state.inner.with_data_mut(|state| {
|
||||
state.popup_id.insert(self.window_id, id);
|
||||
state
|
||||
(state
|
||||
.menu_states
|
||||
.iter()
|
||||
.find(|s| s.index.is_none())
|
||||
|
|
@ -452,19 +452,28 @@ where
|
|||
width: r.width as i32,
|
||||
height: r.height as i32,
|
||||
},
|
||||
)
|
||||
), match (state.horizontal_direction, state.vertical_direction) {
|
||||
(Direction::Positive, Direction::Positive) => cctk::wayland_protocols::xdg::shell::client::xdg_positioner::Gravity::BottomRight,
|
||||
(Direction::Positive, Direction::Negative) => cctk::wayland_protocols::xdg::shell::client::xdg_positioner::Gravity::TopRight,
|
||||
(Direction::Negative, Direction::Positive) => cctk::wayland_protocols::xdg::shell::client::xdg_positioner::Gravity::BottomLeft,
|
||||
(Direction::Negative, Direction::Negative) => cctk::wayland_protocols::xdg::shell::client::xdg_positioner::Gravity::TopLeft,
|
||||
})
|
||||
});
|
||||
|
||||
let menu_node = popup_menu.layout(renderer, Limits::NONE.min_width(1.).min_height(1.));
|
||||
let popup_size = menu_node.size();
|
||||
let positioner = SctkPositioner {
|
||||
size: Some((popup_size.width.ceil() as u32 + 2, popup_size.height.ceil() as u32 + 2)),
|
||||
anchor_rect,
|
||||
anchor: cctk::wayland_protocols::xdg::shell::client::xdg_positioner::Anchor::BottomLeft,
|
||||
gravity:cctk::wayland_protocols::xdg::shell::client::xdg_positioner::Gravity::BottomRight,
|
||||
reactive: true,
|
||||
..Default::default()
|
||||
};
|
||||
size: Some((
|
||||
popup_size.width.ceil() as u32 + 2,
|
||||
popup_size.height.ceil() as u32 + 2,
|
||||
)),
|
||||
anchor_rect,
|
||||
anchor:
|
||||
cctk::wayland_protocols::xdg::shell::client::xdg_positioner::Anchor::BottomLeft,
|
||||
gravity,
|
||||
reactive: true,
|
||||
..Default::default()
|
||||
};
|
||||
let parent = self.window_id;
|
||||
shell.publish((surface_action)(crate::surface::action::simple_popup(
|
||||
move || SctkPopupSettings {
|
||||
|
|
@ -496,7 +505,7 @@ where
|
|||
let state = tree.state.downcast_mut::<MenuBarState>();
|
||||
state
|
||||
.inner
|
||||
.with_data_mut(|inner| menu_roots_diff(&mut self.menu_roots, &mut inner.tree))
|
||||
.with_data_mut(|inner| menu_roots_diff(&mut self.menu_roots, &mut inner.tree));
|
||||
}
|
||||
|
||||
fn tag(&self) -> tree::Tag {
|
||||
|
|
@ -550,10 +559,9 @@ where
|
|||
shell: &mut Shell<'_, Message>,
|
||||
viewport: &Rectangle,
|
||||
) -> event::Status {
|
||||
use event::Event::{Mouse, Touch, Window};
|
||||
use event::Event::{Mouse, Touch};
|
||||
use mouse::{Button::Left, Event::ButtonReleased};
|
||||
use touch::Event::{FingerLifted, FingerLost};
|
||||
use window::Event::Focused;
|
||||
|
||||
let root_status = process_root_events(
|
||||
&mut self.menu_roots,
|
||||
|
|
@ -656,7 +664,7 @@ where
|
|||
// draw path highlight
|
||||
if self.path_highlight.is_some() {
|
||||
let styling = theme.appearance(&self.style);
|
||||
if let Some(active) = state.active_root.get(0) {
|
||||
if let Some(active) = state.active_root.first() {
|
||||
let active_bounds = layout
|
||||
.children()
|
||||
.nth(*active)
|
||||
|
|
@ -668,7 +676,7 @@ where
|
|||
radius: styling.bar_border_radius.into(),
|
||||
..Default::default()
|
||||
},
|
||||
shadow: Default::default(),
|
||||
shadow: Shadow::default(),
|
||||
};
|
||||
|
||||
renderer.fill_quad(path_quad, styling.path);
|
||||
|
|
@ -734,7 +742,7 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
impl<'a, Message> From<MenuBar<Message>> for Element<'a, Message, crate::Theme, Renderer>
|
||||
impl<Message> From<MenuBar<Message>> for Element<'_, Message, crate::Theme, Renderer>
|
||||
where
|
||||
Message: Clone + 'static,
|
||||
{
|
||||
|
|
|
|||
|
|
@ -322,15 +322,13 @@ impl MenuState {
|
|||
// self.menu_bounds.child_positions.len()
|
||||
// );
|
||||
|
||||
|
||||
// viewport space children bounds
|
||||
let children_bounds = self.menu_bounds.children_bounds + overlay_offset;
|
||||
let child_nodes = self.menu_bounds.child_positions[start_index..=end_index]
|
||||
.iter()
|
||||
.zip(self.menu_bounds.child_sizes[start_index..=end_index].iter())
|
||||
.zip(menu_tree[start_index..=end_index].iter())
|
||||
.enumerate()
|
||||
.map(|(i, ((cp, size), mt))| {
|
||||
.map(|((cp, size), mt)| {
|
||||
let mut position = *cp;
|
||||
let mut size = *size;
|
||||
|
||||
|
|
@ -343,7 +341,6 @@ impl MenuState {
|
|||
}
|
||||
|
||||
let limits = Limits::new(size, size);
|
||||
|
||||
|
||||
mt.item
|
||||
.layout(&mut tree[mt.index], renderer, &limits)
|
||||
|
|
@ -351,8 +348,7 @@ impl MenuState {
|
|||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
Node::with_children(children_bounds.size(), child_nodes)
|
||||
.move_to(children_bounds.position())
|
||||
Node::with_children(children_bounds.size(), child_nodes).move_to(children_bounds.position())
|
||||
}
|
||||
|
||||
fn layout_single<Message>(
|
||||
|
|
@ -468,12 +464,18 @@ impl<'b, Message: Clone + 'static> Menu<'b, Message> {
|
|||
|
||||
let empty = Vec::new();
|
||||
self.tree.inner.with_data_mut(|data| {
|
||||
if data.active_root.len() < self.depth + 1 || data.menu_states.len() < self.depth + 1 {
|
||||
return Node::new(Size::ZERO);
|
||||
if data.active_root.len() < self.depth + 1 || data.menu_states.len() < self.depth + 1 {
|
||||
return Node::new(limits.min());
|
||||
}
|
||||
|
||||
let overlay_offset = Point::ORIGIN - position;
|
||||
let tree_children = &mut data.tree.children;
|
||||
let children = (if self.is_overlay {0} else {self.depth}..=self.depth)
|
||||
let tree_children: &mut Vec<Tree> = &mut data.tree.children;
|
||||
|
||||
let children = (if self.is_overlay { 0 } else { self.depth }..=if self.is_overlay {
|
||||
data.active_root.len() - 1
|
||||
} else {
|
||||
self.depth
|
||||
})
|
||||
.map(|active_root| {
|
||||
if self.menu_roots.is_empty() {
|
||||
return (&empty, vec![]);
|
||||
|
|
@ -491,7 +493,7 @@ impl<'b, Message: Clone + 'static> Menu<'b, Message> {
|
|||
},
|
||||
);
|
||||
|
||||
data.menu_states[if self.is_overlay {0} else {self.depth}..=self.depth].iter()
|
||||
data.menu_states[if self.is_overlay {0} else {self.depth}..=if self.is_overlay{data.active_root.len() - 1} else {self.depth}].iter()
|
||||
.enumerate()
|
||||
.filter(|ms| self.is_overlay || ms.0 < 1)
|
||||
.fold((roots, Vec::new()), |(menu_root, mut nodes), (_i, ms)| {
|
||||
|
|
@ -509,6 +511,7 @@ impl<'b, Message: Clone + 'static> Menu<'b, Message> {
|
|||
let node_size = children_node.size();
|
||||
intrinsic_size.height += node_size.height;
|
||||
intrinsic_size.width = intrinsic_size.width.max(node_size.width);
|
||||
|
||||
nodes.push(children_node);
|
||||
// if popup just use len 1?
|
||||
// only the last menu can have a None active index
|
||||
|
|
@ -556,9 +559,10 @@ impl<'b, Message: Clone + 'static> Menu<'b, Message> {
|
|||
.with_data(|data| data.open || data.active_root.len() <= self.depth)
|
||||
{
|
||||
return (None, Ignored);
|
||||
};
|
||||
}
|
||||
|
||||
let viewport = layout.bounds();
|
||||
|
||||
let viewport_size = viewport.size();
|
||||
let overlay_offset = Point::ORIGIN - viewport.position();
|
||||
let overlay_cursor = view_cursor.position().unwrap_or_default() - overlay_offset;
|
||||
|
|
@ -634,7 +638,11 @@ impl<'b, Message: Clone + 'static> Menu<'b, Message> {
|
|||
.distance(view_cursor.position().unwrap_or_default())
|
||||
< 2.0
|
||||
{
|
||||
let is_inside = state.menu_states[..=self.depth]
|
||||
let is_inside = state.menu_states[..=if self.is_overlay {
|
||||
state.active_root.len().saturating_sub(1)
|
||||
} else {
|
||||
self.depth
|
||||
}]
|
||||
.iter()
|
||||
.any(|ms| ms.menu_bounds.check_bounds.contains(overlay_cursor));
|
||||
let mut needs_reset = false;
|
||||
|
|
@ -648,6 +656,11 @@ impl<'b, Message: Clone + 'static> Menu<'b, Message> {
|
|||
needs_reset |= self.close_condition.click_outside && !is_inside;
|
||||
|
||||
if needs_reset {
|
||||
#[cfg(all(
|
||||
feature = "wayland",
|
||||
feature = "winit",
|
||||
feature = "surface-message"
|
||||
))]
|
||||
if let Some(handler) = self.on_surface_action.as_ref() {
|
||||
let mut root = self.window_id;
|
||||
let mut depth = self.depth;
|
||||
|
|
@ -658,7 +671,7 @@ impl<'b, Message: Clone + 'static> Menu<'b, Message> {
|
|||
if depth == 0 {
|
||||
break;
|
||||
}
|
||||
root = parent.0.clone();
|
||||
root = *parent.0;
|
||||
depth = depth.saturating_sub(1);
|
||||
}
|
||||
shell
|
||||
|
|
@ -698,7 +711,7 @@ impl<'b, Message: Clone + 'static> Menu<'b, Message> {
|
|||
if !state.open || state.active_root.len() <= self.depth {
|
||||
return;
|
||||
}
|
||||
let active_root = &state.active_root[..=self.depth];
|
||||
let active_root = &state.active_root[..=if self.is_overlay { 0 } else { self.depth }];
|
||||
let viewport = layout.bounds();
|
||||
let viewport_size = viewport.size();
|
||||
let overlay_offset = Point::ORIGIN - viewport.position();
|
||||
|
|
@ -710,18 +723,16 @@ impl<'b, Message: Clone + 'static> Menu<'b, Message> {
|
|||
};
|
||||
|
||||
let styling = theme.appearance(&self.style);
|
||||
let (active_tree, roots) = active_root
|
||||
.iter()
|
||||
.skip(1)
|
||||
.fold(
|
||||
(
|
||||
&state.tree.children[active_root[0]].children,
|
||||
&self.menu_roots[active_root[0]].children,
|
||||
),
|
||||
|(tree, mt), next_active_root| (tree, &mt[*next_active_root].children),
|
||||
);
|
||||
let roots = active_root.iter().skip(1).fold(
|
||||
&self.menu_roots[active_root[0]].children,
|
||||
|mt, next_active_root| (&mt[*next_active_root].children),
|
||||
);
|
||||
let indices = state.get_trimmed_indices(self.depth).collect::<Vec<_>>();
|
||||
state.menu_states[if self.is_overlay {0} else {self.depth}..=self.depth]
|
||||
state.menu_states[if self.is_overlay { 0 } else { self.depth }..=if self.is_overlay {
|
||||
state.menu_states.len() - 1
|
||||
} else {
|
||||
self.depth
|
||||
}]
|
||||
.iter()
|
||||
.zip(layout.children())
|
||||
.enumerate()
|
||||
|
|
@ -729,7 +740,7 @@ impl<'b, Message: Clone + 'static> Menu<'b, Message> {
|
|||
.fold(
|
||||
roots,
|
||||
|menu_roots: &Vec<MenuTree<Message>>, (i, (ms, children_layout))| {
|
||||
let draw_path = self.path_highlight.as_ref().map_or(false, |ph| match ph {
|
||||
let draw_path = self.path_highlight.as_ref().is_some_and(|ph| match ph {
|
||||
PathHighlight::Full => true,
|
||||
PathHighlight::OmitActive => {
|
||||
!indices.is_empty() && i < indices.len() - 1
|
||||
|
|
@ -738,7 +749,9 @@ impl<'b, Message: Clone + 'static> Menu<'b, Message> {
|
|||
});
|
||||
|
||||
// react only to the last menu
|
||||
if self.depth == state.active_root.len() - 1 {
|
||||
let view_cursor = if self.depth == state.active_root.len() - 1
|
||||
|| i == state.menu_states.len() - 1
|
||||
{
|
||||
view_cursor
|
||||
} else {
|
||||
Cursor::Available([-1.0; 2].into())
|
||||
|
|
@ -796,7 +809,7 @@ impl<'b, Message: Clone + 'static> Menu<'b, Message> {
|
|||
.zip(children_layout.children())
|
||||
.for_each(|(mt, clo)| {
|
||||
mt.item.draw(
|
||||
&active_tree[mt.index],
|
||||
&state.tree.children[active_root[0]].children[mt.index],
|
||||
r,
|
||||
theme,
|
||||
style,
|
||||
|
|
@ -858,8 +871,8 @@ impl<Message: Clone + 'static> overlay::Overlay<Message, crate::Theme, crate::Re
|
|||
}
|
||||
}
|
||||
|
||||
impl<'a, Message: std::clone::Clone + 'static> Widget<Message, crate::Theme, crate::Renderer>
|
||||
for Menu<'a, Message>
|
||||
impl<Message: std::clone::Clone + 'static> Widget<Message, crate::Theme, crate::Renderer>
|
||||
for Menu<'_, Message>
|
||||
{
|
||||
fn size(&self) -> Size<Length> {
|
||||
Size {
|
||||
|
|
@ -923,14 +936,7 @@ impl<'a, Message: std::clone::Clone + 'static> Widget<Message, crate::Theme, cra
|
|||
.get(self.depth)
|
||||
.cloned()
|
||||
.unwrap_or_default();
|
||||
// let root_bounds_list = active_roots
|
||||
// .into_iter()
|
||||
// .fold(layout, |l, active_root| {
|
||||
// l.children().nth(active_root).unwrap()
|
||||
// })
|
||||
// .children()
|
||||
// .map(|c| c.bounds())
|
||||
// .collect();
|
||||
|
||||
|
||||
let root_bounds_list = layout
|
||||
.children()
|
||||
|
|
@ -939,7 +945,6 @@ impl<'a, Message: std::clone::Clone + 'static> Widget<Message, crate::Theme, cra
|
|||
.children()
|
||||
.map(|lo| lo.bounds())
|
||||
.collect();
|
||||
// drop(state);
|
||||
|
||||
let mut popup_menu = Menu {
|
||||
tree: self.tree.clone(),
|
||||
|
|
@ -979,8 +984,10 @@ impl<'a, Message: std::clone::Clone + 'static> Widget<Message, crate::Theme, cra
|
|||
layout.bounds(),
|
||||
self.main_offset as f32,
|
||||
);
|
||||
let anchor_rect = self.tree.inner.with_data_mut(|state| {
|
||||
state.menu_states.get(self.depth + 1)
|
||||
let (anchor_rect, gravity) = self.tree.inner.with_data_mut(|state| {
|
||||
(state
|
||||
.menu_states
|
||||
.get(self.depth + 1)
|
||||
.map(|s| s.menu_bounds.parent_bounds)
|
||||
.map_or_else(
|
||||
|| {
|
||||
|
|
@ -998,7 +1005,12 @@ impl<'a, Message: std::clone::Clone + 'static> Widget<Message, crate::Theme, cra
|
|||
width: r.width as i32,
|
||||
height: r.height as i32,
|
||||
},
|
||||
)
|
||||
), match (state.horizontal_direction, state.vertical_direction) {
|
||||
(Direction::Positive, Direction::Positive) => cctk::wayland_protocols::xdg::shell::client::xdg_positioner::Gravity::BottomRight,
|
||||
(Direction::Positive, Direction::Negative) => cctk::wayland_protocols::xdg::shell::client::xdg_positioner::Gravity::TopRight,
|
||||
(Direction::Negative, Direction::Positive) => cctk::wayland_protocols::xdg::shell::client::xdg_positioner::Gravity::BottomLeft,
|
||||
(Direction::Negative, Direction::Negative) => cctk::wayland_protocols::xdg::shell::client::xdg_positioner::Gravity::TopLeft,
|
||||
})
|
||||
});
|
||||
|
||||
let menu_node = Widget::layout(
|
||||
|
|
@ -1013,7 +1025,7 @@ impl<'a, Message: std::clone::Clone + 'static> Widget<Message, crate::Theme, cra
|
|||
size: Some((popup_size.width.ceil() as u32 + 2, popup_size.height.ceil() as u32 + 2)),
|
||||
anchor_rect,
|
||||
anchor: cctk::wayland_protocols::xdg::shell::client::xdg_positioner::Anchor::TopRight,
|
||||
gravity:cctk::wayland_protocols::xdg::shell::client::xdg_positioner::Gravity::BottomRight,
|
||||
gravity,
|
||||
reactive: true,
|
||||
..Default::default()
|
||||
};
|
||||
|
|
@ -1063,6 +1075,7 @@ fn pad_rectangle(rect: Rectangle, padding: Padding) -> Rectangle {
|
|||
}
|
||||
}
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub(super) fn init_root_menu<Message: Clone>(
|
||||
menu: &mut Menu<'_, Message>,
|
||||
renderer: &crate::Renderer,
|
||||
|
|
@ -1074,10 +1087,8 @@ pub(super) fn init_root_menu<Message: Clone>(
|
|||
main_offset: f32,
|
||||
) {
|
||||
menu.tree.inner.with_data_mut(|state| {
|
||||
if !(state
|
||||
.menu_states
|
||||
.get(menu.depth)
|
||||
.is_none()
|
||||
|
||||
if !(state.menu_states.get(menu.depth).is_none()
|
||||
&& (!menu.is_overlay || bar_bounds.contains(overlay_cursor)))
|
||||
|| menu.depth > 0
|
||||
|| !state.open
|
||||
|
|
@ -1130,8 +1141,7 @@ pub(super) fn init_root_menu<Message: Clone>(
|
|||
menu.is_overlay,
|
||||
);
|
||||
set = true;
|
||||
|
||||
state.active_root.insert(menu.depth, i);
|
||||
state.active_root.push(i);
|
||||
let ms = MenuState {
|
||||
index: None,
|
||||
scroll_offset: 0.0,
|
||||
|
|
@ -1145,9 +1155,7 @@ pub(super) fn init_root_menu<Message: Clone>(
|
|||
break;
|
||||
}
|
||||
}
|
||||
if !set {
|
||||
panic!("huh");
|
||||
}
|
||||
debug_assert!(set, "Root not set");
|
||||
});
|
||||
}
|
||||
|
||||
|
|
@ -1165,20 +1173,17 @@ pub(super) fn init_root_popup_menu<Message>(
|
|||
Message: std::clone::Clone,
|
||||
{
|
||||
menu.tree.inner.with_data_mut(|state| {
|
||||
if !(state
|
||||
.menu_states
|
||||
.get(menu.depth)
|
||||
.is_none()
|
||||
if !(state.menu_states.get(menu.depth).is_none()
|
||||
&& (!menu.is_overlay || bar_bounds.contains(overlay_cursor)))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
let active_roots = &state
|
||||
.active_root[..=menu.depth];
|
||||
let active_roots = &state.active_root[..=menu.depth];
|
||||
|
||||
let mut set = false;
|
||||
let mt = active_roots.iter()
|
||||
let mt = active_roots
|
||||
.iter()
|
||||
.skip(1)
|
||||
.fold(&menu.menu_roots[active_roots[0]], |mt, next_active_root| {
|
||||
&mt.children[*next_active_root]
|
||||
|
|
@ -1232,7 +1237,7 @@ pub(super) fn init_root_popup_menu<Message>(
|
|||
// Hack to ensure menu opens properly
|
||||
shell.invalidate_layout();
|
||||
// non tree buttons arent active?
|
||||
assert!(set, "oops");
|
||||
debug_assert!(set, "Root popup menu state was not set.");
|
||||
});
|
||||
}
|
||||
|
||||
|
|
@ -1264,23 +1269,16 @@ fn process_menu_events<Message: std::clone::Clone>(
|
|||
|
||||
let Some(hover_index) = hover.index else {
|
||||
return Status::Ignored;
|
||||
};
|
||||
};
|
||||
|
||||
let (tree, mt) = state.active_root
|
||||
.iter()
|
||||
.skip(1)
|
||||
.fold(
|
||||
// then use menu states for each open menu
|
||||
(
|
||||
&mut state.tree.children[state.active_root[0]].children,
|
||||
&mut menu_roots[state.active_root[0]],
|
||||
),
|
||||
|(tree, mt), next_active_root| (tree, &mut mt.children[*next_active_root]),
|
||||
);
|
||||
|
||||
let mt = state.active_root.iter().skip(1).fold(
|
||||
// then use menu states for each open menu
|
||||
&mut menu_roots[state.active_root[0]],
|
||||
|mt, next_active_root| &mut mt.children[*next_active_root],
|
||||
);
|
||||
|
||||
let mt = &mut mt.children[hover_index];
|
||||
let tree = &mut tree[mt.index];
|
||||
let tree = &mut state.tree.children[state.active_root[0]].children[mt.index];
|
||||
|
||||
// get layout
|
||||
let child_node = hover.layout_single(
|
||||
|
|
@ -1333,18 +1331,14 @@ where
|
|||
let mut new_menu_root = None;
|
||||
|
||||
menu.tree.inner.with_data_mut(|state| {
|
||||
let active_root = &state.active_root[..=menu.depth];
|
||||
|
||||
if state.pressed {
|
||||
return (new_menu_root, Ignored);
|
||||
}
|
||||
|
||||
|
||||
/* When overlay is running, cursor_position in any widget method will go negative
|
||||
but I still want Widget::draw() to react to cursor movement */
|
||||
state.view_cursor = view_cursor;
|
||||
|
||||
// * remove invalid menus
|
||||
|
||||
|
||||
let mut prev_bounds = std::iter::once(menu.bar_bounds)
|
||||
.chain(
|
||||
if menu.is_overlay {
|
||||
|
|
@ -1355,7 +1349,7 @@ where
|
|||
.map(|s| s.menu_bounds.children_bounds),
|
||||
)
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
|
||||
if menu.is_overlay && menu.close_condition.leave {
|
||||
for i in (0..state.menu_states.len()).rev() {
|
||||
let mb = &state.menu_states[i].menu_bounds;
|
||||
|
|
@ -1369,22 +1363,37 @@ where
|
|||
break;
|
||||
}
|
||||
prev_bounds.pop();
|
||||
state.active_root.pop();
|
||||
state.menu_states.pop();
|
||||
}
|
||||
} else if menu.is_overlay {
|
||||
for i in (0..state.menu_states.len()).rev() {
|
||||
let mb = &state.menu_states[i].menu_bounds;
|
||||
|
||||
if mb.parent_bounds.contains(overlay_cursor)
|
||||
|| mb.children_bounds.contains(overlay_cursor)
|
||||
|| prev_bounds.iter().all(|pvb| !pvb.contains(overlay_cursor))
|
||||
{
|
||||
break;
|
||||
}
|
||||
prev_bounds.pop();
|
||||
state.active_root.pop();
|
||||
state.menu_states.pop();
|
||||
}
|
||||
}
|
||||
|
||||
// * update active item
|
||||
let menu_states_len = state.menu_states.len();
|
||||
|
||||
let Some(last_menu_state) = state.menu_states.get_mut(if menu.is_overlay {
|
||||
menu_states_len - 1
|
||||
menu_states_len.saturating_sub(1)
|
||||
} else {
|
||||
menu.depth
|
||||
}) else {
|
||||
if menu.is_overlay {
|
||||
// no menus left
|
||||
// TODO do we want to avoid this for popups?
|
||||
state.active_root.remove(menu.depth);
|
||||
// state.active_root.remove(menu.depth);
|
||||
|
||||
// keep state.open when the cursor is still inside the menu bar
|
||||
// this allows the overlay to keep drawing when the cursor is
|
||||
|
|
@ -1406,31 +1415,32 @@ where
|
|||
|| menu.is_overlay && !last_children_bounds.contains(overlay_cursor)
|
||||
// cursor is outside
|
||||
{
|
||||
|
||||
last_menu_state.index = None;
|
||||
return (new_menu_root, Captured);
|
||||
}
|
||||
// cursor is in the children part
|
||||
|
||||
// TODO set active root here even when not a tree.
|
||||
// ensure that the
|
||||
|
||||
// calc new index
|
||||
let height_diff = (overlay_cursor.y
|
||||
- (last_children_bounds.y + last_menu_state.scroll_offset))
|
||||
.clamp(0.0, last_children_bounds.height - 0.001);
|
||||
|
||||
let (active_tree, roots) = active_root
|
||||
.iter()
|
||||
.skip(1)
|
||||
.fold(
|
||||
(
|
||||
&mut state.tree.children[active_root[0]].children,
|
||||
&menu.menu_roots[active_root[0]].children,
|
||||
),
|
||||
|(tree, mt), next_active_root| (tree, &mt[*next_active_root].children),
|
||||
);
|
||||
let active_root = if menu.is_overlay {
|
||||
&state.active_root
|
||||
} else {
|
||||
&state.active_root[..=menu.depth]
|
||||
};
|
||||
|
||||
let active_menu = roots;
|
||||
if state.pressed {
|
||||
return (new_menu_root, Ignored);
|
||||
}
|
||||
let roots = active_root.iter().skip(1).fold(
|
||||
&menu.menu_roots[active_root[0]].children,
|
||||
|mt, next_active_root| &mt[*next_active_root].children,
|
||||
);
|
||||
let tree = &mut state.tree.children[active_root[0]].children;
|
||||
|
||||
let active_menu: &Vec<MenuTree<Message>> = roots;
|
||||
let new_index = match menu.item_height {
|
||||
ItemHeight::Uniform(u) => (height_diff / f32::from(u)).floor() as usize,
|
||||
ItemHeight::Static(_) | ItemHeight::Dynamic(_) => {
|
||||
|
|
@ -1446,12 +1456,10 @@ where
|
|||
}
|
||||
};
|
||||
|
||||
|
||||
let remove = !menu.is_overlay
|
||||
&& last_menu_state
|
||||
.index
|
||||
.as_ref()
|
||||
.is_some_and(|i| *i != new_index && !active_menu[*i].children.is_empty());
|
||||
let remove = last_menu_state
|
||||
.index
|
||||
.as_ref()
|
||||
.is_some_and(|i| *i != new_index && !active_menu[*i].children.is_empty());
|
||||
|
||||
#[cfg(all(feature = "wayland", feature = "winit", feature = "surface-message"))]
|
||||
{
|
||||
|
|
@ -1465,9 +1473,9 @@ where
|
|||
}
|
||||
}
|
||||
let item = &active_menu[new_index];
|
||||
|
||||
// set new index
|
||||
let old_index = last_menu_state.index.replace(new_index);
|
||||
|
||||
// get new active item
|
||||
// * add new menu if the new item is a menu
|
||||
if !item.children.is_empty() && old_index.is_none_or(|i| i != new_index) {
|
||||
|
|
@ -1504,18 +1512,22 @@ where
|
|||
&aod,
|
||||
menu.bounds_expand,
|
||||
item_bounds,
|
||||
active_tree,
|
||||
tree,
|
||||
menu.is_overlay,
|
||||
),
|
||||
};
|
||||
|
||||
|
||||
new_menu_root = Some((new_index, ms.clone()));
|
||||
state.menu_states.truncate(menu.depth + 1);
|
||||
if menu.is_overlay {
|
||||
state.active_root.push(new_index);
|
||||
} else {
|
||||
state.menu_states.truncate(menu.depth + 1);
|
||||
}
|
||||
state.menu_states.push(ms);
|
||||
} else if remove {
|
||||
} else if !menu.is_overlay && remove {
|
||||
state.menu_states.truncate(menu.depth + 1);
|
||||
}
|
||||
|
||||
|
||||
(new_menu_root, Captured)
|
||||
})
|
||||
}
|
||||
|
|
@ -1534,7 +1546,6 @@ where
|
|||
use mouse::ScrollDelta;
|
||||
|
||||
menu.tree.inner.with_data_mut(|state| {
|
||||
|
||||
let delta_y = match delta {
|
||||
ScrollDelta::Lines { y, .. } => y * 60.0,
|
||||
ScrollDelta::Pixels { y, .. } => y,
|
||||
|
|
|
|||
|
|
@ -210,10 +210,11 @@ where
|
|||
///
|
||||
/// # Returns
|
||||
/// - A vector of `MenuTree`.
|
||||
#[must_use]
|
||||
pub fn menu_items<
|
||||
A: MenuAction<Message = Message>,
|
||||
L: Into<Cow<'static, str>> + 'static,
|
||||
Message: 'static + std::clone::Clone + std::fmt::Debug,
|
||||
Message: 'static + std::clone::Clone,
|
||||
>(
|
||||
key_binds: &HashMap<KeyBind, A>,
|
||||
children: Vec<MenuItem<A, L>>,
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
use std::collections::HashMap;
|
||||
|
||||
use apply::Apply;
|
||||
use iced::window;
|
||||
|
||||
use crate::{
|
||||
Core, Element,
|
||||
|
|
@ -10,6 +9,7 @@ use crate::{
|
|||
|
||||
use super::menu::{self, ItemHeight, ItemWidth};
|
||||
|
||||
#[must_use]
|
||||
pub fn responsive_menu_bar() -> ResponsiveMenuBar {
|
||||
ResponsiveMenuBar::default()
|
||||
}
|
||||
|
|
@ -34,18 +34,21 @@ impl Default for ResponsiveMenuBar {
|
|||
|
||||
impl ResponsiveMenuBar {
|
||||
/// Set the item width
|
||||
#[must_use]
|
||||
pub fn item_width(mut self, item_width: ItemWidth) -> Self {
|
||||
self.item_width = item_width;
|
||||
self
|
||||
}
|
||||
|
||||
/// Set the item height
|
||||
#[must_use]
|
||||
pub fn item_height(mut self, item_height: ItemHeight) -> Self {
|
||||
self.item_height = item_height;
|
||||
self
|
||||
}
|
||||
|
||||
/// Set the spacing
|
||||
#[must_use]
|
||||
pub fn spacing(mut self, spacing: f32) -> Self {
|
||||
self.spacing = spacing;
|
||||
self
|
||||
|
|
@ -56,7 +59,7 @@ impl ResponsiveMenuBar {
|
|||
/// Will panic if the menu bar collapses without tracking the size
|
||||
pub fn into_element<
|
||||
'a,
|
||||
Message: std::fmt::Debug + Clone + 'static,
|
||||
Message: Clone + 'static,
|
||||
A: menu::Action<Message = Message> + Clone,
|
||||
S: Into<std::borrow::Cow<'static, str>> + 'static,
|
||||
>(
|
||||
|
|
|
|||
|
|
@ -20,9 +20,9 @@ pub type MultiSelectTableView<'a, Item, Category, Message> =
|
|||
TableView<'a, MultiSelect, Item, Category, Message>;
|
||||
pub type MultiSelectModel<Item, Category> = Model<MultiSelect, Item, Category>;
|
||||
|
||||
pub fn table<'a, SelectionMode, Item, Category, Message>(
|
||||
model: &'a Model<SelectionMode, Item, Category>,
|
||||
) -> TableView<'a, SelectionMode, Item, Category, Message>
|
||||
pub fn table<SelectionMode, Item, Category, Message>(
|
||||
model: &Model<SelectionMode, Item, Category>,
|
||||
) -> TableView<'_, SelectionMode, Item, Category, Message>
|
||||
where
|
||||
Message: Clone,
|
||||
SelectionMode: Default,
|
||||
|
|
@ -33,9 +33,9 @@ where
|
|||
TableView::new(model)
|
||||
}
|
||||
|
||||
pub fn compact_table<'a, SelectionMode, Item, Category, Message>(
|
||||
model: &'a Model<SelectionMode, Item, Category>,
|
||||
) -> CompactTableView<'a, SelectionMode, Item, Category, Message>
|
||||
pub fn compact_table<SelectionMode, Item, Category, Message>(
|
||||
model: &Model<SelectionMode, Item, Category>,
|
||||
) -> CompactTableView<'_, SelectionMode, Item, Category, Message>
|
||||
where
|
||||
Message: Clone,
|
||||
SelectionMode: Default,
|
||||
|
|
|
|||
|
|
@ -47,9 +47,8 @@ where
|
|||
pub(super) item_context_builder: Box<dyn Fn(&Item) -> Option<Vec<menu::Tree<Message>>>>,
|
||||
}
|
||||
|
||||
impl<SelectionMode, Item, Category, Message>
|
||||
From<CompactTableView<'static, SelectionMode, Item, Category, Message>>
|
||||
for Element<'static, Message>
|
||||
impl<'a, SelectionMode, Item, Category, Message>
|
||||
From<CompactTableView<'a, SelectionMode, Item, Category, Message>> for Element<'a, Message>
|
||||
where
|
||||
Category: ItemCategory,
|
||||
Item: ItemInterface<Category>,
|
||||
|
|
@ -57,7 +56,7 @@ where
|
|||
SelectionMode: Default,
|
||||
Message: Clone + 'static,
|
||||
{
|
||||
fn from(val: CompactTableView<'static, SelectionMode, Item, Category, Message>) -> Self {
|
||||
fn from(val: CompactTableView<'a, SelectionMode, Item, Category, Message>) -> Self {
|
||||
let cosmic_theme::Spacing { space_xxxs, .. } = theme::spacing();
|
||||
val.model
|
||||
.iter()
|
||||
|
|
@ -172,7 +171,7 @@ where
|
|||
)
|
||||
.apply(Element::from)
|
||||
})
|
||||
.collect::<Vec<Element<'static, Message>>>()
|
||||
.collect::<Vec<Element<'a, Message>>>()
|
||||
.apply(widget::column::with_children)
|
||||
.spacing(val.item_spacing)
|
||||
.padding(val.element_padding)
|
||||
|
|
|
|||
|
|
@ -67,8 +67,8 @@ where
|
|||
pub(super) category_context_builder: Box<dyn Fn(Category) -> Option<Vec<menu::Tree<Message>>>>,
|
||||
}
|
||||
|
||||
impl<SelectionMode, Item, Category, Message>
|
||||
From<TableView<'static, SelectionMode, Item, Category, Message>> for Element<'static, Message>
|
||||
impl<'a, SelectionMode, Item, Category, Message>
|
||||
From<TableView<'a, SelectionMode, Item, Category, Message>> for Element<'a, Message>
|
||||
where
|
||||
Category: ItemCategory,
|
||||
Item: ItemInterface<Category>,
|
||||
|
|
@ -76,7 +76,7 @@ where
|
|||
SelectionMode: Default,
|
||||
Message: Clone + 'static,
|
||||
{
|
||||
fn from(val: TableView<'static, SelectionMode, Item, Category, Message>) -> Self {
|
||||
fn from(val: TableView<'a, SelectionMode, Item, Category, Message>) -> Self {
|
||||
// Header row
|
||||
let header_row = val
|
||||
.model
|
||||
|
|
@ -125,7 +125,7 @@ where
|
|||
.apply(|mouse_area| widget::context_menu(mouse_area, cat_context_tree))
|
||||
.apply(Element::from)
|
||||
})
|
||||
.collect::<Vec<Element<'static, Message>>>()
|
||||
.collect::<Vec<Element<'a, Message>>>()
|
||||
.apply(widget::row::with_children)
|
||||
.apply(Element::from);
|
||||
// Build the items
|
||||
|
|
@ -234,12 +234,12 @@ where
|
|||
]
|
||||
})
|
||||
.flatten()
|
||||
.collect::<Vec<Element<'static, Message>>>()
|
||||
.collect::<Vec<Element<'a, Message>>>()
|
||||
};
|
||||
vec![vec![header_row], items_full]
|
||||
.into_iter()
|
||||
.flatten()
|
||||
.collect::<Vec<Element<'static, Message>>>()
|
||||
.collect::<Vec<Element<'a, Message>>>()
|
||||
.apply(widget::column::with_children)
|
||||
.width(val.width)
|
||||
.height(val.height)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue