From 8c9c15de85326caabce1f19001eda9566cac5ba1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?nicole=20miko=C5=82ajczyk?= Date: Thu, 2 Jul 2026 18:12:02 +0200 Subject: [PATCH] feat: disable Cut and Copy buttons when no text is selected MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: nicole mikołajczyk --- src/main.rs | 16 +++++++++++++++- src/menu.rs | 34 ++++++++++++++++++++++++++++------ 2 files changed, 43 insertions(+), 7 deletions(-) diff --git a/src/main.rs b/src/main.rs index 766175e..d78bfb8 100644 --- a/src/main.rs +++ b/src/main.rs @@ -194,6 +194,7 @@ fn main() -> Result<(), Box> { #[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, Ord, PartialEq, PartialOrd, Serialize)] pub enum Action { Todo, + NoOp, About, CloseFile, CloseProject(usize), @@ -244,6 +245,7 @@ impl Action { fn message(&self, entity_opt: Option) -> Message { match self { Self::Todo => Message::Todo, + Self::NoOp => Message::NoOp, Self::About => Message::ToggleContextPage(ContextPage::About), Self::CloseFile => Message::CloseFile, Self::CloseProject(project_i) => Message::CloseProject(*project_i), @@ -371,6 +373,7 @@ pub enum Message { Modifiers(Modifiers), NewFile, NewWindow, + NoOp, NotifyEvent(notify::Event), NotifyWatcher(WatcherWrapper), OpenFile(PathBuf), @@ -2161,6 +2164,9 @@ impl Application for App { } } } + Message::NoOp => { + // Do nothing + } Message::NotifyEvent(event) => { // Reload tabs that changed let mut tab_reload = Vec::new(); @@ -3027,12 +3033,19 @@ impl Application for App { } fn header_start(&self) -> Vec> { + let has_selection = match self.active_tab() { + Some(Tab::Editor(tab)) => tab.editor.lock().unwrap().selection() != Selection::None, + Some(Tab::GitDiff(_)) => false, + None => false, + }; + vec![menu_bar( &self.core, &self.config, &self.config_state, &self.key_binds, &self.projects, + has_selection, )] } @@ -3088,9 +3101,10 @@ impl Application for App { text_box = text_box.line_numbers(); } let mut popover = widget::popover(text_box); + let has_selection = tab.editor.lock().unwrap().selection() != Selection::None; if let Some(point) = tab.context_menu { popover = popover - .popup(menu::context_menu(&self.key_binds, tab_id)) + .popup(menu::context_menu(&self.key_binds, tab_id, has_selection)) .position(widget::popover::Position::Point(point)); } tab_column = tab_column.push(popover); diff --git a/src/menu.rs b/src/menu.rs index 51d52cd..7474645 100644 --- a/src/menu.rs +++ b/src/menu.rs @@ -119,6 +119,7 @@ fn format_recent_menu_path(path: &PathBuf, home_dir_opt: Option<&PathBuf>) -> St pub fn context_menu<'a>( key_binds: &HashMap, entity: segmented_button::Entity, + has_selection: bool, ) -> Element<'a, Message> { fn key_style(theme: &cosmic::Theme) -> TextStyle { // TODO use wayland popups @@ -130,7 +131,7 @@ pub fn context_menu<'a>( } } - let menu_item = |menu_label, menu_action| { + let base_menu_item = |menu_label, menu_action| { let mut key = String::new(); for (key_bind, key_action) in key_binds.iter() { if key_action == &menu_action { @@ -145,7 +146,19 @@ pub fn context_menu<'a>( .class(theme::Text::Custom(key_style)) .into(), ]) - .on_press(Message::TabContextAction(entity, menu_action)) + }; + + let optional_menu_item = |menu_label, menu_action, disabled| { + base_menu_item(menu_label, menu_action).on_press_maybe(if disabled { + None + } else { + Some(Message::TabContextAction(entity, menu_action)) + }) + }; + + let menu_item = |menu_label, menu_action| { + base_menu_item(menu_label, menu_action) + .on_press(Message::TabContextAction(entity, menu_action)) }; widget::container( @@ -153,8 +166,8 @@ pub fn context_menu<'a>( menu_item(fl!("undo"), Action::Undo).into(), menu_item(fl!("redo"), Action::Redo).into(), divider::horizontal::light().into(), - menu_item(fl!("cut"), Action::Cut).into(), - menu_item(fl!("copy"), Action::Copy).into(), + optional_menu_item(fl!("cut"), Action::Cut, !has_selection).into(), + optional_menu_item(fl!("copy"), Action::Copy, !has_selection).into(), menu_item(fl!("paste"), Action::Paste).into(), menu_item(fl!("select-all"), Action::SelectAll).into(), ]), @@ -186,6 +199,7 @@ pub fn menu_bar<'a>( config_state: &ConfigState, key_binds: &HashMap, projects: &Vec<(String, PathBuf)>, + has_selection: bool, ) -> Element<'a, Message> { //TODO: port to libcosmic let menu_tab_width = |tab_width: u16| { @@ -278,8 +292,16 @@ pub fn menu_bar<'a>( MenuItem::Button(fl!("undo"), None, Action::Undo), MenuItem::Button(fl!("redo"), None, Action::Redo), MenuItem::Divider, - MenuItem::Button(fl!("cut"), None, Action::Cut), - MenuItem::Button(fl!("copy"), None, Action::Copy), + if has_selection { + MenuItem::Button(fl!("cut"), None, Action::Cut) + } else { + MenuItem::ButtonDisabled(fl!("cut"), None, Action::NoOp) + }, + if has_selection { + MenuItem::Button(fl!("copy"), None, Action::Copy) + } else { + MenuItem::ButtonDisabled(fl!("copy"), None, Action::NoOp) + }, MenuItem::Button(fl!("paste"), None, Action::Paste), MenuItem::Button(fl!("select-all"), None, Action::SelectAll), MenuItem::Divider,