On wayland, place context menus into popups, fixes #1090
This commit is contained in:
parent
050e043867
commit
605f44763b
7 changed files with 211 additions and 62 deletions
1
Cargo.lock
generated
1
Cargo.lock
generated
|
|
@ -1484,6 +1484,7 @@ dependencies = [
|
|||
"bzip2",
|
||||
"chrono",
|
||||
"compio",
|
||||
"cosmic-client-toolkit",
|
||||
"cosmic-mime-apps",
|
||||
"dirs 6.0.0",
|
||||
"env_logger",
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@ icu = { version = "1.5.0", features = [
|
|||
"compiled_data",
|
||||
"icu_datetime_experimental",
|
||||
] }
|
||||
cctk = { git = "https://github.com/pop-os/cosmic-protocols", package = "cosmic-client-toolkit", rev = "178eb0b", optional = true }
|
||||
cosmic-mime-apps = { git = "https://github.com/pop-os/cosmic-mime-apps.git", optional = true }
|
||||
dirs = "6.0.0"
|
||||
env_logger = "0.11"
|
||||
|
|
@ -106,7 +107,7 @@ io-uring = ["compio/io-uring", "dep:io-uring"]
|
|||
io-uring-bindgen = ["io-uring?/bindgen"]
|
||||
jemalloc = ["dep:tikv-jemallocator"]
|
||||
notify = ["dep:notify-rust"]
|
||||
wayland = ["libcosmic/wayland", "dep:wayland-client"]
|
||||
wayland = ["libcosmic/wayland", "dep:cctk", "dep:wayland-client"]
|
||||
wgpu = ["libcosmic/wgpu"]
|
||||
|
||||
[profile.dev]
|
||||
|
|
|
|||
134
src/app.rs
134
src/app.rs
|
|
@ -602,11 +602,12 @@ pub struct MounterData(MounterKey, MounterItem);
|
|||
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum WindowKind {
|
||||
ContextMenu(Entity, widget::Id),
|
||||
Desktop(Entity),
|
||||
DesktopViewOptions,
|
||||
Dialogs(widget::Id),
|
||||
Preview(Option<Entity>, PreviewKind),
|
||||
FileDialog(Option<Vec<PathBuf>>),
|
||||
Preview(Option<Entity>, PreviewKind),
|
||||
}
|
||||
|
||||
pub struct WatcherWrapper {
|
||||
|
|
@ -671,7 +672,7 @@ pub struct App {
|
|||
surface_names: HashMap<WindowId, String>,
|
||||
toasts: widget::toaster::Toasts<Message>,
|
||||
watcher_opt: Option<(Debouncer<RecommendedWatcher, FileIdMap>, HashSet<PathBuf>)>,
|
||||
window_id_opt: Option<window::Id>,
|
||||
pub(crate) window_id_opt: Option<window::Id>,
|
||||
windows: HashMap<window::Id, WindowKind>,
|
||||
nav_dnd_hover: Option<(Location, Instant)>,
|
||||
tab_dnd_hover: Option<(Entity, Instant)>,
|
||||
|
|
@ -1120,9 +1121,20 @@ impl App {
|
|||
}
|
||||
|
||||
fn remove_window(&mut self, id: &window::Id) {
|
||||
if let Some(WindowKind::Desktop(entity)) = self.windows.remove(id) {
|
||||
// Remove the tab from the tab model
|
||||
self.tab_model.remove(entity);
|
||||
if let Some(window_kind) = self.windows.remove(id) {
|
||||
match window_kind {
|
||||
WindowKind::ContextMenu(entity, _) => {
|
||||
// Close context menu
|
||||
if let Some(tab) = self.tab_model.data_mut::<Tab>(entity) {
|
||||
tab.context_menu = None;
|
||||
}
|
||||
}
|
||||
WindowKind::Desktop(entity) => {
|
||||
// Remove the tab from the tab model
|
||||
self.tab_model.remove(entity);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -2410,8 +2422,10 @@ impl Application for App {
|
|||
}
|
||||
if let Some(tab) = self.tab_model.data_mut::<Tab>(entity) {
|
||||
if tab.context_menu.is_some() {
|
||||
tab.context_menu = None;
|
||||
return Task::none();
|
||||
return self.update(Message::TabMessage(
|
||||
Some(entity),
|
||||
tab::Message::ContextMenu(None),
|
||||
));
|
||||
}
|
||||
|
||||
if tab.edit_location.is_some() {
|
||||
|
|
@ -3683,12 +3697,26 @@ impl Application for App {
|
|||
return self.update_config();
|
||||
}
|
||||
Message::TabActivate(entity) => {
|
||||
self.tab_model.activate(entity);
|
||||
let mut tasks = Vec::new();
|
||||
|
||||
// Close old context menu
|
||||
let active = self.tab_model.active();
|
||||
if let Some(tab) = self.tab_model.data_mut::<Tab>(active) {
|
||||
if tab.context_menu.is_some() {
|
||||
tasks.push(self.update(Message::TabMessage(
|
||||
Some(active),
|
||||
tab::Message::ContextMenu(None),
|
||||
)));
|
||||
}
|
||||
}
|
||||
|
||||
// Activate new tab
|
||||
self.tab_model.activate(entity);
|
||||
if let Some(tab) = self.tab_model.data::<Tab>(entity) {
|
||||
self.activate_nav_model_location(&tab.location.clone());
|
||||
}
|
||||
return self.update_title();
|
||||
tasks.push(self.update_title());
|
||||
return Task::batch(tasks);
|
||||
}
|
||||
Message::TabNext => {
|
||||
let len = self.tab_model.iter().count();
|
||||
|
|
@ -3824,6 +3852,75 @@ impl Application for App {
|
|||
self.update_tab(entity, tab_path, selection_paths),
|
||||
]));
|
||||
}
|
||||
tab::Command::ContextMenu(point_opt) => {
|
||||
#[cfg(feature = "wayland")]
|
||||
match point_opt {
|
||||
Some(point) => {
|
||||
if crate::is_wayland() {
|
||||
// Open context menu
|
||||
use cctk::wayland_protocols::xdg::shell::client::xdg_positioner::{
|
||||
Anchor, Gravity,
|
||||
};
|
||||
use cosmic::iced_runtime::platform_specific::wayland::popup::{
|
||||
SctkPopupSettings, SctkPositioner,
|
||||
};
|
||||
let window_id = WindowId::unique();
|
||||
self.windows.insert(
|
||||
window_id.clone(),
|
||||
WindowKind::ContextMenu(entity, widget::Id::unique()),
|
||||
);
|
||||
commands.push(self.update(Message::Surface(
|
||||
cosmic::surface::action::app_popup(
|
||||
move |app: &mut crate::App| -> SctkPopupSettings {
|
||||
let anchor_rect = Rectangle {
|
||||
x: point.x as i32,
|
||||
y: point.y as i32,
|
||||
width: 1,
|
||||
height: 1,
|
||||
};
|
||||
let positioner = SctkPositioner {
|
||||
size: None,
|
||||
anchor_rect,
|
||||
anchor: Anchor::None,
|
||||
gravity: Gravity::BottomRight,
|
||||
reactive: true,
|
||||
..Default::default()
|
||||
};
|
||||
SctkPopupSettings {
|
||||
parent: app
|
||||
.window_id_opt
|
||||
.unwrap_or_else(|| WindowId::NONE),
|
||||
id: window_id,
|
||||
positioner,
|
||||
parent_size: None,
|
||||
grab: true,
|
||||
close_with_children: false,
|
||||
input_zone: None,
|
||||
}
|
||||
},
|
||||
None,
|
||||
),
|
||||
)));
|
||||
}
|
||||
}
|
||||
None => {
|
||||
// Destroy previous popup
|
||||
let mut window_ids = Vec::new();
|
||||
for (window_id, window_kind) in self.windows.iter() {
|
||||
if let WindowKind::ContextMenu(e, _) = window_kind {
|
||||
if *e == entity {
|
||||
window_ids.push(*window_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
for window_id in window_ids {
|
||||
commands.push(self.update(Message::Surface(
|
||||
cosmic::surface::action::destroy_popup(window_id),
|
||||
)));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
tab::Command::Delete(paths) => commands.push(self.delete(paths)),
|
||||
tab::Command::DropFiles(to, from) => {
|
||||
commands.push(self.update(Message::PasteContents(to, from)));
|
||||
|
|
@ -4055,10 +4152,12 @@ impl Application for App {
|
|||
}
|
||||
}
|
||||
Message::WindowUnfocus => {
|
||||
/*TODO
|
||||
let tab_entity = self.tab_model.active();
|
||||
if let Some(tab) = self.tab_model.data_mut::<Tab>(tab_entity) {
|
||||
tab.context_menu = None;
|
||||
}
|
||||
*/
|
||||
}
|
||||
Message::WindowCloseRequested(id) => {
|
||||
self.remove_window(&id);
|
||||
|
|
@ -4548,9 +4647,9 @@ impl Application for App {
|
|||
};
|
||||
}
|
||||
}
|
||||
Message::Surface(a) => {
|
||||
Message::Surface(action) => {
|
||||
return cosmic::task::message(cosmic::Action::Cosmic(
|
||||
cosmic::app::Action::Surface(a),
|
||||
cosmic::app::Action::Surface(action),
|
||||
));
|
||||
}
|
||||
Message::SaveSortNames => {
|
||||
|
|
@ -5583,6 +5682,19 @@ impl Application for App {
|
|||
|
||||
fn view_window(&self, id: WindowId) -> Element<Self::Message> {
|
||||
let content = match self.windows.get(&id) {
|
||||
Some(WindowKind::ContextMenu(entity, id)) => {
|
||||
match self.tab_model.data::<Tab>(*entity) {
|
||||
Some(tab) => {
|
||||
return widget::autosize::autosize(
|
||||
menu::context_menu(tab, &self.key_binds, &self.modifiers)
|
||||
.map(|x| Message::TabMessage(Some(*entity), x)),
|
||||
id.clone(),
|
||||
)
|
||||
.into()
|
||||
}
|
||||
None => widget::text("Unknown tab ID").into(),
|
||||
}
|
||||
}
|
||||
Some(WindowKind::Desktop(entity)) => {
|
||||
let mut tab_column = widget::column::with_capacity(3);
|
||||
|
||||
|
|
|
|||
|
|
@ -457,6 +457,7 @@ impl From<AppMessage> for Message {
|
|||
AppMessage::ZoomIn(_entity_opt) => Message::ZoomIn,
|
||||
AppMessage::ZoomOut(_entity_opt) => Message::ZoomOut,
|
||||
AppMessage::NewItem(_entity_opt, true) => Message::NewFolder,
|
||||
AppMessage::Surface(action) => Message::Surface(action),
|
||||
unsupported => {
|
||||
log::warn!("{unsupported:?} not supported in dialog mode");
|
||||
Message::None
|
||||
|
|
@ -1236,8 +1237,7 @@ impl Application for App {
|
|||
}
|
||||
|
||||
if self.tab.context_menu.is_some() {
|
||||
self.tab.context_menu = None;
|
||||
return Task::none();
|
||||
return self.update(Message::TabMessage(tab::Message::ContextMenu(None)));
|
||||
}
|
||||
|
||||
if self.tab.edit_location.is_some() {
|
||||
|
|
@ -1787,9 +1787,9 @@ impl Application for App {
|
|||
tab::View::Grid => zoom_out(&mut config.icon_sizes.grid, 50, 500),
|
||||
});
|
||||
}
|
||||
Message::Surface(a) => {
|
||||
Message::Surface(action) => {
|
||||
return cosmic::task::message(cosmic::Action::Cosmic(
|
||||
cosmic::app::Action::Surface(a),
|
||||
cosmic::app::Action::Surface(action),
|
||||
));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -52,6 +52,13 @@ pub fn home_dir() -> PathBuf {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn is_wayland() -> bool {
|
||||
matches!(
|
||||
cosmic::app::cosmic::windowing_system(),
|
||||
Some(cosmic::app::cosmic::WindowingSystem::Wayland)
|
||||
)
|
||||
}
|
||||
|
||||
/// Runs application in desktop mode
|
||||
#[rustfmt::skip]
|
||||
pub fn desktop() -> Result<(), Box<dyn std::error::Error>> {
|
||||
|
|
|
|||
|
|
@ -32,7 +32,8 @@ pub struct MouseArea<'a, Message> {
|
|||
on_release: Option<Box<dyn OnMouseButton<'a, Message>>>,
|
||||
on_resize: Option<Box<dyn OnResize<'a, Message>>>,
|
||||
on_right_press: Option<Box<dyn OnMouseButton<'a, Message>>>,
|
||||
on_right_press_no_capture: Option<Box<dyn OnMouseButton<'a, Message>>>,
|
||||
on_right_press_no_capture: bool,
|
||||
on_right_press_window_position: bool,
|
||||
on_right_release: Option<Box<dyn OnMouseButton<'a, Message>>>,
|
||||
on_middle_press: Option<Box<dyn OnMouseButton<'a, Message>>>,
|
||||
on_middle_release: Option<Box<dyn OnMouseButton<'a, Message>>>,
|
||||
|
|
@ -103,10 +104,17 @@ impl<'a, Message> MouseArea<'a, Message> {
|
|||
self
|
||||
}
|
||||
|
||||
/// The message to emit on a right button press without capturing.
|
||||
/// on_right_press will not capture input
|
||||
#[must_use]
|
||||
pub fn on_right_press_no_capture(mut self, message: impl OnMouseButton<'a, Message>) -> Self {
|
||||
self.on_right_press_no_capture = Some(Box::new(message));
|
||||
pub fn on_right_press_no_capture(mut self) -> Self {
|
||||
self.on_right_press_no_capture = true;
|
||||
self
|
||||
}
|
||||
|
||||
/// on_right_press will provide window position instead of widget relative
|
||||
#[must_use]
|
||||
pub fn on_right_press_window_position(mut self) -> Self {
|
||||
self.on_right_press_window_position = true;
|
||||
self
|
||||
}
|
||||
|
||||
|
|
@ -203,8 +211,8 @@ impl<'a, Message, F> OnMouseButton<'a, Message> for F where F: Fn(Option<Point>)
|
|||
pub trait OnDrag<'a, Message>: Fn(Option<Rectangle>) -> Message + 'a {}
|
||||
impl<'a, Message, F> OnDrag<'a, Message> for F where F: Fn(Option<Rectangle>) -> Message + 'a {}
|
||||
|
||||
pub trait OnResize<'a, Message>: Fn(Size, Rectangle) -> Message + 'a {}
|
||||
impl<'a, Message, F> OnResize<'a, Message> for F where F: Fn(Size, Rectangle) -> Message + 'a {}
|
||||
pub trait OnResize<'a, Message>: Fn(Rectangle) -> Message + 'a {}
|
||||
impl<'a, Message, F> OnResize<'a, Message> for F where F: Fn(Rectangle) -> Message + 'a {}
|
||||
|
||||
pub trait OnScroll<'a, Message>: Fn(mouse::ScrollDelta) -> Option<Message> + 'a {}
|
||||
impl<'a, Message, F> OnScroll<'a, Message> for F where
|
||||
|
|
@ -223,7 +231,7 @@ struct State {
|
|||
last_virtual_position: Option<Point>,
|
||||
drag_initiated: Option<Point>,
|
||||
prev_click: Option<(mouse::Click, Instant)>,
|
||||
size: Option<Size>,
|
||||
viewport: Option<Rectangle>,
|
||||
}
|
||||
|
||||
impl State {
|
||||
|
|
@ -286,7 +294,8 @@ impl<'a, Message> MouseArea<'a, Message> {
|
|||
on_release: None,
|
||||
on_resize: None,
|
||||
on_right_press: None,
|
||||
on_right_press_no_capture: None,
|
||||
on_right_press_no_capture: false,
|
||||
on_right_press_window_position: false,
|
||||
on_right_release: None,
|
||||
on_middle_press: None,
|
||||
on_middle_release: None,
|
||||
|
|
@ -507,10 +516,9 @@ fn update<Message: Clone>(
|
|||
let layout_bounds = layout.bounds();
|
||||
|
||||
if let Some(message) = widget.on_resize.as_ref() {
|
||||
let size = layout_bounds.size();
|
||||
if state.size != Some(size) {
|
||||
state.size = Some(size);
|
||||
shell.publish(message(size, *viewport));
|
||||
if state.viewport != Some(*viewport) {
|
||||
state.viewport = Some(*viewport);
|
||||
shell.publish(message(*viewport));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -635,17 +643,18 @@ fn update<Message: Clone>(
|
|||
|
||||
if let Some(message) = widget.on_right_press.as_ref() {
|
||||
if let Event::Mouse(mouse::Event::ButtonPressed(mouse::Button::Right)) = event {
|
||||
shell.publish(message(cursor.position_in(layout_bounds)));
|
||||
let point_opt = if widget.on_right_press_window_position {
|
||||
cursor.position_over(layout_bounds)
|
||||
} else {
|
||||
cursor.position_in(layout_bounds)
|
||||
};
|
||||
shell.publish(message(point_opt));
|
||||
|
||||
return event::Status::Captured;
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(message) = widget.on_right_press_no_capture.as_ref() {
|
||||
if let Event::Mouse(mouse::Event::ButtonPressed(mouse::Button::Right)) = event {
|
||||
shell.publish(message(cursor.position_in(layout_bounds)));
|
||||
|
||||
return event::Status::Ignored;
|
||||
if widget.on_right_press_no_capture {
|
||||
return event::Status::Ignored;
|
||||
} else {
|
||||
return event::Status::Captured;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
67
src/tab.rs
67
src/tab.rs
|
|
@ -1508,6 +1508,7 @@ pub enum Command {
|
|||
AddToSidebar(PathBuf),
|
||||
AutoScroll(Option<f32>),
|
||||
ChangeLocation(String, Location, Option<Vec<PathBuf>>),
|
||||
ContextMenu(Option<Point>),
|
||||
Delete(Vec<PathBuf>),
|
||||
DropFiles(PathBuf, ClipboardPaste),
|
||||
EmptyTrash,
|
||||
|
|
@ -1566,9 +1567,9 @@ pub enum Message {
|
|||
Reload,
|
||||
RightClick(Option<usize>),
|
||||
MiddleClick(usize),
|
||||
Resize(Rectangle),
|
||||
Scroll(Viewport),
|
||||
ScrollTab(f32),
|
||||
ScrollToFocus,
|
||||
SearchContext(Location, SearchContextWrapper),
|
||||
SearchReady(bool),
|
||||
SelectAll,
|
||||
|
|
@ -2384,6 +2385,7 @@ pub struct Tab {
|
|||
pub location_context_menu_index: Option<usize>,
|
||||
pub context_menu: Option<Point>,
|
||||
pub mode: Mode,
|
||||
pub offset_opt: Option<Vector>,
|
||||
pub scroll_opt: Option<AbsoluteOffset>,
|
||||
pub size_opt: Cell<Option<Size>>,
|
||||
pub item_view_size_opt: Cell<Option<Size>>,
|
||||
|
|
@ -2495,6 +2497,7 @@ impl Tab {
|
|||
location_context_menu_point: None,
|
||||
location_context_menu_index: None,
|
||||
mode: Mode::App,
|
||||
offset_opt: None,
|
||||
scroll_opt: None,
|
||||
size_opt: Cell::new(None),
|
||||
item_view_size_opt: Cell::new(None),
|
||||
|
|
@ -2861,6 +2864,7 @@ impl Tab {
|
|||
let mut history_i_opt = None;
|
||||
let mod_ctrl = modifiers.contains(Modifiers::CTRL) && self.mode.multiple();
|
||||
let mod_shift = modifiers.contains(Modifiers::SHIFT) && self.mode.multiple();
|
||||
let last_context_menu = self.context_menu;
|
||||
match message {
|
||||
Message::AddNetworkDrive => {
|
||||
commands.push(Command::AddNetworkDrive);
|
||||
|
|
@ -3087,6 +3091,7 @@ impl Tab {
|
|||
self.edit_location = None;
|
||||
if point_opt.is_none() || !mod_shift {
|
||||
self.context_menu = point_opt;
|
||||
|
||||
//TODO: hack for clearing selecting when right clicking empty space
|
||||
if self.context_menu.is_some() && self.last_right_click.take().is_none() {
|
||||
if let Some(ref mut items) = self.items_opt {
|
||||
|
|
@ -3578,7 +3583,16 @@ impl Tab {
|
|||
item.highlighted = true;
|
||||
}
|
||||
}
|
||||
Message::Resize(viewport) => {
|
||||
self.offset_opt = Some(Vector::new(viewport.x, viewport.y));
|
||||
|
||||
// Scroll to ensure focused item still in view
|
||||
if let Some(offset) = self.select_focus_scroll() {
|
||||
commands.push(Command::Iced(
|
||||
scrollable::scroll_to(self.scrollable_id.clone(), offset).into(),
|
||||
));
|
||||
}
|
||||
}
|
||||
Message::Scroll(viewport) => {
|
||||
self.scroll_opt = Some(viewport.absolute_offset());
|
||||
self.watch_drag = true;
|
||||
|
|
@ -3595,13 +3609,6 @@ impl Tab {
|
|||
.into(),
|
||||
));
|
||||
}
|
||||
Message::ScrollToFocus => {
|
||||
if let Some(offset) = self.select_focus_scroll() {
|
||||
commands.push(Command::Iced(
|
||||
scrollable::scroll_to(self.scrollable_id.clone(), offset).into(),
|
||||
));
|
||||
}
|
||||
}
|
||||
Message::SearchContext(location, context) => {
|
||||
if location == self.location {
|
||||
self.search_context = context.0;
|
||||
|
|
@ -3872,6 +3879,18 @@ impl Tab {
|
|||
));
|
||||
}
|
||||
|
||||
//TODO: check for wayland
|
||||
if self.context_menu != last_context_menu {
|
||||
if last_context_menu.is_some() {
|
||||
commands.push(Command::ContextMenu(None));
|
||||
}
|
||||
if let Some(point) = self.context_menu {
|
||||
commands.push(Command::ContextMenu(Some(
|
||||
point + self.offset_opt.unwrap_or_default(),
|
||||
)));
|
||||
}
|
||||
}
|
||||
|
||||
// Change directory if requested
|
||||
if let Some(mut location) = cd {
|
||||
if matches!(self.mode, Mode::Desktop) {
|
||||
|
|
@ -4480,9 +4499,9 @@ impl Tab {
|
|||
Message::LocationContextMenuIndex(None)
|
||||
})
|
||||
} else {
|
||||
mouse_area = mouse_area.on_right_press_no_capture(move |_point_opt| {
|
||||
Message::LocationContextMenuIndex(Some(index))
|
||||
})
|
||||
mouse_area = mouse_area.on_right_press_no_capture().on_right_press(
|
||||
move |_point_opt| Message::LocationContextMenuIndex(Some(index)),
|
||||
)
|
||||
}
|
||||
|
||||
let mouse_area = if let Location::Path(_) = &self.location {
|
||||
|
|
@ -4739,9 +4758,9 @@ impl Tab {
|
|||
column = column.push(button)
|
||||
} else {
|
||||
column = column.push(
|
||||
mouse_area::MouseArea::new(button).on_right_press_no_capture(
|
||||
move |_point_opt| Message::RightClick(Some(i)),
|
||||
),
|
||||
mouse_area::MouseArea::new(button)
|
||||
.on_right_press_no_capture()
|
||||
.on_right_press(move |_point_opt| Message::RightClick(Some(i))),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -5158,9 +5177,9 @@ impl Tab {
|
|||
if self.context_menu.is_some() {
|
||||
mouse_area
|
||||
} else {
|
||||
mouse_area.on_right_press_no_capture(move |_point_opt| {
|
||||
Message::RightClick(Some(i))
|
||||
})
|
||||
mouse_area
|
||||
.on_right_press_no_capture()
|
||||
.on_right_press(move |_point_opt| Message::RightClick(Some(i)))
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -5375,8 +5394,7 @@ impl Tab {
|
|||
let mut mouse_area = mouse_area::MouseArea::new(item_view)
|
||||
.on_press(move |_point_opt| Message::Click(None))
|
||||
.on_release(|_| Message::ClickRelease(None))
|
||||
//TODO: better way to keep focused item in view
|
||||
.on_resize(|_, _| Message::ScrollToFocus)
|
||||
.on_resize(Message::Resize)
|
||||
.on_back_press(move |_point_opt| Message::GoPrevious)
|
||||
.on_forward_press(move |_point_opt| Message::GoNext)
|
||||
.on_scroll(|delta| respond_to_scroll_direction(delta, self.modifiers));
|
||||
|
|
@ -5388,12 +5406,13 @@ impl Tab {
|
|||
}
|
||||
|
||||
let mut popover = widget::popover(mouse_area);
|
||||
|
||||
if let Some(point) = self.context_menu {
|
||||
let context_menu = menu::context_menu(self, key_binds, &self.modifiers);
|
||||
popover = popover
|
||||
.popup(context_menu)
|
||||
.position(widget::popover::Position::Point(point));
|
||||
if !cfg!(feature = "wayland") || !crate::is_wayland() {
|
||||
let context_menu = menu::context_menu(self, key_binds, &self.modifiers);
|
||||
popover = popover
|
||||
.popup(context_menu)
|
||||
.position(widget::popover::Position::Point(point));
|
||||
}
|
||||
}
|
||||
|
||||
let mut tab_column = widget::column::with_capacity(3);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue