diff --git a/Cargo.lock b/Cargo.lock index 1ef0a49f..27af214d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1222,7 +1222,7 @@ dependencies = [ [[package]] name = "cosmic-config" version = "0.1.0" -source = "git+https://github.com/pop-os/libcosmic.git#aaadf7199ebed8a5a04ebed559f62455d622689e" +source = "git+https://github.com/pop-os/libcosmic.git#62b0c8a401c175ab956229b2901f2fdb8b96aeab" dependencies = [ "atomicwrites", "cosmic-config-derive", @@ -1241,7 +1241,7 @@ dependencies = [ [[package]] name = "cosmic-config-derive" version = "0.1.0" -source = "git+https://github.com/pop-os/libcosmic.git#aaadf7199ebed8a5a04ebed559f62455d622689e" +source = "git+https://github.com/pop-os/libcosmic.git#62b0c8a401c175ab956229b2901f2fdb8b96aeab" dependencies = [ "quote", "syn 1.0.109", @@ -1348,7 +1348,7 @@ dependencies = [ [[package]] name = "cosmic-theme" version = "0.1.0" -source = "git+https://github.com/pop-os/libcosmic.git#aaadf7199ebed8a5a04ebed559f62455d622689e" +source = "git+https://github.com/pop-os/libcosmic.git#62b0c8a401c175ab956229b2901f2fdb8b96aeab" dependencies = [ "almost", "cosmic-config", @@ -2776,7 +2776,7 @@ dependencies = [ [[package]] name = "iced" version = "0.14.0-dev" -source = "git+https://github.com/pop-os/libcosmic.git#aaadf7199ebed8a5a04ebed559f62455d622689e" +source = "git+https://github.com/pop-os/libcosmic.git#62b0c8a401c175ab956229b2901f2fdb8b96aeab" dependencies = [ "dnd", "iced_accessibility", @@ -2794,7 +2794,7 @@ dependencies = [ [[package]] name = "iced_accessibility" version = "0.1.0" -source = "git+https://github.com/pop-os/libcosmic.git#aaadf7199ebed8a5a04ebed559f62455d622689e" +source = "git+https://github.com/pop-os/libcosmic.git#62b0c8a401c175ab956229b2901f2fdb8b96aeab" dependencies = [ "accesskit", "accesskit_winit", @@ -2803,7 +2803,7 @@ dependencies = [ [[package]] name = "iced_core" version = "0.14.0-dev" -source = "git+https://github.com/pop-os/libcosmic.git#aaadf7199ebed8a5a04ebed559f62455d622689e" +source = "git+https://github.com/pop-os/libcosmic.git#62b0c8a401c175ab956229b2901f2fdb8b96aeab" dependencies = [ "bitflags 2.6.0", "bytes", @@ -2827,7 +2827,7 @@ dependencies = [ [[package]] name = "iced_futures" version = "0.14.0-dev" -source = "git+https://github.com/pop-os/libcosmic.git#aaadf7199ebed8a5a04ebed559f62455d622689e" +source = "git+https://github.com/pop-os/libcosmic.git#62b0c8a401c175ab956229b2901f2fdb8b96aeab" dependencies = [ "futures", "iced_core", @@ -2853,7 +2853,7 @@ dependencies = [ [[package]] name = "iced_graphics" version = "0.14.0-dev" -source = "git+https://github.com/pop-os/libcosmic.git#aaadf7199ebed8a5a04ebed559f62455d622689e" +source = "git+https://github.com/pop-os/libcosmic.git#62b0c8a401c175ab956229b2901f2fdb8b96aeab" dependencies = [ "bitflags 2.6.0", "bytemuck", @@ -2875,7 +2875,7 @@ dependencies = [ [[package]] name = "iced_renderer" version = "0.14.0-dev" -source = "git+https://github.com/pop-os/libcosmic.git#aaadf7199ebed8a5a04ebed559f62455d622689e" +source = "git+https://github.com/pop-os/libcosmic.git#62b0c8a401c175ab956229b2901f2fdb8b96aeab" dependencies = [ "iced_graphics", "iced_tiny_skia", @@ -2887,7 +2887,7 @@ dependencies = [ [[package]] name = "iced_runtime" version = "0.14.0-dev" -source = "git+https://github.com/pop-os/libcosmic.git#aaadf7199ebed8a5a04ebed559f62455d622689e" +source = "git+https://github.com/pop-os/libcosmic.git#62b0c8a401c175ab956229b2901f2fdb8b96aeab" dependencies = [ "bytes", "dnd", @@ -2902,7 +2902,7 @@ dependencies = [ [[package]] name = "iced_tiny_skia" version = "0.14.0-dev" -source = "git+https://github.com/pop-os/libcosmic.git#aaadf7199ebed8a5a04ebed559f62455d622689e" +source = "git+https://github.com/pop-os/libcosmic.git#62b0c8a401c175ab956229b2901f2fdb8b96aeab" dependencies = [ "bytemuck", "cosmic-text", @@ -2918,7 +2918,7 @@ dependencies = [ [[package]] name = "iced_wgpu" version = "0.14.0-dev" -source = "git+https://github.com/pop-os/libcosmic.git#aaadf7199ebed8a5a04ebed559f62455d622689e" +source = "git+https://github.com/pop-os/libcosmic.git#62b0c8a401c175ab956229b2901f2fdb8b96aeab" dependencies = [ "as-raw-xcb-connection", "bitflags 2.6.0", @@ -2949,7 +2949,7 @@ dependencies = [ [[package]] name = "iced_widget" version = "0.14.0-dev" -source = "git+https://github.com/pop-os/libcosmic.git#aaadf7199ebed8a5a04ebed559f62455d622689e" +source = "git+https://github.com/pop-os/libcosmic.git#62b0c8a401c175ab956229b2901f2fdb8b96aeab" dependencies = [ "dnd", "iced_renderer", @@ -2967,7 +2967,7 @@ dependencies = [ [[package]] name = "iced_winit" version = "0.14.0-dev" -source = "git+https://github.com/pop-os/libcosmic.git#aaadf7199ebed8a5a04ebed559f62455d622689e" +source = "git+https://github.com/pop-os/libcosmic.git#62b0c8a401c175ab956229b2901f2fdb8b96aeab" dependencies = [ "dnd", "iced_futures", @@ -3551,7 +3551,7 @@ checksum = "18d287de67fe55fd7e1581fe933d965a5a9477b38e949cfa9f8574ef01506398" [[package]] name = "libcosmic" version = "0.1.0" -source = "git+https://github.com/pop-os/libcosmic.git#aaadf7199ebed8a5a04ebed559f62455d622689e" +source = "git+https://github.com/pop-os/libcosmic.git#62b0c8a401c175ab956229b2901f2fdb8b96aeab" dependencies = [ "apply", "ashpd 0.9.2", @@ -3575,6 +3575,7 @@ dependencies = [ "iced_winit", "lazy_static", "libc", + "license", "mime 0.3.17", "palette", "rfd", @@ -3649,6 +3650,17 @@ dependencies = [ "redox_syscall 0.5.7", ] +[[package]] +name = "license" +version = "3.5.1+3.25.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8825807237bd9fa571b99ffea06a26901b0e44692208f87e3b040a499f1504a7" +dependencies = [ + "reword", + "serde", + "serde_json", +] + [[package]] name = "linux-raw-sys" version = "0.3.8" @@ -5253,6 +5265,15 @@ dependencies = [ "usvg", ] +[[package]] +name = "reword" +version = "7.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe272098dce9ed76b479995953f748d1851261390b08f8a0ff619c885a1f0765" +dependencies = [ + "unicode-segmentation", +] + [[package]] name = "rfd" version = "0.14.1" diff --git a/Cargo.toml b/Cargo.toml index 52b6721e..6240446d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -63,7 +63,7 @@ uzers = "0.12.0" git = "https://github.com/pop-os/libcosmic.git" default-features = false #TODO: a11y feature crashes -features = ["multi-window", "tokio", "winit"] +features = ["multi-window", "tokio", "winit", "about"] [features] default = ["bzip2", "desktop", "gvfs", "liblzma", "notify", "wgpu"] diff --git a/i18n/en/cosmic_files.ftl b/i18n/en/cosmic_files.ftl index a05cd2d2..b28d1492 100644 --- a/i18n/en/cosmic_files.ftl +++ b/i18n/en/cosmic_files.ftl @@ -277,3 +277,7 @@ sort-newest-first = Newest first sort-oldest-first = Oldest first sort-smallest-to-largest = Smallest to largest sort-largest-to-smallest = Largest to smallest + +## About +repository = Repository +support = Support diff --git a/res/icons/bundled/archive-extract-symbolic.svg b/res/icons/bundled/archive-extract-symbolic.svg new file mode 100644 index 00000000..4fe1863e --- /dev/null +++ b/res/icons/bundled/archive-extract-symbolic.svg @@ -0,0 +1,2 @@ + + diff --git a/res/icons/bundled/arrow-into-box-symbolic.svg b/res/icons/bundled/arrow-into-box-symbolic.svg new file mode 100644 index 00000000..fca4bc39 --- /dev/null +++ b/res/icons/bundled/arrow-into-box-symbolic.svg @@ -0,0 +1,2 @@ + + diff --git a/res/icons/bundled/brush-monitor-symbolic.svg b/res/icons/bundled/brush-monitor-symbolic.svg new file mode 100644 index 00000000..8b0436a0 --- /dev/null +++ b/res/icons/bundled/brush-monitor-symbolic.svg @@ -0,0 +1,2 @@ + + diff --git a/res/icons/bundled/clipboard-symbolic.svg b/res/icons/bundled/clipboard-symbolic.svg new file mode 100644 index 00000000..9ba800e2 --- /dev/null +++ b/res/icons/bundled/clipboard-symbolic.svg @@ -0,0 +1,2 @@ + + diff --git a/res/icons/bundled/copy-symbolic.svg b/res/icons/bundled/copy-symbolic.svg new file mode 100644 index 00000000..7aad5a3e --- /dev/null +++ b/res/icons/bundled/copy-symbolic.svg @@ -0,0 +1,2 @@ + + diff --git a/res/icons/bundled/cross-small-square-filled-symbolic.svg b/res/icons/bundled/cross-small-square-filled-symbolic.svg new file mode 100644 index 00000000..4f83c5d1 --- /dev/null +++ b/res/icons/bundled/cross-small-square-filled-symbolic.svg @@ -0,0 +1,2 @@ + + diff --git a/res/icons/bundled/cut-symbolic.svg b/res/icons/bundled/cut-symbolic.svg new file mode 100644 index 00000000..5e00a6d3 --- /dev/null +++ b/res/icons/bundled/cut-symbolic.svg @@ -0,0 +1,2 @@ + + diff --git a/res/icons/bundled/display-symbolic.svg b/res/icons/bundled/display-symbolic.svg new file mode 100644 index 00000000..e3152317 --- /dev/null +++ b/res/icons/bundled/display-symbolic.svg @@ -0,0 +1,2 @@ + + diff --git a/res/icons/bundled/dock-left-symbolic.svg b/res/icons/bundled/dock-left-symbolic.svg new file mode 100644 index 00000000..3c515204 --- /dev/null +++ b/res/icons/bundled/dock-left-symbolic.svg @@ -0,0 +1,2 @@ + + diff --git a/res/icons/bundled/document-open-symbolic.svg b/res/icons/bundled/document-open-symbolic.svg new file mode 100644 index 00000000..9ca10452 --- /dev/null +++ b/res/icons/bundled/document-open-symbolic.svg @@ -0,0 +1,2 @@ + + diff --git a/res/icons/bundled/edit-copy-symbolic.svg b/res/icons/bundled/edit-copy-symbolic.svg new file mode 100644 index 00000000..230b742c --- /dev/null +++ b/res/icons/bundled/edit-copy-symbolic.svg @@ -0,0 +1,2 @@ + + diff --git a/res/icons/bundled/edit-select-all-symbolic.svg b/res/icons/bundled/edit-select-all-symbolic.svg new file mode 100644 index 00000000..d1e48c28 --- /dev/null +++ b/res/icons/bundled/edit-select-all-symbolic.svg @@ -0,0 +1,2 @@ + + diff --git a/res/icons/bundled/edit-symbolic.svg b/res/icons/bundled/edit-symbolic.svg new file mode 100644 index 00000000..51090b91 --- /dev/null +++ b/res/icons/bundled/edit-symbolic.svg @@ -0,0 +1,2 @@ + + diff --git a/res/icons/bundled/empty-trash-bin-symbolic.svg b/res/icons/bundled/empty-trash-bin-symbolic.svg new file mode 100644 index 00000000..f27ba1b0 --- /dev/null +++ b/res/icons/bundled/empty-trash-bin-symbolic.svg @@ -0,0 +1,2 @@ + + diff --git a/res/icons/bundled/external-link-symbolic.svg b/res/icons/bundled/external-link-symbolic.svg new file mode 100644 index 00000000..e88a887a --- /dev/null +++ b/res/icons/bundled/external-link-symbolic.svg @@ -0,0 +1,2 @@ + + diff --git a/res/icons/bundled/folder-new-symbolic.svg b/res/icons/bundled/folder-new-symbolic.svg new file mode 100644 index 00000000..2d467ae9 --- /dev/null +++ b/res/icons/bundled/folder-new-symbolic.svg @@ -0,0 +1,2 @@ + + diff --git a/res/icons/bundled/folder-symbolic.svg b/res/icons/bundled/folder-symbolic.svg new file mode 100644 index 00000000..c7f1815c --- /dev/null +++ b/res/icons/bundled/folder-symbolic.svg @@ -0,0 +1,2 @@ + + diff --git a/res/icons/bundled/grid-symbolic.svg b/res/icons/bundled/grid-symbolic.svg new file mode 100644 index 00000000..441f2752 --- /dev/null +++ b/res/icons/bundled/grid-symbolic.svg @@ -0,0 +1,2 @@ + + diff --git a/res/icons/bundled/history-undo-symbolic.svg b/res/icons/bundled/history-undo-symbolic.svg new file mode 100644 index 00000000..c1afe3ad --- /dev/null +++ b/res/icons/bundled/history-undo-symbolic.svg @@ -0,0 +1,2 @@ + + diff --git a/res/icons/bundled/image-round-symbolic.svg b/res/icons/bundled/image-round-symbolic.svg new file mode 100644 index 00000000..0f687ca1 --- /dev/null +++ b/res/icons/bundled/image-round-symbolic.svg @@ -0,0 +1,2 @@ + + diff --git a/res/icons/bundled/info-outline-symbolic.svg b/res/icons/bundled/info-outline-symbolic.svg new file mode 100644 index 00000000..254e7e83 --- /dev/null +++ b/res/icons/bundled/info-outline-symbolic.svg @@ -0,0 +1,2 @@ + + diff --git a/res/icons/bundled/list-large-symbolic.svg b/res/icons/bundled/list-large-symbolic.svg new file mode 100644 index 00000000..cbcd0bbd --- /dev/null +++ b/res/icons/bundled/list-large-symbolic.svg @@ -0,0 +1,2 @@ + + diff --git a/res/icons/bundled/loupe-symbolic.svg b/res/icons/bundled/loupe-symbolic.svg new file mode 100644 index 00000000..da6ef8c5 --- /dev/null +++ b/res/icons/bundled/loupe-symbolic.svg @@ -0,0 +1,2 @@ + + diff --git a/res/icons/bundled/package-x-generic-symbolic.svg b/res/icons/bundled/package-x-generic-symbolic.svg new file mode 100644 index 00000000..16076016 --- /dev/null +++ b/res/icons/bundled/package-x-generic-symbolic.svg @@ -0,0 +1,2 @@ + + diff --git a/res/icons/bundled/paper-symbolic.svg b/res/icons/bundled/paper-symbolic.svg new file mode 100644 index 00000000..d24c7186 --- /dev/null +++ b/res/icons/bundled/paper-symbolic.svg @@ -0,0 +1,2 @@ + + diff --git a/res/icons/bundled/settings-symbolic.svg b/res/icons/bundled/settings-symbolic.svg new file mode 100644 index 00000000..408d7e5d --- /dev/null +++ b/res/icons/bundled/settings-symbolic.svg @@ -0,0 +1,2 @@ + + diff --git a/res/icons/bundled/shell-overview-symbolic.svg b/res/icons/bundled/shell-overview-symbolic.svg new file mode 100644 index 00000000..ef1bf2a6 --- /dev/null +++ b/res/icons/bundled/shell-overview-symbolic.svg @@ -0,0 +1,2 @@ + + diff --git a/res/icons/bundled/symbolic-link-symbolic.svg b/res/icons/bundled/symbolic-link-symbolic.svg new file mode 100644 index 00000000..0d582a9e --- /dev/null +++ b/res/icons/bundled/symbolic-link-symbolic.svg @@ -0,0 +1,2 @@ + + diff --git a/res/icons/bundled/tab-new-filled-symbolic.svg b/res/icons/bundled/tab-new-filled-symbolic.svg new file mode 100644 index 00000000..2b2f1d80 --- /dev/null +++ b/res/icons/bundled/tab-new-filled-symbolic.svg @@ -0,0 +1,2 @@ + + diff --git a/res/icons/bundled/terminal-symbolic.svg b/res/icons/bundled/terminal-symbolic.svg new file mode 100644 index 00000000..f2bba5b9 --- /dev/null +++ b/res/icons/bundled/terminal-symbolic.svg @@ -0,0 +1,2 @@ + + diff --git a/res/icons/bundled/user-trash-symbolic.svg b/res/icons/bundled/user-trash-symbolic.svg new file mode 100644 index 00000000..f99b5009 --- /dev/null +++ b/res/icons/bundled/user-trash-symbolic.svg @@ -0,0 +1,2 @@ + + diff --git a/res/icons/bundled/value-decrease-symbolic.svg b/res/icons/bundled/value-decrease-symbolic.svg new file mode 100644 index 00000000..41f0b6a4 --- /dev/null +++ b/res/icons/bundled/value-decrease-symbolic.svg @@ -0,0 +1,2 @@ + + diff --git a/res/icons/bundled/value-increase-symbolic.svg b/res/icons/bundled/value-increase-symbolic.svg new file mode 100644 index 00000000..1470fac6 --- /dev/null +++ b/res/icons/bundled/value-increase-symbolic.svg @@ -0,0 +1,2 @@ + + diff --git a/res/icons/bundled/view-conceal-symbolic.svg b/res/icons/bundled/view-conceal-symbolic.svg new file mode 100644 index 00000000..3f1cb044 --- /dev/null +++ b/res/icons/bundled/view-conceal-symbolic.svg @@ -0,0 +1,2 @@ + + diff --git a/src/app.rs b/src/app.rs index 7388ec17..86558d28 100644 --- a/src/app.rs +++ b/src/app.rs @@ -13,7 +13,7 @@ use cosmic::iced::{ Limits, }; use cosmic::{ - app::{self, message, Core, Task}, + app::{self, context_drawer, message, Core, Task}, cosmic_config, cosmic_theme, executor, iced::{ clipboard::dnd::DndAction, @@ -29,6 +29,7 @@ use cosmic::{ style, theme, widget::{ self, + about::About, dnd_destination::DragId, menu::{action::MenuAction, key_bind::KeyBind}, segmented_button::{self, Entity}, @@ -69,6 +70,8 @@ use crate::{ tab::{self, HeadingOptions, ItemMetadata, Location, Tab, HOVER_DURATION}, }; +pub mod icons; + #[derive(Clone, Debug)] pub enum Mode { App, @@ -339,6 +342,7 @@ pub enum Message { ), TabView(Option, tab::View), ToggleContextPage(ContextPage), + ToggleContextDrawer, ToggleFoldersFirst, Undo(usize), UndoTrash(widget::ToastId, Arc<[PathBuf]>), @@ -503,6 +507,7 @@ impl PartialEq for WatcherWrapper { /// The [`App`] stores application-specific state. pub struct App { core: Core, + about: About, nav_bar_context_id: segmented_button::Entity, nav_model: segmented_button::SingleSelectModel, tab_model: segmented_button::Model, @@ -1429,8 +1434,24 @@ impl Application for App { let window_id_opt = core.main_window_id(); + let about = About::default() + .name(fl!("cosmic-files")) + .author("System 76") + .icon(Self::APP_ID) + .version("0.1.0") + .license("GPL-3.0-only") + .links([ + (fl!("repository"), "https://github.com/pop-os/cosmic-files"), + ( + fl!("support"), + "https://github.com/pop-os/cosmic-files/issues", + ), + ]) + .developers([("Jeremy Soller", "jeremy@system76.com")]); + let mut app = App { core, + about, nav_bar_context_id: segmented_button::Entity::null(), nav_model: segmented_button::ModelBuilder::default().build(), tab_model: segmented_button::ModelBuilder::default().build(), @@ -1539,37 +1560,44 @@ impl Application for App { { items.push(cosmic::widget::menu::Item::Button( fl!("open"), + Some(icons::get_handle("document-open-symbolic", 14)), NavMenuAction::Open(entity), )); items.push(cosmic::widget::menu::Item::Button( fl!("open-with"), + Some(icons::get_handle("external-link-symbolic", 14)), NavMenuAction::OpenWith(entity), )); } else { items.push(cosmic::widget::menu::Item::Button( fl!("open-in-new-tab"), + Some(icons::get_handle("tab-new-filled-symbolic", 14)), NavMenuAction::OpenInNewTab(entity), )); items.push(cosmic::widget::menu::Item::Button( fl!("open-in-new-window"), + Some(icons::get_handle("edit-copy-symbolic", 14)), NavMenuAction::OpenInNewWindow(entity), )); } items.push(cosmic::widget::menu::Item::Divider); items.push(cosmic::widget::menu::Item::Button( fl!("show-details"), + Some(icons::get_handle("info-outline-symbolic", 14)), NavMenuAction::Preview(entity), )); items.push(cosmic::widget::menu::Item::Divider); if favorite_index_opt.is_some() { items.push(cosmic::widget::menu::Item::Button( fl!("remove-from-sidebar"), + Some(icons::get_handle("cross-small-square-filled-symbolic", 14)), NavMenuAction::RemoveFromSidebar(entity), )); } if matches!(location_opt, Some(Location::Trash)) { items.push(cosmic::widget::menu::Item::Button( fl!("empty-trash"), + Some(icons::get_handle("user-trash-symbolic", 14)), NavMenuAction::EmptyTrash, )); } @@ -2724,7 +2752,6 @@ impl Application for App { tab::Command::AddNetworkDrive => { self.context_page = ContextPage::NetworkDrive; self.set_show_context(true); - self.set_context_title(self.context_page.title()); } tab::Command::AddToSidebar(path) => { let mut favorites = self.config.favorites.clone(); @@ -2792,7 +2819,6 @@ impl Application for App { tab::Command::Preview(kind) => { self.context_page = ContextPage::Preview(Some(entity), kind); self.set_show_context(true); - self.set_context_title(self.context_page.title()); } tab::Command::WindowDrag => { if let Some(window_id) = &self.window_id_opt { @@ -2847,7 +2873,9 @@ impl Application for App { self.set_show_context(true); } self.context_page = context_page; - self.set_context_title(self.context_page.title()); + } + Message::ToggleContextDrawer => { + self.set_show_context(!self.core.window.show_context); } Message::Undo(_id) => { // TODO: undo @@ -3183,7 +3211,6 @@ impl Application for App { PreviewKind::Custom(PreviewItem(item)), ); self.set_show_context(true); - self.set_context_title(self.context_page.title()); } Err(err) => { log::warn!("failed to get item from path {:?}: {}", path, err); @@ -3302,17 +3329,34 @@ impl Application for App { Task::none() } - fn context_drawer(&self) -> Option> { + fn context_drawer(&self) -> Option> { if !self.core.window.show_context { return None; } Some(match &self.context_page { - ContextPage::About => self.about(), - ContextPage::EditHistory => self.edit_history(), - ContextPage::NetworkDrive => self.network_drive(), - ContextPage::Preview(entity_opt, kind) => self.preview(entity_opt, kind, true), - ContextPage::Settings => self.settings(), + ContextPage::About => context_drawer::about( + &self.about, + Message::LaunchUrl, + Message::ToggleContextDrawer, + ), + ContextPage::EditHistory => { + context_drawer::context_drawer(self.edit_history(), Message::ToggleContextDrawer) + .title(self.context_page.title()) + } + ContextPage::NetworkDrive => { + context_drawer::context_drawer(self.network_drive(), Message::ToggleContextDrawer) + .title(self.context_page.title()) + } + ContextPage::Preview(entity_opt, kind) => context_drawer::context_drawer( + self.preview(entity_opt, kind, true), + Message::ToggleContextDrawer, + ) + .title(self.context_page.title()), + ContextPage::Settings => { + context_drawer::context_drawer(self.settings(), Message::ToggleContextDrawer) + .title(self.context_page.title()) + } }) } diff --git a/src/app/icons.rs b/src/app/icons.rs new file mode 100644 index 00000000..368befaf --- /dev/null +++ b/src/app/icons.rs @@ -0,0 +1,103 @@ +// SPDX-License-Identifier: GPL-3.0-only + +use cosmic::widget::icon; +use std::collections::HashMap; +use std::sync::{Mutex, OnceLock}; + +pub(crate) static ICON_CACHE: OnceLock> = OnceLock::new(); + +#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] +pub struct IconCacheKey { + name: &'static str, + size: u16, +} + +pub struct IconCache { + cache: HashMap, +} + +impl IconCache { + pub fn new() -> Self { + let mut cache = HashMap::new(); + + macro_rules! bundle { + ($name:expr, $size:expr) => { + let data: &'static [u8] = + include_bytes!(concat!("../../res/icons/bundled/", $name, ".svg")); + cache.insert( + IconCacheKey { + name: $name, + size: $size, + }, + icon::from_svg_bytes(data).symbolic(true), + ); + }; + } + + bundle!("tab-new-filled-symbolic", 14); + bundle!("value-increase-symbolic", 14); + bundle!("value-decrease-symbolic", 14); + bundle!("loupe-symbolic", 14); + bundle!("folder-symbolic", 14); + bundle!("folder-new-symbolic", 14); + bundle!("edit-copy-symbolic", 14); + bundle!("paper-symbolic", 14); + bundle!("document-open-symbolic", 14); + bundle!("arrow-into-box-symbolic", 14); + bundle!("edit-symbolic", 14); + bundle!("user-trash-symbolic", 14); + bundle!("cross-small-square-filled-symbolic", 14); + bundle!("external-link-symbolic", 14); + bundle!("cut-symbolic", 14); + bundle!("copy-symbolic", 14); + bundle!("clipboard-symbolic", 14); + bundle!("edit-select-all-symbolic", 14); + bundle!("history-undo-symbolic", 14); + bundle!("grid-symbolic", 14); + bundle!("list-large-symbolic", 14); + bundle!("view-conceal-symbolic", 14); + bundle!("settings-symbolic", 14); + bundle!("info-outline-symbolic", 14); + bundle!("dock-left-symbolic", 14); + bundle!("arrow-into-box-symbolic", 14); + bundle!("image-round-symbolic", 14); + bundle!("terminal-symbolic", 14); + bundle!("symbolic-link-symbolic", 14); + bundle!("package-x-generic-symbolic", 14); + bundle!("archive-extract-symbolic", 14); + bundle!("brush-monitor-symbolic", 14); + bundle!("display-symbolic", 14); + bundle!("shell-overview-symbolic", 14); + bundle!("empty-trash-bin-symbolic", 14); + + Self { cache } + } + + pub fn get_icon(&mut self, name: &'static str, size: u16) -> icon::Icon { + let handle = self + .cache + .entry(IconCacheKey { name, size }) + .or_insert_with(|| icon::from_name(name).size(size).handle()) + .clone(); + icon::icon(handle).size(size) + } + + pub fn get_handle(&mut self, name: &'static str, size: u16) -> icon::Handle { + let handle = self + .cache + .entry(IconCacheKey { name, size }) + .or_insert_with(|| icon::from_name(name).size(size).handle()) + .clone(); + handle + } +} + +pub fn get_icon(name: &'static str, size: u16) -> icon::Icon { + let mut icon_cache = ICON_CACHE.get().unwrap().lock().unwrap(); + icon_cache.get_icon(name, size) +} + +pub fn get_handle(name: &'static str, size: u16) -> icon::Handle { + let mut icon_cache = ICON_CACHE.get().unwrap().lock().unwrap(); + icon_cache.get_handle(name, size) +} diff --git a/src/dialog.rs b/src/dialog.rs index 794b63a0..5490f743 100644 --- a/src/dialog.rs +++ b/src/dialog.rs @@ -2,7 +2,7 @@ // SPDX-License-Identifier: GPL-3.0-only use cosmic::{ - app::{self, cosmic::Cosmic, message, Core, Task}, + app::{self, context_drawer, cosmic::Cosmic, message, Core, Task}, cosmic_config, cosmic_theme, executor, iced::{ event, @@ -794,13 +794,16 @@ impl Application for App { (app, commands) } - fn context_drawer(&self) -> Option> { + fn context_drawer(&self) -> Option> { if !self.core.window.show_context { return None; } match &self.context_page { - ContextPage::Preview(_, kind) => Some(self.preview(kind).map(Message::from)), + ContextPage::Preview(_, kind) => Some(context_drawer::context_drawer( + self.preview(kind).map(Message::from), + Message::DialogCancel, + )), _ => None, } } @@ -1401,7 +1404,6 @@ impl Application for App { tab::Command::Preview(kind) => { self.context_page = ContextPage::Preview(None, kind); self.set_show_context(true); - self.set_context_title(self.context_page.title()); } tab::Command::WindowDrag => { commands.push(window::drag(self.flags.window_id)); diff --git a/src/lib.rs b/src/lib.rs index c6ca3456..650c87d6 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -2,9 +2,12 @@ // SPDX-License-Identifier: GPL-3.0-only use cosmic::{app::Settings, iced::Limits}; -use std::{env, fs, path::PathBuf, process}; +use std::{env, fs, path::PathBuf, process, sync::Mutex}; -use app::{App, Flags}; +use app::{ + icons::{IconCache, ICON_CACHE}, + App, Flags, +}; pub mod app; pub mod clipboard; use config::Config; @@ -87,6 +90,8 @@ pub fn main() -> Result<(), Box> { localize::localize(); + ICON_CACHE.get_or_init(|| Mutex::new(IconCache::new())); + let (config_handler, config) = Config::load(); let mut daemonize = true; diff --git a/src/menu.rs b/src/menu.rs index d3616ae2..c3703548 100644 --- a/src/menu.rs +++ b/src/menu.rs @@ -15,7 +15,7 @@ use mime_guess::Mime; use std::collections::HashMap; use crate::{ - app::{Action, Message}, + app::{icons, Action, Message}, config::Config, fl, tab::{self, HeadingOptions, Location, LocationMenuAction, Tab}, @@ -38,13 +38,14 @@ macro_rules! menu_button { fn menu_button_optional( label: String, + icon: Option, action: Action, enabled: bool, ) -> menu::Item { if enabled { - menu::Item::Button(label, action) + menu::Item::Button(label, icon, action) } else { - menu::Item::ButtonDisabled(label, action) + menu::Item::ButtonDisabled(label, icon, action) } } @@ -61,14 +62,25 @@ pub fn context_menu<'a>( String::new() }; - let menu_item = |label, action| { + let menu_item = |label, icon, action| { let key = find_key(&action); - menu_button!(text::body(label), horizontal_space(), text::body(key)) + if let Some(icon) = icon { + menu_button!( + widget::icon(icon), + widget::Space::with_width(8.0), + text::body(label), + horizontal_space(), + text::body(key) + ) .on_press(tab::Message::ContextAction(action)) + } else { + menu_button!(text::body(label), horizontal_space(), text::body(key)) + .on_press(tab::Message::ContextAction(action)) + } }; let (sort_name, sort_direction, _) = tab.sort_options(); - let sort_item = |label, variant| { + let sort_item = |label, icon, variant| { menu_item( format!( "{} {}", @@ -79,6 +91,7 @@ pub fn context_menu<'a>( _ => "", } ), + icon, Action::ToggleSort(variant), ) .into() @@ -134,50 +147,159 @@ pub fn context_menu<'a>( Location::Desktop(..) | Location::Path(..) | Location::Search(..) | Location::Recents, ) => { if selected_trash_only { - children.push(menu_item(fl!("open"), Action::Open).into()); + children.push( + menu_item( + fl!("open"), + Some(icons::get_handle("document-open-symbolic", 14)), + Action::Open, + ) + .into(), + ); if tab::trash_entries() > 0 { - children.push(menu_item(fl!("empty-trash"), Action::EmptyTrash).into()); + children.push( + menu_item( + fl!("empty-trash"), + Some(icons::get_handle("user-trash-symbolic", 14)), + Action::EmptyTrash, + ) + .into(), + ); } } else if let Some(entry) = selected_desktop_entry { - children.push(menu_item(fl!("open"), Action::Open).into()); + children.push( + menu_item( + fl!("open"), + Some(icons::get_handle("document-open-symbolic", 14)), + Action::Open, + ) + .into(), + ); #[cfg(feature = "desktop")] { for (i, action) in entry.desktop_actions.into_iter().enumerate() { - children.push(menu_item(action.name, Action::ExecEntryAction(i)).into()) + children + .push(menu_item(action.name, None, Action::ExecEntryAction(i)).into()) } } children.push(divider::horizontal::light().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()); + children.push( + menu_item( + fl!("rename"), + Some(icons::get_handle("edit-symbolic", 14)), + Action::Rename, + ) + .into(), + ); + children.push( + menu_item( + fl!("cut"), + Some(icons::get_handle("cut-symbolic", 14)), + Action::Cut, + ) + .into(), + ); + children.push( + menu_item( + fl!("copy"), + Some(icons::get_handle("copy-symbolic", 14)), + Action::Copy, + ) + .into(), + ); // Should this simply bypass trash and remove the shortcut? - children.push(menu_item(fl!("move-to-trash"), Action::MoveToTrash).into()); + children.push( + menu_item( + fl!("move-to-trash"), + Some(icons::get_handle("user-trash-symbolic", 14)), + Action::MoveToTrash, + ) + .into(), + ); } else if selected > 0 { if selected_dir == 1 && selected == 1 || selected_dir == 0 { - children.push(menu_item(fl!("open"), Action::Open).into()); + children.push( + menu_item( + fl!("open"), + Some(icons::get_handle("document-open-symbolic", 14)), + Action::Open, + ) + .into(), + ); } if selected == 1 { - children.push(menu_item(fl!("open-with"), Action::OpenWith).into()); + children.push( + menu_item( + fl!("open-with"), + Some(icons::get_handle("external-link-symbolic", 14)), + Action::OpenWith, + ) + .into(), + ); if selected_dir == 1 { - children - .push(menu_item(fl!("open-in-terminal"), Action::OpenTerminal).into()); + children.push( + menu_item( + fl!("open-in-terminal"), + Some(icons::get_handle("terminal-symbolic", 14)), + Action::OpenTerminal, + ) + .into(), + ); } } if matches!(tab.location, Location::Search(..)) { children.push( - menu_item(fl!("open-item-location"), Action::OpenItemLocation).into(), + menu_item( + fl!("open-item-location"), + Some(icons::get_handle("symbolic-link-symbolic", 14)), + Action::OpenItemLocation, + ) + .into(), ); } // All selected items are directories if selected == selected_dir && matches!(tab.mode, tab::Mode::App) { - children.push(menu_item(fl!("open-in-new-tab"), Action::OpenInNewTab).into()); - children - .push(menu_item(fl!("open-in-new-window"), Action::OpenInNewWindow).into()); + children.push( + menu_item( + fl!("open-in-new-tab"), + Some(icons::get_handle("tab-new-filled-symbolic", 14)), + Action::OpenInNewTab, + ) + .into(), + ); + children.push( + menu_item( + fl!("open-in-new-window"), + Some(icons::get_handle("edit-copy-symbolic", 14)), + Action::OpenInNewWindow, + ) + .into(), + ); } children.push(divider::horizontal::light().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()); + children.push( + menu_item( + fl!("rename"), + Some(icons::get_handle("edit-symbolic", 14)), + Action::Rename, + ) + .into(), + ); + children.push( + menu_item( + fl!("cut"), + Some(icons::get_handle("cut-symbolic", 14)), + Action::Cut, + ) + .into(), + ); + children.push( + menu_item( + fl!("copy"), + Some(icons::get_handle("copy-symbolic", 14)), + Action::Copy, + ) + .into(), + ); children.push(divider::horizontal::light().into()); let supported_archive_types = [ @@ -199,55 +321,148 @@ pub fn context_menu<'a>( .collect::>(); selected_types.retain(|t| !supported_archive_types.contains(t)); if selected_types.is_empty() { - children.push(menu_item(fl!("extract-here"), Action::ExtractHere).into()); + children.push( + menu_item( + fl!("extract-here"), + Some(icons::get_handle("archive-extract-symbolic", 14)), + Action::ExtractHere, + ) + .into(), + ); } - children.push(menu_item(fl!("compress"), Action::Compress).into()); + children.push( + menu_item( + fl!("compress"), + Some(icons::get_handle("package-x-generic-symbolic", 14)), + Action::Compress, + ) + .into(), + ); children.push(divider::horizontal::light().into()); //TODO: Print? - children.push(menu_item(fl!("show-details"), Action::Preview).into()); + children.push( + menu_item( + fl!("show-details"), + Some(icons::get_handle("info-outline-symbolic", 14)), + Action::Preview, + ) + .into(), + ); if matches!(tab.mode, tab::Mode::App) { children.push(divider::horizontal::light().into()); - children.push(menu_item(fl!("add-to-sidebar"), Action::AddToSidebar).into()); + children.push( + menu_item( + fl!("add-to-sidebar"), + Some(icons::get_handle("dock-left-symbolic", 14)), + Action::AddToSidebar, + ) + .into(), + ); } children.push(divider::horizontal::light().into()); - children.push(menu_item(fl!("move-to-trash"), Action::MoveToTrash).into()); + children.push( + menu_item( + fl!("move-to-trash"), + Some(icons::get_handle("user-trash-symbolic", 14)), + 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-folder"), Action::NewFolder).into()); - children.push(menu_item(fl!("new-file"), Action::NewFile).into()); - children.push(menu_item(fl!("open-in-terminal"), Action::OpenTerminal).into()); + children.push( + menu_item( + fl!("new-folder"), + Some(icons::get_handle("folder-new-symbolic", 14)), + Action::NewFolder, + ) + .into(), + ); + children.push( + menu_item( + fl!("new-file"), + Some(icons::get_handle("paper-symbolic", 14)), + Action::NewFile, + ) + .into(), + ); + children.push( + menu_item( + fl!("open-in-terminal"), + Some(icons::get_handle("terminal-symbolic", 14)), + Action::OpenTerminal, + ) + .into(), + ); children.push(divider::horizontal::light().into()); if tab.mode.multiple() { - children.push(menu_item(fl!("select-all"), Action::SelectAll).into()); + children.push( + menu_item( + fl!("select-all"), + Some(icons::get_handle("edit-select-all-symbolic", 14)), + Action::SelectAll, + ) + .into(), + ); } - children.push(menu_item(fl!("paste"), Action::Paste).into()); + children.push( + menu_item( + fl!("paste"), + Some(icons::get_handle("clipboard-symbolic", 14)), + Action::Paste, + ) + .into(), + ); //TODO: only show if cosmic-settings is found? if matches!(tab.mode, tab::Mode::Desktop) { children.push(divider::horizontal::light().into()); children.push( - menu_item(fl!("change-wallpaper"), Action::CosmicSettingsWallpaper).into(), + menu_item( + fl!("change-wallpaper"), + Some(icons::get_handle("image-symbolic", 14)), + Action::CosmicSettingsWallpaper, + ) + .into(), ); children.push( - menu_item(fl!("desktop-appearance"), Action::CosmicSettingsAppearance) - .into(), + menu_item( + fl!("desktop-appearance"), + Some(icons::get_handle("brush-monitor-symbolic", 14)), + Action::CosmicSettingsAppearance, + ) + .into(), ); children.push( - menu_item(fl!("display-settings"), Action::CosmicSettingsDisplays).into(), + menu_item( + fl!("display-settings"), + Some(icons::get_handle("display-symbolic", 14)), + Action::CosmicSettingsDisplays, + ) + .into(), ); } children.push(divider::horizontal::light().into()); // TODO: Nested menu - children.push(sort_item(fl!("sort-by-name"), HeadingOptions::Name)); - children.push(sort_item(fl!("sort-by-modified"), HeadingOptions::Modified)); - children.push(sort_item(fl!("sort-by-size"), HeadingOptions::Size)); + children.push(sort_item(fl!("sort-by-name"), None, HeadingOptions::Name)); + children.push(sort_item( + fl!("sort-by-modified"), + None, + HeadingOptions::Modified, + )); + children.push(sort_item(fl!("sort-by-size"), None, HeadingOptions::Size)); if matches!(tab.location, Location::Desktop(..)) { children.push(divider::horizontal::light().into()); children.push( - menu_item(fl!("desktop-view-options"), Action::DesktopViewOptions).into(), + menu_item( + fl!("desktop-view-options"), + Some(icons::get_handle("shell-overview-symbolic", 14)), + Action::DesktopViewOptions, + ) + .into(), ); } } @@ -258,64 +473,143 @@ pub fn context_menu<'a>( ) => { if selected > 0 { if selected_dir == 1 && selected == 1 || selected_dir == 0 { - children.push(menu_item(fl!("open"), Action::Open).into()); + children.push( + menu_item( + fl!("open"), + Some(icons::get_handle("document-open-symbolic", 14)), + Action::Open, + ) + .into(), + ); } if matches!(tab.location, Location::Search(..)) { children.push( - menu_item(fl!("open-item-location"), Action::OpenItemLocation).into(), + menu_item( + fl!("open-item-location"), + Some(icons::get_handle("symbolic-link-symbolic", 14)), + Action::OpenItemLocation, + ) + .into(), ); } children.push(divider::horizontal::light().into()); - children.push(menu_item(fl!("show-details"), Action::Preview).into()); + children.push( + menu_item( + fl!("show-details"), + Some(icons::get_handle("info-outline-symbolic", 14)), + Action::Preview, + ) + .into(), + ); } else { if dialog_kind.save() { - children.push(menu_item(fl!("new-folder"), Action::NewFolder).into()); + children.push( + menu_item( + fl!("new-folder"), + Some(icons::get_handle("folder-new-symbolic", 14)), + Action::NewFolder, + ) + .into(), + ); } if tab.mode.multiple() { - children.push(menu_item(fl!("select-all"), Action::SelectAll).into()); + children.push( + menu_item( + fl!("select-all"), + Some(icons::get_handle("edit-select-all-symbolic", 14)), + Action::SelectAll, + ) + .into(), + ); } if !children.is_empty() { children.push(divider::horizontal::light().into()); } - children.push(sort_item(fl!("sort-by-name"), HeadingOptions::Name)); - children.push(sort_item(fl!("sort-by-modified"), HeadingOptions::Modified)); - children.push(sort_item(fl!("sort-by-size"), HeadingOptions::Size)); + children.push(sort_item(fl!("sort-by-name"), None, HeadingOptions::Name)); + children.push(sort_item( + fl!("sort-by-modified"), + None, + HeadingOptions::Modified, + )); + children.push(sort_item(fl!("sort-by-size"), None, HeadingOptions::Size)); } } (_, Location::Network(..)) => { if selected > 0 { if selected_dir == 1 && selected == 1 || selected_dir == 0 { - children.push(menu_item(fl!("open"), Action::Open).into()); + children.push( + menu_item( + fl!("open"), + Some(icons::get_handle("document-open-symbolic", 14)), + Action::Open, + ) + .into(), + ); } } else { if tab.mode.multiple() { - children.push(menu_item(fl!("select-all"), Action::SelectAll).into()); + children.push( + menu_item( + fl!("select-all"), + Some(icons::get_handle("edit-select-all-symbolic", 14)), + Action::SelectAll, + ) + .into(), + ); } if !children.is_empty() { children.push(divider::horizontal::light().into()); } - children.push(sort_item(fl!("sort-by-name"), HeadingOptions::Name)); - children.push(sort_item(fl!("sort-by-modified"), HeadingOptions::Modified)); - children.push(sort_item(fl!("sort-by-size"), HeadingOptions::Size)); + children.push(sort_item(fl!("sort-by-name"), None, HeadingOptions::Name)); + children.push(sort_item( + fl!("sort-by-modified"), + None, + HeadingOptions::Modified, + )); + children.push(sort_item(fl!("sort-by-size"), None, HeadingOptions::Size)); } } (_, Location::Trash) => { if tab.mode.multiple() { - children.push(menu_item(fl!("select-all"), Action::SelectAll).into()); + children.push( + menu_item( + fl!("select-all"), + Some(icons::get_handle("edit-select-all-symbolic", 14)), + Action::SelectAll, + ) + .into(), + ); } if !children.is_empty() { children.push(divider::horizontal::light().into()); } if selected > 0 { - children.push(menu_item(fl!("show-details"), Action::Preview).into()); + children.push( + menu_item( + fl!("show-details"), + Some(icons::get_handle("info-outline-symbolic", 14)), + Action::Preview, + ) + .into(), + ); children.push(divider::horizontal::light().into()); - children - .push(menu_item(fl!("restore-from-trash"), Action::RestoreFromTrash).into()); + children.push( + menu_item( + fl!("restore-from-trash"), + Some(icons::get_handle("empty-trash-bin-symbolic", 14)), + Action::RestoreFromTrash, + ) + .into(), + ); } else { // TODO: Nested menu - children.push(sort_item(fl!("sort-by-name"), HeadingOptions::Name)); - children.push(sort_item(fl!("sort-by-trashed"), HeadingOptions::TrashedOn)); - children.push(sort_item(fl!("sort-by-size"), HeadingOptions::Size)); + children.push(sort_item(fl!("sort-by-name"), None, HeadingOptions::Name)); + children.push(sort_item( + fl!("sort-by-trashed"), + None, + HeadingOptions::TrashedOn, + )); + children.push(sort_item(fl!("sort-by-size"), None, HeadingOptions::Size)); } } } @@ -351,6 +645,7 @@ pub fn dialog_menu<'a>( let sort_item = |label, sort, dir| { menu::Item::CheckBox( label, + None, sort_name == sort && sort_direction == dir, Action::SetSort(sort, dir), ) @@ -382,11 +677,13 @@ pub fn dialog_menu<'a>( vec![ menu::Item::CheckBox( fl!("grid-view"), + Some(icons::get_handle("grid-symbolic", 14)), matches!(tab.config.view, tab::View::Grid), Action::TabViewGrid, ), menu::Item::CheckBox( fl!("list-view"), + Some(icons::get_handle("list-large-symbolic", 14)), matches!(tab.config.view, tab::View::List), Action::TabViewList, ), @@ -447,24 +744,44 @@ pub fn dialog_menu<'a>( menu::items( key_binds, vec![ - menu::Item::Button(fl!("zoom-in"), Action::ZoomIn), - menu::Item::Button(fl!("default-size"), Action::ZoomDefault), - menu::Item::Button(fl!("zoom-out"), Action::ZoomOut), + menu::Item::Button( + fl!("zoom-in"), + Some(icons::get_handle("value-increase-symbolic", 14)), + Action::ZoomIn, + ), + menu::Item::Button( + fl!("default-size"), + Some(icons::get_handle("loupe-symbolic", 14)), + Action::ZoomDefault, + ), + menu::Item::Button( + fl!("zoom-out"), + Some(icons::get_handle("value-decrease-symbolic", 14)), + Action::ZoomOut, + ), menu::Item::Divider, menu::Item::CheckBox( fl!("show-hidden-files"), + Some(icons::get_handle("view-conceal-symbolic", 14)), tab.config.show_hidden, Action::ToggleShowHidden, ), menu::Item::CheckBox( fl!("list-directories-first"), + Some(icons::get_handle("folder-symbolic", 14)), tab.config.folders_first, Action::ToggleFoldersFirst, ), - menu::Item::CheckBox(fl!("show-details"), show_details, Action::Preview), + menu::Item::CheckBox( + fl!("show-details"), + Some(icons::get_handle("info-outline-symbolic", 14)), + show_details, + Action::Preview, + ), menu::Item::Divider, menu_button_optional( fl!("gallery-preview"), + Some(icons::get_handle("image-round-symbolic", 14)), Action::Gallery, selected_gallery > 0, ), @@ -487,6 +804,7 @@ pub fn menu_bar<'a>( let sort_item = |label, sort, dir| { menu::Item::CheckBox( label, + None, sort_options.map_or(false, |(sort_name, sort_direction, _)| { sort_name == sort && sort_direction == dir }), @@ -518,25 +836,70 @@ pub fn menu_bar<'a>( menu::items( key_binds, vec![ - menu::Item::Button(fl!("new-tab"), Action::TabNew), - menu::Item::Button(fl!("new-window"), Action::WindowNew), - menu::Item::Button(fl!("new-folder"), Action::NewFolder), - menu::Item::Button(fl!("new-file"), Action::NewFile), + menu::Item::Button( + fl!("new-tab"), + Some(icons::get_handle("tab-new-filled-symbolic", 14)), + Action::TabNew, + ), + menu::Item::Button( + fl!("new-window"), + Some(icons::get_handle("edit-copy-symbolic", 14)), + Action::WindowNew, + ), + menu::Item::Button( + fl!("new-folder"), + Some(icons::get_handle("folder-new-symbolic", 14)), + Action::NewFolder, + ), + menu::Item::Button( + fl!("new-file"), + Some(icons::get_handle("paper-symbolic", 14)), + Action::NewFile, + ), menu_button_optional( fl!("open"), + Some(icons::get_handle("document-open-symbolic", 14)), Action::Open, (selected > 0 && selected_dir == 0) || (selected_dir == 1 && selected == 1), ), - menu_button_optional(fl!("open-with"), Action::OpenWith, selected == 1), + menu_button_optional( + fl!("open-with"), + Some(icons::get_handle("external-link-symbolic", 14)), + Action::OpenWith, + selected == 1, + ), menu::Item::Divider, - menu_button_optional(fl!("rename"), Action::Rename, selected > 0), + menu_button_optional( + fl!("rename"), + Some(icons::get_handle("edit-symbolic", 14)), + Action::Rename, + selected > 0, + ), menu::Item::Divider, - menu_button_optional(fl!("add-to-sidebar"), Action::AddToSidebar, selected > 0), + menu_button_optional( + fl!("add-to-sidebar"), + Some(icons::get_handle("dock-left-symbolic", 14)), + Action::AddToSidebar, + selected > 0, + ), menu::Item::Divider, - menu_button_optional(fl!("move-to-trash"), Action::MoveToTrash, selected > 0), + menu_button_optional( + fl!("move-to-trash"), + Some(icons::get_handle("user-trash-symbolic", 14)), + Action::MoveToTrash, + selected > 0, + ), menu::Item::Divider, - menu::Item::Button(fl!("close-tab"), Action::TabClose), - menu::Item::Button(fl!("quit"), Action::WindowClose), + menu::Item::Button( + fl!("close-tab"), + Some(icons::get_handle("cross-small-square-filled-symbolic", 14)), + Action::TabClose, + ), + menu::Item::Button( + fl!("quit"), + Some(icons::get_handle("arrow-into-box-symbolic", 14)), + Action::WindowClose, + ), ], ), ), @@ -545,12 +908,35 @@ pub fn menu_bar<'a>( menu::items( key_binds, vec![ - menu_button_optional(fl!("cut"), Action::Cut, selected > 0), - menu_button_optional(fl!("copy"), Action::Copy, selected > 0), - menu_button_optional(fl!("paste"), Action::Paste, selected > 0), - menu::Item::Button(fl!("select-all"), Action::SelectAll), + menu_button_optional( + fl!("cut"), + Some(icons::get_handle("cut-symbolic", 14)), + Action::Cut, + selected > 0, + ), + menu_button_optional( + fl!("copy"), + Some(icons::get_handle("copy-symbolic", 14)), + Action::Copy, + selected > 0, + ), + menu_button_optional( + fl!("paste"), + Some(icons::get_handle("clipboard-symbolic", 14)), + Action::Paste, + selected > 0, + ), + menu::Item::Button( + fl!("select-all"), + Some(icons::get_handle("edit-select-all-symbolic", 14)), + Action::SelectAll, + ), menu::Item::Divider, - menu::Item::Button(fl!("history"), Action::EditHistory), + menu::Item::Button( + fl!("history"), + Some(icons::get_handle("history-undo-symbolic", 14)), + Action::EditHistory, + ), ], ), ), @@ -559,42 +945,72 @@ pub fn menu_bar<'a>( menu::items( key_binds, vec![ - menu::Item::Button(fl!("zoom-in"), Action::ZoomIn), - menu::Item::Button(fl!("default-size"), Action::ZoomDefault), - menu::Item::Button(fl!("zoom-out"), Action::ZoomOut), + menu::Item::Button( + fl!("zoom-in"), + Some(icons::get_handle("value-increase-symbolic", 14)), + Action::ZoomIn, + ), + menu::Item::Button( + fl!("default-size"), + Some(icons::get_handle("loupe-symbolic", 14)), + Action::ZoomDefault, + ), + menu::Item::Button( + fl!("zoom-out"), + Some(icons::get_handle("value-decrease-symbolic", 14)), + Action::ZoomOut, + ), menu::Item::Divider, menu::Item::CheckBox( fl!("grid-view"), + Some(icons::get_handle("grid-symbolic", 14)), tab_opt.map_or(false, |tab| matches!(tab.config.view, tab::View::Grid)), Action::TabViewGrid, ), menu::Item::CheckBox( fl!("list-view"), + Some(icons::get_handle("list-large-symbolic", 14)), tab_opt.map_or(false, |tab| matches!(tab.config.view, tab::View::List)), Action::TabViewList, ), menu::Item::Divider, menu::Item::CheckBox( fl!("show-hidden-files"), + Some(icons::get_handle("view-conceal-symbolic", 14)), tab_opt.map_or(false, |tab| tab.config.show_hidden), Action::ToggleShowHidden, ), menu::Item::CheckBox( fl!("list-directories-first"), + Some(icons::get_handle("folder-symbolic", 14)), tab_opt.map_or(false, |tab| tab.config.folders_first), Action::ToggleFoldersFirst, ), - menu::Item::CheckBox(fl!("show-details"), config.show_details, Action::Preview), + menu::Item::CheckBox( + fl!("show-details"), + Some(icons::get_handle("info-outline-symbolic", 14)), + config.show_details, + Action::Preview, + ), menu::Item::Divider, menu_button_optional( fl!("gallery-preview"), + Some(icons::get_handle("image-round-symbolic", 14)), Action::Gallery, selected_gallery > 0, ), menu::Item::Divider, - menu::Item::Button(fl!("menu-settings"), Action::Settings), + menu::Item::Button( + fl!("menu-settings"), + Some(icons::get_handle("settings-symbolic", 14)), + Action::Settings, + ), menu::Item::Divider, - menu::Item::Button(fl!("menu-about"), Action::About), + menu::Item::Button( + fl!("menu-about"), + Some(icons::get_handle("info-outline-symbolic", 14)), + Action::About, + ), ], ), ),