This commit is contained in:
parent
8e7e6df35c
commit
1e1912d419
2 changed files with 179 additions and 48 deletions
127
src/main.rs
127
src/main.rs
|
|
@ -10,7 +10,8 @@ use cosmic::iced::alignment::Vertical;
|
||||||
use cosmic::iced::keyboard::{Key, Modifiers};
|
use cosmic::iced::keyboard::{Key, Modifiers};
|
||||||
use cosmic::iced::window::{Mode, Position};
|
use cosmic::iced::window::{Mode, Position};
|
||||||
use cosmic::iced::{
|
use cosmic::iced::{
|
||||||
self, event, window, Background as IcedBackground, Border, Length,
|
self, event, window, Background as IcedBackground, Border, Color,
|
||||||
|
Length,
|
||||||
};
|
};
|
||||||
use cosmic::iced_core::text::Wrapping;
|
use cosmic::iced_core::text::Wrapping;
|
||||||
use cosmic::iced_futures::Subscription;
|
use cosmic::iced_futures::Subscription;
|
||||||
|
|
@ -22,8 +23,9 @@ use cosmic::widget::menu::{ItemWidth, KeyBind};
|
||||||
use cosmic::widget::nav_bar::nav_bar_style;
|
use cosmic::widget::nav_bar::nav_bar_style;
|
||||||
use cosmic::widget::tooltip::Position as TPosition;
|
use cosmic::widget::tooltip::Position as TPosition;
|
||||||
use cosmic::widget::{
|
use cosmic::widget::{
|
||||||
button, horizontal_space, mouse_area, nav_bar, nav_bar_toggle,
|
button, context_menu, horizontal_space, mouse_area, nav_bar,
|
||||||
responsive, search_input, tooltip, vertical_space, Space,
|
nav_bar_toggle, responsive, scrollable, search_input, tooltip,
|
||||||
|
vertical_space, Space,
|
||||||
};
|
};
|
||||||
use cosmic::widget::{container, text};
|
use cosmic::widget::{container, text};
|
||||||
use cosmic::widget::{icon, slider};
|
use cosmic::widget::{icon, slider};
|
||||||
|
|
@ -129,6 +131,7 @@ struct App {
|
||||||
library_dragged_item: Option<ServiceItem>,
|
library_dragged_item: Option<ServiceItem>,
|
||||||
fontdb: Arc<fontdb::Database>,
|
fontdb: Arc<fontdb::Database>,
|
||||||
menu_keys: HashMap<KeyBind, MenuAction>,
|
menu_keys: HashMap<KeyBind, MenuAction>,
|
||||||
|
context_menu: Option<usize>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
|
|
@ -152,9 +155,11 @@ enum Message {
|
||||||
AddSelectServiceItem(usize),
|
AddSelectServiceItem(usize),
|
||||||
HoveredServiceItem(Option<usize>),
|
HoveredServiceItem(Option<usize>),
|
||||||
AddServiceItem(usize, ServiceItem),
|
AddServiceItem(usize, ServiceItem),
|
||||||
|
RemoveServiceItem(usize),
|
||||||
AddServiceItemDrop(usize),
|
AddServiceItemDrop(usize),
|
||||||
AppendServiceItem(ServiceItem),
|
AppendServiceItem(ServiceItem),
|
||||||
ReorderService(usize, usize),
|
ReorderService(usize, usize),
|
||||||
|
ContextMenuItem(usize),
|
||||||
SearchFocus,
|
SearchFocus,
|
||||||
Search(String),
|
Search(String),
|
||||||
CloseSearch,
|
CloseSearch,
|
||||||
|
|
@ -175,6 +180,7 @@ enum MenuAction {
|
||||||
SaveAs,
|
SaveAs,
|
||||||
Open,
|
Open,
|
||||||
OpenSettings,
|
OpenSettings,
|
||||||
|
DeleteItem(usize),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl menu::Action for MenuAction {
|
impl menu::Action for MenuAction {
|
||||||
|
|
@ -187,6 +193,9 @@ impl menu::Action for MenuAction {
|
||||||
MenuAction::SaveAs => Message::SaveAs,
|
MenuAction::SaveAs => Message::SaveAs,
|
||||||
MenuAction::Open => Message::Open,
|
MenuAction::Open => Message::Open,
|
||||||
MenuAction::OpenSettings => Message::OpenSettings,
|
MenuAction::OpenSettings => Message::OpenSettings,
|
||||||
|
MenuAction::DeleteItem(index) => {
|
||||||
|
Message::RemoveServiceItem(*index)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -324,6 +333,7 @@ impl cosmic::Application for App {
|
||||||
fontdb: Arc::clone(&fontdb),
|
fontdb: Arc::clone(&fontdb),
|
||||||
menu_keys,
|
menu_keys,
|
||||||
hovered_item: None,
|
hovered_item: None,
|
||||||
|
context_menu: None,
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut batch = vec![];
|
let mut batch = vec![];
|
||||||
|
|
@ -1093,6 +1103,15 @@ impl cosmic::Application for App {
|
||||||
self.presenter.update_items(self.service.clone());
|
self.presenter.update_items(self.service.clone());
|
||||||
Task::none()
|
Task::none()
|
||||||
}
|
}
|
||||||
|
Message::RemoveServiceItem(index) => {
|
||||||
|
self.service.remove(index);
|
||||||
|
self.presenter.update_items(self.service.clone());
|
||||||
|
Task::none()
|
||||||
|
}
|
||||||
|
Message::ContextMenuItem(index) => {
|
||||||
|
self.context_menu = Some(index);
|
||||||
|
Task::none()
|
||||||
|
}
|
||||||
Message::AddServiceItemDrop(index) => {
|
Message::AddServiceItemDrop(index) => {
|
||||||
if let Some(item) = &self.library_dragged_item {
|
if let Some(item) = &self.library_dragged_item {
|
||||||
self.service.insert(index, item.clone());
|
self.service.insert(index, item.clone());
|
||||||
|
|
@ -1484,6 +1503,7 @@ where
|
||||||
&item.title,
|
&item.title,
|
||||||
size.width,
|
size.width,
|
||||||
))
|
))
|
||||||
|
.align_y(Vertical::Center)
|
||||||
.wrapping(Wrapping::None)
|
.wrapping(Wrapping::None)
|
||||||
.into()
|
.into()
|
||||||
});
|
});
|
||||||
|
|
@ -1492,6 +1512,7 @@ where
|
||||||
.align_y(Vertical::Center)
|
.align_y(Vertical::Center)
|
||||||
.spacing(cosmic::theme::spacing().space_xs),
|
.spacing(cosmic::theme::spacing().space_xs),
|
||||||
)
|
)
|
||||||
|
.height(cosmic::theme::spacing().space_xl)
|
||||||
.padding(cosmic::theme::spacing().space_s)
|
.padding(cosmic::theme::spacing().space_s)
|
||||||
.class(cosmic::theme::style::Container::Secondary)
|
.class(cosmic::theme::style::Container::Secondary)
|
||||||
.style(move |t| {
|
.style(move |t| {
|
||||||
|
|
@ -1524,9 +1545,44 @@ where
|
||||||
index,
|
index,
|
||||||
))
|
))
|
||||||
.on_drag(Message::None)
|
.on_drag(Message::None)
|
||||||
|
.on_right_press(Message::ContextMenuItem(index))
|
||||||
.on_release(Message::SelectServiceItem(index));
|
.on_release(Message::SelectServiceItem(index));
|
||||||
let tooltip = tooltip(
|
let single_item = if let Some(context_menu_item) =
|
||||||
|
self.context_menu
|
||||||
|
{
|
||||||
|
if context_menu_item == index {
|
||||||
|
let context_menu = context_menu(
|
||||||
mouse_area,
|
mouse_area,
|
||||||
|
self.context_menu.map_or_else(
|
||||||
|
|| None,
|
||||||
|
|i| {
|
||||||
|
if i == index {
|
||||||
|
let menu =
|
||||||
|
vec![menu::Item::Button(
|
||||||
|
"Delete",
|
||||||
|
None,
|
||||||
|
MenuAction::DeleteItem(index),
|
||||||
|
)];
|
||||||
|
Some(menu::items(
|
||||||
|
&HashMap::new(),
|
||||||
|
menu,
|
||||||
|
))
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
},
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.close_on_escape(true);
|
||||||
|
Element::from(context_menu)
|
||||||
|
} else {
|
||||||
|
Element::from(mouse_area)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Element::from(mouse_area)
|
||||||
|
};
|
||||||
|
let tooltip = tooltip(
|
||||||
|
single_item,
|
||||||
text::body(item.kind.to_string()),
|
text::body(item.kind.to_string()),
|
||||||
TPosition::Right,
|
TPosition::Right,
|
||||||
)
|
)
|
||||||
|
|
@ -1555,14 +1611,10 @@ where
|
||||||
.into()
|
.into()
|
||||||
});
|
});
|
||||||
|
|
||||||
let column = column![
|
let scrollable = scrollable(
|
||||||
text::heading("Service List")
|
draggable::column::column(list)
|
||||||
.center()
|
.spacing(10)
|
||||||
.width(Length::Fill),
|
.on_drag(|event| match event {
|
||||||
iced::widget::horizontal_rule(1),
|
|
||||||
draggable::column::column(list).spacing(10).on_drag(
|
|
||||||
|event| {
|
|
||||||
match event {
|
|
||||||
draggable::DragEvent::Picked { .. } => {
|
draggable::DragEvent::Picked { .. } => {
|
||||||
Message::None
|
Message::None
|
||||||
}
|
}
|
||||||
|
|
@ -1570,16 +1622,44 @@ where
|
||||||
index,
|
index,
|
||||||
target_index,
|
target_index,
|
||||||
..
|
..
|
||||||
} => Message::ReorderService(
|
} => Message::ReorderService(index, target_index),
|
||||||
index,
|
|
||||||
target_index,
|
|
||||||
),
|
|
||||||
draggable::DragEvent::Canceled { .. } => {
|
draggable::DragEvent::Canceled { .. } => {
|
||||||
Message::None
|
Message::None
|
||||||
}
|
}
|
||||||
}
|
})
|
||||||
}
|
.style(|t| draggable::column::Style {
|
||||||
),
|
scale: 1.05,
|
||||||
|
moved_item_overlay: Color::from(
|
||||||
|
t.cosmic().primary.base,
|
||||||
|
)
|
||||||
|
.scale_alpha(0.2)
|
||||||
|
.into(),
|
||||||
|
ghost_border: Border {
|
||||||
|
width: 1.0,
|
||||||
|
color: t.cosmic().secondary.base.into(),
|
||||||
|
radius: t.cosmic().radius_m().into(),
|
||||||
|
},
|
||||||
|
ghost_background: Color::from(
|
||||||
|
t.cosmic().secondary.base,
|
||||||
|
)
|
||||||
|
.scale_alpha(0.2)
|
||||||
|
.into(),
|
||||||
|
})
|
||||||
|
.height(Length::Shrink),
|
||||||
|
)
|
||||||
|
.anchor_top()
|
||||||
|
.height(Length::Fill);
|
||||||
|
|
||||||
|
let column = column![
|
||||||
|
text::heading("Service List")
|
||||||
|
.center()
|
||||||
|
.width(Length::Fill),
|
||||||
|
iced::widget::horizontal_rule(1),
|
||||||
|
scrollable
|
||||||
|
]
|
||||||
|
.padding(10)
|
||||||
|
.spacing(10);
|
||||||
|
let container = Container::new(stack![
|
||||||
dnd_destination(
|
dnd_destination(
|
||||||
vertical_space().width(Length::Fill),
|
vertical_space().width(Length::Fill),
|
||||||
vec!["application/service-item".into()]
|
vec!["application/service-item".into()]
|
||||||
|
|
@ -1601,11 +1681,10 @@ where
|
||||||
debug!(?item);
|
debug!(?item);
|
||||||
Message::AppendServiceItem(item)
|
Message::AppendServiceItem(item)
|
||||||
}
|
}
|
||||||
)
|
),
|
||||||
]
|
column
|
||||||
.padding(10)
|
])
|
||||||
.spacing(10);
|
.style(nav_bar_style);
|
||||||
let container = Container::new(column).style(nav_bar_style);
|
|
||||||
|
|
||||||
container.center(Length::FillPortion(2)).into()
|
container.center(Length::FillPortion(2)).into()
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -363,7 +363,7 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
fn diff(&mut self, tree: &mut Tree) {
|
fn diff(&mut self, tree: &mut Tree) {
|
||||||
tree.diff_children(&mut self.children);
|
tree.diff_children(self.children.as_mut_slice());
|
||||||
}
|
}
|
||||||
|
|
||||||
fn size(&self) -> Size<Length> {
|
fn size(&self) -> Size<Length> {
|
||||||
|
|
@ -410,9 +410,14 @@ where
|
||||||
.iter()
|
.iter()
|
||||||
.zip(&mut tree.children)
|
.zip(&mut tree.children)
|
||||||
.zip(layout.children())
|
.zip(layout.children())
|
||||||
.for_each(|((child, state), layout)| {
|
.for_each(|((child, state), c_layout)| {
|
||||||
child.as_widget().operate(
|
child.as_widget().operate(
|
||||||
state, layout, renderer, operation,
|
state,
|
||||||
|
c_layout.with_virtual_offset(
|
||||||
|
layout.virtual_offset(),
|
||||||
|
),
|
||||||
|
renderer,
|
||||||
|
operation,
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
@ -557,11 +562,12 @@ where
|
||||||
.iter_mut()
|
.iter_mut()
|
||||||
.zip(&mut tree.children)
|
.zip(&mut tree.children)
|
||||||
.zip(layout.children())
|
.zip(layout.children())
|
||||||
.map(|((child, state), layout)| {
|
.map(|((child, state), c_layout)| {
|
||||||
child.as_widget_mut().on_event(
|
child.as_widget_mut().on_event(
|
||||||
state,
|
state,
|
||||||
event.clone(),
|
event.clone(),
|
||||||
layout,
|
c_layout
|
||||||
|
.with_virtual_offset(layout.virtual_offset()),
|
||||||
cursor,
|
cursor,
|
||||||
renderer,
|
renderer,
|
||||||
clipboard,
|
clipboard,
|
||||||
|
|
@ -592,9 +598,14 @@ where
|
||||||
.iter()
|
.iter()
|
||||||
.zip(&tree.children)
|
.zip(&tree.children)
|
||||||
.zip(layout.children())
|
.zip(layout.children())
|
||||||
.map(|((child, state), layout)| {
|
.map(|((child, state), c_layout)| {
|
||||||
child.as_widget().mouse_interaction(
|
child.as_widget().mouse_interaction(
|
||||||
state, layout, cursor, viewport, renderer,
|
state,
|
||||||
|
c_layout
|
||||||
|
.with_virtual_offset(layout.virtual_offset()),
|
||||||
|
cursor,
|
||||||
|
viewport,
|
||||||
|
renderer,
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
.max()
|
.max()
|
||||||
|
|
@ -606,7 +617,7 @@ where
|
||||||
tree: &Tree,
|
tree: &Tree,
|
||||||
renderer: &mut Renderer,
|
renderer: &mut Renderer,
|
||||||
theme: &Theme,
|
theme: &Theme,
|
||||||
defaults: &renderer::Style,
|
default_style: &renderer::Style,
|
||||||
layout: Layout<'_>,
|
layout: Layout<'_>,
|
||||||
cursor: mouse::Cursor,
|
cursor: mouse::Cursor,
|
||||||
viewport: &Rectangle,
|
viewport: &Rectangle,
|
||||||
|
|
@ -672,7 +683,7 @@ where
|
||||||
state,
|
state,
|
||||||
renderer,
|
renderer,
|
||||||
theme,
|
theme,
|
||||||
defaults,
|
default_style,
|
||||||
child_layout,
|
child_layout,
|
||||||
cursor,
|
cursor,
|
||||||
viewport,
|
viewport,
|
||||||
|
|
@ -712,7 +723,7 @@ where
|
||||||
state,
|
state,
|
||||||
renderer,
|
renderer,
|
||||||
theme,
|
theme,
|
||||||
defaults,
|
default_style,
|
||||||
child_layout,
|
child_layout,
|
||||||
cursor,
|
cursor,
|
||||||
viewport,
|
viewport,
|
||||||
|
|
@ -762,20 +773,39 @@ where
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
// Draw all children normally when not dragging
|
// Draw all children normally when not dragging
|
||||||
for ((child, state), layout) in self
|
if let Some(clipped_viewport) =
|
||||||
|
layout.bounds().intersection(viewport)
|
||||||
|
{
|
||||||
|
let viewport = if self.clip {
|
||||||
|
&clipped_viewport
|
||||||
|
} else {
|
||||||
|
viewport
|
||||||
|
};
|
||||||
|
for ((child, state), c_layout) in self
|
||||||
.children
|
.children
|
||||||
.iter()
|
.iter()
|
||||||
.zip(&tree.children)
|
.zip(&tree.children)
|
||||||
.zip(layout.children())
|
.zip(layout.children())
|
||||||
|
.filter(|(_, layout)| {
|
||||||
|
layout.bounds().intersects(viewport)
|
||||||
|
})
|
||||||
{
|
{
|
||||||
child.as_widget().draw(
|
child.as_widget().draw(
|
||||||
state, renderer, theme, defaults, layout,
|
state,
|
||||||
cursor, viewport,
|
renderer,
|
||||||
|
theme,
|
||||||
|
default_style,
|
||||||
|
c_layout.with_virtual_offset(
|
||||||
|
layout.virtual_offset(),
|
||||||
|
),
|
||||||
|
cursor,
|
||||||
|
viewport,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn overlay<'b>(
|
fn overlay<'b>(
|
||||||
&'b mut self,
|
&'b mut self,
|
||||||
|
|
@ -792,6 +822,28 @@ where
|
||||||
translation,
|
translation,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn drag_destinations(
|
||||||
|
&self,
|
||||||
|
state: &Tree,
|
||||||
|
layout: Layout<'_>,
|
||||||
|
renderer: &Renderer,
|
||||||
|
dnd_rectangles: &mut cosmic::iced_core::clipboard::DndDestinationRectangles,
|
||||||
|
) {
|
||||||
|
for ((e, c_layout), state) in self
|
||||||
|
.children
|
||||||
|
.iter()
|
||||||
|
.zip(layout.children())
|
||||||
|
.zip(state.children.iter())
|
||||||
|
{
|
||||||
|
e.as_widget().drag_destinations(
|
||||||
|
state,
|
||||||
|
c_layout.with_virtual_offset(layout.virtual_offset()),
|
||||||
|
renderer,
|
||||||
|
dnd_rectangles,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, Message, Theme, Renderer>
|
impl<'a, Message, Theme, Renderer>
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue