diff --git a/src/app.rs b/src/app.rs index 1c76f35..f2c4dd3 100644 --- a/src/app.rs +++ b/src/app.rs @@ -28,7 +28,7 @@ use cosmic::{ event, futures::{self, SinkExt}, keyboard::{Event as KeyEvent, Key, Modifiers}, - stream, + mouse, stream, widget::scrollable, window::{self, Event as WindowEvent, Id as WindowId}, }, @@ -365,6 +365,7 @@ pub enum Message { ModifiersChanged(window::Id, Modifiers), MounterItems(MounterKey, MounterItems), MountResult(MounterKey, MounterItem, Result), + Mouse(window::Id, mouse::Button), MoveTo(Option), MoveToResult(DialogResult), NavBarClose(Entity), @@ -1545,6 +1546,21 @@ impl App { } } + fn close_context_menus(&mut self) -> Task { + let active = self.tab_model.active(); + if let Some(tab) = self.tab_model.data_mut::(active) { + tab.location_context_menu_index = None; + if tab.context_menu.is_some() { + return self.update(Message::TabMessage( + Some(active), + tab::Message::ContextMenu(None, None), + )); + } + } + + Task::none() + } + fn update_nav_model(&mut self) { let mut nav_model = segmented_button::ModelBuilder::default(); @@ -2570,11 +2586,12 @@ impl Application for App { self.set_show_context(false); return cosmic::task::message(cosmic::action::app(Message::SetShowDetails(false))); } - if self.search_get().is_some() { - // Close search if open - return self.search_set_active(None); - } if let Some(tab) = self.tab_model.data_mut::(entity) { + if tab.location_context_menu_index.is_some() { + tab.location_context_menu_index = None; + return Task::none(); + } + if tab.context_menu.is_some() { return self.update(Message::TabMessage( Some(entity), @@ -2597,6 +2614,11 @@ impl Application for App { } } + if self.search_get().is_some() { + // Close search if open + return self.search_set_active(None); + } + Task::none() } @@ -3271,6 +3293,12 @@ impl Application for App { ); } }, + Message::Mouse(window_id, _button) => { + // Close context menu when clicking outside. + if self.core.main_window_id() == Some(window_id) { + return self.close_context_menus(); + } + } Message::MoveTo(entity_opt) => { let selected_paths: Box<[_]> = self.selected_paths(entity_opt).collect(); return self.move_to(&selected_paths); @@ -4013,14 +4041,18 @@ impl Application for App { )); } Message::SearchActivate => { - return if self.search_get().is_none() { - self.search_set_active(Some(String::new())) + let mut tasks = vec![self.close_context_menus()]; + + if self.search_get().is_none() { + tasks.push(self.search_set_active(Some(String::new()))); } else { - widget::text_input::focus(self.search_id.clone()) + tasks.push(widget::text_input::focus(self.search_id.clone())); }; + + return Task::batch(tasks); } Message::SearchClear => { - return self.search_set_active(None); + return Task::batch([self.close_context_menus(), self.search_set_active(None)]); } Message::SearchInput(input) => { return self.search_set_active(Some(input)); @@ -4037,18 +4069,7 @@ impl Application for App { return self.update_config(); } Message::TabActivate(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::(active) - && tab.context_menu.is_some() - { - tasks.push(self.update(Message::TabMessage( - Some(active), - tab::Message::ContextMenu(None, None), - ))); - } + let mut tasks = vec![self.close_context_menus()]; // Activate new tab self.tab_model.activate(entity); @@ -6141,6 +6162,10 @@ impl Application for App { let mut subscriptions = vec![ //TODO: filter more events by window id event::listen_with(|event, status, window_id| match event { + Event::Mouse(mouse::Event::ButtonPressed(button)) => match status { + event::Status::Ignored => Some(Message::Mouse(window_id, button)), + event::Status::Captured => None, + }, Event::Keyboard(KeyEvent::KeyPressed { key, modifiers, diff --git a/src/dialog.rs b/src/dialog.rs index a5b9c4a..c103a06 100644 --- a/src/dialog.rs +++ b/src/dialog.rs @@ -11,7 +11,7 @@ use cosmic::{ event, futures::{self, SinkExt}, keyboard::{Event as KeyEvent, Key, Modifiers, key::Named}, - stream, + mouse, stream, widget::scrollable, window, }, @@ -468,6 +468,7 @@ enum Message { Key(Modifiers, Key, Option), ModifiersChanged(Modifiers), MounterItems(MounterKey, MounterItems), + Mouse(window::Id, mouse::Button), NewFolder, NotifyEvents(Vec), NotifyWatcher(WatcherWrapper), @@ -854,6 +855,15 @@ impl App { } } + fn close_context_menus(&mut self) -> Task { + self.tab.location_context_menu_index = None; + if self.tab.context_menu.is_some() { + return self.update(Message::TabMessage(tab::Message::ContextMenu(None, None))); + } + + Task::none() + } + fn update_nav_model(&mut self) { let mut nav_model = segmented_button::ModelBuilder::default(); @@ -1300,9 +1310,9 @@ impl Application for App { return Task::none(); } - if self.search_get().is_some() { - // Close search if open - return self.search_set(None); + if self.tab.location_context_menu_index.is_some() { + self.tab.location_context_menu_index = None; + return Task::none(); } if self.tab.context_menu.is_some() { @@ -1315,6 +1325,11 @@ impl Application for App { return Task::none(); } + if self.search_get().is_some() { + // Close search if open + return self.search_set(None); + } + let had_focused_button = self.tab.select_focus_id().is_some(); if self.tab.select_none() { if had_focused_button { @@ -1529,6 +1544,12 @@ impl Application for App { return Task::batch(commands); } + Message::Mouse(window_id, _button) => { + // Close context menu when clicking outside. + if self.core.main_window_id() == Some(window_id) { + return self.close_context_menus(); + } + } Message::NewFolder => { if let Some(path) = self.tab.location.path_opt() { self.dialog_pages.push_back(DialogPage::NewFolder { @@ -1684,14 +1705,18 @@ impl Application for App { ))); } Message::SearchActivate => { - return if self.search_get().is_none() { - self.search_set(Some(String::new())) + let mut tasks = vec![self.close_context_menus()]; + + if self.search_get().is_none() { + tasks.push(self.search_set(Some(String::new()))); } else { - widget::text_input::focus(self.search_id.clone()) - }; + tasks.push(widget::text_input::focus(self.search_id.clone())); + } + + return Task::batch(tasks); } Message::SearchClear => { - return self.search_set(None); + return Task::batch([self.close_context_menus(), self.search_set(None)]); } Message::SearchInput(input) => { return self.search_set(Some(input)); @@ -1972,7 +1997,11 @@ impl Application for App { struct WatcherSubscription; struct TimeSubscription; let mut subscriptions = vec![ - event::listen_with(|event, status, _window_id| match event { + event::listen_with(|event, status, window_id| match event { + Event::Mouse(mouse::Event::ButtonPressed(button)) => match status { + event::Status::Ignored => Some(Message::Mouse(window_id, button)), + event::Status::Captured => None, + }, Event::Keyboard(KeyEvent::KeyPressed { key, modifiers,