Add open message, improve context menus

This commit is contained in:
Jeremy Soller 2024-02-28 15:46:23 -07:00
parent 09be33e391
commit dc8433ce59
No known key found for this signature in database
GPG key ID: D02FD439211AF56F
5 changed files with 89 additions and 29 deletions

View file

@ -51,6 +51,7 @@ pub enum Action {
MoveToTrash, MoveToTrash,
NewFile, NewFile,
NewFolder, NewFolder,
Open,
Operations, Operations,
Paste, Paste,
Properties, Properties,
@ -76,12 +77,13 @@ impl Action {
Action::Copy => Message::Copy(entity_opt), Action::Copy => Message::Copy(entity_opt),
Action::Cut => Message::Cut(entity_opt), Action::Cut => Message::Cut(entity_opt),
Action::EditLocation => Message::EditLocation(entity_opt), Action::EditLocation => Message::EditLocation(entity_opt),
Action::HistoryNext => Message::TabMessage(None, tab::Message::GoNext), Action::HistoryNext => Message::TabMessage(entity_opt, tab::Message::GoNext),
Action::HistoryPrevious => Message::TabMessage(None, tab::Message::GoPrevious), Action::HistoryPrevious => Message::TabMessage(entity_opt, tab::Message::GoPrevious),
Action::LocationUp => Message::TabMessage(None, tab::Message::LocationUp), Action::LocationUp => Message::TabMessage(entity_opt, tab::Message::LocationUp),
Action::MoveToTrash => Message::MoveToTrash(entity_opt), Action::MoveToTrash => Message::MoveToTrash(entity_opt),
Action::NewFile => Message::NewItem(entity_opt, false), Action::NewFile => Message::NewItem(entity_opt, false),
Action::NewFolder => Message::NewItem(entity_opt, true), Action::NewFolder => Message::NewItem(entity_opt, true),
Action::Open => Message::TabMessage(entity_opt, tab::Message::Open),
Action::Operations => Message::ToggleContextPage(ContextPage::Operations), Action::Operations => Message::ToggleContextPage(ContextPage::Operations),
Action::Paste => Message::Paste(entity_opt), Action::Paste => Message::Paste(entity_opt),
Action::Properties => Message::ToggleContextPage(ContextPage::Properties), Action::Properties => Message::ToggleContextPage(ContextPage::Properties),
@ -1316,7 +1318,7 @@ impl Application for App {
match self.tab_model.data::<Tab>(entity) { match self.tab_model.data::<Tab>(entity) {
Some(tab) => { Some(tab) => {
let tab_view = tab let tab_view = tab
.view(self.core()) .view(self.core(), &self.key_binds)
.map(move |message| Message::TabMessage(Some(entity), message)); .map(move |message| Message::TabMessage(Some(entity), message));
tab_column = tab_column.push(tab_view); tab_column = tab_column.push(tab_view);
} }

View file

@ -16,7 +16,13 @@ use cosmic::{
Application, ApplicationExt, Element, Application, ApplicationExt, Element,
}; };
use notify::Watcher; use notify::Watcher;
use std::{any::TypeId, collections::HashSet, env, fs, path::PathBuf, time}; use std::{
any::TypeId,
collections::{HashMap, HashSet},
env, fs,
path::PathBuf,
time,
};
use crate::{ use crate::{
config::TabConfig, config::TabConfig,
@ -610,8 +616,9 @@ impl Application for App {
let mut tab_column = widget::column::with_capacity(2); let mut tab_column = widget::column::with_capacity(2);
tab_column = tab_column.push( tab_column = tab_column.push(
//TODO: key binds for dialog
self.tab self.tab
.view(self.core()) .view(self.core(), &HashMap::new())
.map(move |message| Message::TabMessage(message)), .map(move |message| Message::TabMessage(message)),
); );

View file

@ -68,6 +68,7 @@ pub fn key_binds() -> HashMap<KeyBind, Action> {
bind!([Alt], Key::Named(Named::ArrowUp), LocationUp); bind!([Alt], Key::Named(Named::ArrowUp), LocationUp);
bind!([], Key::Named(Named::Delete), MoveToTrash); bind!([], Key::Named(Named::Delete), MoveToTrash);
bind!([Ctrl, Shift], Key::Character("N".into()), NewFolder); bind!([Ctrl, Shift], Key::Character("N".into()), NewFolder);
bind!([], Key::Named(Named::Enter), Open);
bind!([Ctrl], Key::Character("v".into()), Paste); bind!([Ctrl], Key::Character("v".into()), Paste);
bind!([], Key::Named(Named::F2), Rename); bind!([], Key::Named(Named::F2), Rename);
bind!([Ctrl], Key::Character("a".into()), SelectAll); bind!([Ctrl], Key::Character("a".into()), SelectAll);

View file

@ -34,10 +34,27 @@ macro_rules! menu_button {
); );
} }
pub fn context_menu<'a>(tab: &Tab) -> Element<'a, tab::Message> { pub fn context_menu<'a>(
//TODO: show key bindings in context menu? tab: &Tab,
let menu_action = |label, action| { key_binds: &HashMap<KeyBind, Action>,
menu_button!(widget::text(label)).on_press(tab::Message::ContextAction(action)) ) -> Element<'a, tab::Message> {
let find_key = |action: &Action| -> String {
for (key_bind, key_action) in key_binds.iter() {
if action == key_action {
return key_bind.to_string();
}
}
String::new()
};
let menu_item = |label, action| {
let key = find_key(&action);
menu_button!(
widget::text(label),
widget::horizontal_space(Length::Fill),
widget::text(key)
)
.on_press(tab::Message::ContextAction(action))
}; };
let selected = tab let selected = tab
@ -48,32 +65,41 @@ pub fn context_menu<'a>(tab: &Tab) -> Element<'a, tab::Message> {
let mut children: Vec<Element<_>> = Vec::new(); let mut children: Vec<Element<_>> = Vec::new();
match tab.location { match tab.location {
Location::Path(_) => { Location::Path(_) => {
children.push(menu_action(fl!("new-file"), Action::NewFile).into());
children.push(menu_action(fl!("new-folder"), Action::NewFolder).into());
children.push(horizontal_rule(1).into());
if selected > 0 {
children.push(menu_action(fl!("rename"), Action::Rename).into());
children.push(menu_action(fl!("cut"), Action::Cut).into());
children.push(menu_action(fl!("copy"), Action::Copy).into());
children.push(menu_action(fl!("paste"), Action::Paste).into());
}
children.push(menu_action(fl!("select-all"), Action::SelectAll).into());
if selected > 0 { if selected > 0 {
children.push(menu_item(fl!("open"), Action::Open).into());
//TODO: Open with
children.push(horizontal_rule(1).into()); children.push(horizontal_rule(1).into());
children.push(menu_action(fl!("move-to-trash"), Action::MoveToTrash).into()); children.push(menu_item(fl!("rename"), Action::Rename).into());
children.push(menu_item(fl!("cut"), Action::Cut).into());
children.push(menu_item(fl!("copy"), Action::Copy).into());
//TODO: Print?
children.push(horizontal_rule(1).into());
//TODO: change to Show details
children.push(menu_item(fl!("properties"), Action::Properties).into());
//TODO: Add to sidebar
children.push(horizontal_rule(1).into());
children.push(menu_item(fl!("move-to-trash"), Action::MoveToTrash).into());
} else {
//TODO: need better designs for menu with no selection
//TODO: have things like properties but they apply to the folder?
children.push(menu_item(fl!("new-file"), Action::NewFile).into());
children.push(menu_item(fl!("new-folder"), Action::NewFolder).into());
children.push(horizontal_rule(1).into());
children.push(menu_item(fl!("select-all"), Action::SelectAll).into());
children.push(menu_item(fl!("paste"), Action::Paste).into());
} }
} }
Location::Trash => { Location::Trash => {
children.push(menu_action(fl!("select-all"), Action::SelectAll).into()); children.push(menu_item(fl!("select-all"), Action::SelectAll).into());
if selected > 0 { if selected > 0 {
children.push(horizontal_rule(1).into());
children.push(menu_item(fl!("properties"), Action::Properties).into());
children.push(horizontal_rule(1).into()); children.push(horizontal_rule(1).into());
children children
.push(menu_action(fl!("restore-from-trash"), Action::RestoreFromTrash).into()); .push(menu_item(fl!("restore-from-trash"), Action::RestoreFromTrash).into());
} }
} }
} }
children.push(horizontal_rule(1).into());
children.push(menu_action(fl!("properties"), Action::Properties).into());
widget::container(widget::column::with_children(children)) widget::container(widget::column::with_children(children))
.padding(1) .padding(1)
@ -134,7 +160,7 @@ pub fn menu_bar<'a>(key_binds: &HashMap<KeyBind, Action>) -> Element<'a, Message
menu_item(fl!("new-window"), Action::WindowNew), menu_item(fl!("new-window"), Action::WindowNew),
menu_item(fl!("new-file"), Action::NewFile), menu_item(fl!("new-file"), Action::NewFile),
menu_item(fl!("new-folder"), Action::NewFolder), menu_item(fl!("new-folder"), Action::NewFolder),
//TODO: open menu_item(fl!("open"), Action::Open),
MenuTree::new(horizontal_rule(1)), MenuTree::new(horizontal_rule(1)),
menu_item(fl!("rename"), Action::Rename), menu_item(fl!("rename"), Action::Rename),
//TOOD: add to sidebar, then divider //TOOD: add to sidebar, then divider

View file

@ -32,7 +32,9 @@ use crate::{
app::Action, app::Action,
config::{IconSizes, TabConfig}, config::{IconSizes, TabConfig},
dialog::DialogKind, dialog::DialogKind,
fl, menu, fl,
key_bind::KeyBind,
menu,
mime_icon::mime_icon, mime_icon::mime_icon,
mouse_area, mouse_area,
}; };
@ -373,6 +375,7 @@ pub enum Message {
GoPrevious, GoPrevious,
Location(Location), Location(Location),
LocationUp, LocationUp,
Open,
RightClick(usize), RightClick(usize),
Scroll(Viewport), Scroll(Viewport),
Thumbnail(PathBuf, Result<image::RgbaImage, ()>), Thumbnail(PathBuf, Result<image::RgbaImage, ()>),
@ -714,6 +717,27 @@ impl Tab {
} }
} }
} }
Message::Open => {
if let Some(ref mut items) = self.items_opt {
for item in items.iter() {
if item.selected {
match self.location {
Location::Path(_) => {
if item.path.is_dir() {
//TODO: allow opening multiple tabs?
cd = Some(Location::Path(item.path.clone()));
} else {
commands.push(Command::OpenFile(item.path.clone()));
}
}
Location::Trash => {
//TODO: open properties?
}
}
}
}
}
}
Message::RightClick(click_i) => { Message::RightClick(click_i) => {
if let Some(ref mut items) = self.items_opt { if let Some(ref mut items) = self.items_opt {
if !items.get(click_i).map_or(false, |x| x.selected) { if !items.get(click_i).map_or(false, |x| x.selected) {
@ -1214,7 +1238,7 @@ impl Tab {
.into() .into()
} }
pub fn view(&self, core: &Core) -> Element<Message> { pub fn view(&self, core: &Core, key_binds: &HashMap<KeyBind, Action>) -> Element<Message> {
let location_view = self.location_view(core); let location_view = self.location_view(core);
let item_view = match self.view { let item_view = match self.view {
View::Grid => self.grid_view(core), View::Grid => self.grid_view(core),
@ -1237,7 +1261,7 @@ impl Tab {
let mut popover = widget::popover(mouse_area); let mut popover = widget::popover(mouse_area);
if let Some(point) = self.context_menu { if let Some(point) = self.context_menu {
popover = popover popover = popover
.popup(menu::context_menu(&self)) .popup(menu::context_menu(&self, &key_binds))
.position(widget::popover::Position::Point(point)); .position(widget::popover::Position::Point(point));
} }
widget::container(widget::column::with_children(vec![ widget::container(widget::column::with_children(vec![