feat: disable Cut and Copy buttons when no text is selected (#588)
- [x] I have disclosed use of any AI generated code in my commit messages. - If you are using an LLM, and do not fully understand the changes it is making to the code base, do not create a PR. - In our experience, AI generated code often results in overly complex code that lacks enough context for a proper fix or feature inclusion. This results in considerably longer code reviews. Due to this, AI authored or partially authored PRs may be closed without comment. - [x] I understand these changes in full and will be able to respond to review comments. - [x] My change is accurately described in the commit message. - [x] My contribution is tested and working as described. - [x] I have read the [Developer Certificate of Origin](https://developercertificate.org/) and certify my contribution under its conditions.
This commit is contained in:
commit
b23384043e
2 changed files with 43 additions and 7 deletions
16
src/main.rs
16
src/main.rs
|
|
@ -194,6 +194,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, Ord, PartialEq, PartialOrd, Serialize)]
|
#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, Ord, PartialEq, PartialOrd, Serialize)]
|
||||||
pub enum Action {
|
pub enum Action {
|
||||||
Todo,
|
Todo,
|
||||||
|
NoOp,
|
||||||
About,
|
About,
|
||||||
CloseFile,
|
CloseFile,
|
||||||
CloseProject(usize),
|
CloseProject(usize),
|
||||||
|
|
@ -244,6 +245,7 @@ impl Action {
|
||||||
fn message(&self, entity_opt: Option<Entity>) -> Message {
|
fn message(&self, entity_opt: Option<Entity>) -> Message {
|
||||||
match self {
|
match self {
|
||||||
Self::Todo => Message::Todo,
|
Self::Todo => Message::Todo,
|
||||||
|
Self::NoOp => Message::NoOp,
|
||||||
Self::About => Message::ToggleContextPage(ContextPage::About),
|
Self::About => Message::ToggleContextPage(ContextPage::About),
|
||||||
Self::CloseFile => Message::CloseFile,
|
Self::CloseFile => Message::CloseFile,
|
||||||
Self::CloseProject(project_i) => Message::CloseProject(*project_i),
|
Self::CloseProject(project_i) => Message::CloseProject(*project_i),
|
||||||
|
|
@ -371,6 +373,7 @@ pub enum Message {
|
||||||
Modifiers(Modifiers),
|
Modifiers(Modifiers),
|
||||||
NewFile,
|
NewFile,
|
||||||
NewWindow,
|
NewWindow,
|
||||||
|
NoOp,
|
||||||
NotifyEvent(notify::Event),
|
NotifyEvent(notify::Event),
|
||||||
NotifyWatcher(WatcherWrapper),
|
NotifyWatcher(WatcherWrapper),
|
||||||
OpenFile(PathBuf),
|
OpenFile(PathBuf),
|
||||||
|
|
@ -2161,6 +2164,9 @@ impl Application for App {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Message::NoOp => {
|
||||||
|
// Do nothing
|
||||||
|
}
|
||||||
Message::NotifyEvent(event) => {
|
Message::NotifyEvent(event) => {
|
||||||
// Reload tabs that changed
|
// Reload tabs that changed
|
||||||
let mut tab_reload = Vec::new();
|
let mut tab_reload = Vec::new();
|
||||||
|
|
@ -3027,12 +3033,19 @@ impl Application for App {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn header_start(&self) -> Vec<Element<'_, Message>> {
|
fn header_start(&self) -> Vec<Element<'_, Message>> {
|
||||||
|
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(
|
vec![menu_bar(
|
||||||
&self.core,
|
&self.core,
|
||||||
&self.config,
|
&self.config,
|
||||||
&self.config_state,
|
&self.config_state,
|
||||||
&self.key_binds,
|
&self.key_binds,
|
||||||
&self.projects,
|
&self.projects,
|
||||||
|
has_selection,
|
||||||
)]
|
)]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -3088,9 +3101,10 @@ impl Application for App {
|
||||||
text_box = text_box.line_numbers();
|
text_box = text_box.line_numbers();
|
||||||
}
|
}
|
||||||
let mut popover = widget::popover(text_box);
|
let mut popover = widget::popover(text_box);
|
||||||
|
let has_selection = tab.editor.lock().unwrap().selection() != Selection::None;
|
||||||
if let Some(point) = tab.context_menu {
|
if let Some(point) = tab.context_menu {
|
||||||
popover = popover
|
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));
|
.position(widget::popover::Position::Point(point));
|
||||||
}
|
}
|
||||||
tab_column = tab_column.push(popover);
|
tab_column = tab_column.push(popover);
|
||||||
|
|
|
||||||
34
src/menu.rs
34
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>(
|
pub fn context_menu<'a>(
|
||||||
key_binds: &HashMap<KeyBind, Action>,
|
key_binds: &HashMap<KeyBind, Action>,
|
||||||
entity: segmented_button::Entity,
|
entity: segmented_button::Entity,
|
||||||
|
has_selection: bool,
|
||||||
) -> Element<'a, Message> {
|
) -> Element<'a, Message> {
|
||||||
fn key_style(theme: &cosmic::Theme) -> TextStyle {
|
fn key_style(theme: &cosmic::Theme) -> TextStyle {
|
||||||
// TODO use wayland popups
|
// 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();
|
let mut key = String::new();
|
||||||
for (key_bind, key_action) in key_binds.iter() {
|
for (key_bind, key_action) in key_binds.iter() {
|
||||||
if key_action == &menu_action {
|
if key_action == &menu_action {
|
||||||
|
|
@ -145,7 +146,19 @@ pub fn context_menu<'a>(
|
||||||
.class(theme::Text::Custom(key_style))
|
.class(theme::Text::Custom(key_style))
|
||||||
.into(),
|
.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(
|
widget::container(
|
||||||
|
|
@ -153,8 +166,8 @@ pub fn context_menu<'a>(
|
||||||
menu_item(fl!("undo"), Action::Undo).into(),
|
menu_item(fl!("undo"), Action::Undo).into(),
|
||||||
menu_item(fl!("redo"), Action::Redo).into(),
|
menu_item(fl!("redo"), Action::Redo).into(),
|
||||||
divider::horizontal::light().into(),
|
divider::horizontal::light().into(),
|
||||||
menu_item(fl!("cut"), Action::Cut).into(),
|
optional_menu_item(fl!("cut"), Action::Cut, !has_selection).into(),
|
||||||
menu_item(fl!("copy"), Action::Copy).into(),
|
optional_menu_item(fl!("copy"), Action::Copy, !has_selection).into(),
|
||||||
menu_item(fl!("paste"), Action::Paste).into(),
|
menu_item(fl!("paste"), Action::Paste).into(),
|
||||||
menu_item(fl!("select-all"), Action::SelectAll).into(),
|
menu_item(fl!("select-all"), Action::SelectAll).into(),
|
||||||
]),
|
]),
|
||||||
|
|
@ -186,6 +199,7 @@ pub fn menu_bar<'a>(
|
||||||
config_state: &ConfigState,
|
config_state: &ConfigState,
|
||||||
key_binds: &HashMap<KeyBind, Action>,
|
key_binds: &HashMap<KeyBind, Action>,
|
||||||
projects: &Vec<(String, PathBuf)>,
|
projects: &Vec<(String, PathBuf)>,
|
||||||
|
has_selection: bool,
|
||||||
) -> Element<'a, Message> {
|
) -> Element<'a, Message> {
|
||||||
//TODO: port to libcosmic
|
//TODO: port to libcosmic
|
||||||
let menu_tab_width = |tab_width: u16| {
|
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!("undo"), None, Action::Undo),
|
||||||
MenuItem::Button(fl!("redo"), None, Action::Redo),
|
MenuItem::Button(fl!("redo"), None, Action::Redo),
|
||||||
MenuItem::Divider,
|
MenuItem::Divider,
|
||||||
MenuItem::Button(fl!("cut"), None, Action::Cut),
|
if has_selection {
|
||||||
MenuItem::Button(fl!("copy"), None, Action::Copy),
|
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!("paste"), None, Action::Paste),
|
||||||
MenuItem::Button(fl!("select-all"), None, Action::SelectAll),
|
MenuItem::Button(fl!("select-all"), None, Action::SelectAll),
|
||||||
MenuItem::Divider,
|
MenuItem::Divider,
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue