From a5dfffcd7221438196e01e9ef418374605bb36af Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Thu, 10 Oct 2024 13:27:50 -0600 Subject: [PATCH] Add view menu for dialog, part of #541 --- src/dialog.rs | 66 ++++++++++++++++++++++++++++++++++++++++- src/menu.rs | 82 +++++++++++++++++++++++++++++++++++++++++++-------- 2 files changed, 134 insertions(+), 14 deletions(-) diff --git a/src/dialog.rs b/src/dialog.rs index 5971da4..d820a77 100644 --- a/src/dialog.rs +++ b/src/dialog.rs @@ -33,6 +33,7 @@ use std::{ any::TypeId, collections::{HashMap, HashSet, VecDeque}, env, fmt, fs, + num::NonZeroU16, path::PathBuf, str::FromStr, time::{self, Instant}, @@ -325,14 +326,25 @@ enum Message { SearchInput(String), TabMessage(tab::Message), TabRescan(Vec), + TabView(tab::View), + ToggleFoldersFirst, + ZoomDefault, + ZoomIn, + ZoomOut, } impl From for Message { fn from(app_message: AppMessage) -> Message { match app_message { + AppMessage::None => Message::None, AppMessage::Preview(_entity_opt) => Message::Preview, AppMessage::SearchActivate => Message::SearchActivate, AppMessage::TabMessage(_entity_opt, tab_message) => Message::TabMessage(tab_message), + AppMessage::TabView(_entity_opt, view) => Message::TabView(view), + AppMessage::ToggleFoldersFirst => Message::ToggleFoldersFirst, + AppMessage::ZoomDefault(_entity_opt) => Message::ZoomDefault, + AppMessage::ZoomIn(_entity_opt) => Message::ZoomIn, + AppMessage::ZoomOut(_entity_opt) => Message::ZoomOut, unsupported => { log::warn!("{unsupported:?} not supported in dialog mode"); Message::None @@ -933,8 +945,12 @@ impl Application for App { ); } + let show_details = match self.context_page { + ContextPage::Preview(..) => self.core.window.show_context, + _ => false, + }; elements.push( - menu::dialog_menu(&self.tab, &self.key_binds) + menu::dialog_menu(&self.tab, &self.key_binds, show_details) .map(Message::from) .into(), ); @@ -1462,6 +1478,54 @@ impl Application for App { return widget::text_input::focus(self.filename_id.clone()); } } + Message::TabView(view) => { + self.tab.config.view = view; + } + Message::ToggleFoldersFirst => { + self.tab.config.folders_first = !self.tab.config.folders_first; + } + Message::ZoomDefault => match self.tab.config.view { + tab::View::List => self.tab.config.icon_sizes.list = 100.try_into().unwrap(), + tab::View::Grid => self.tab.config.icon_sizes.grid = 100.try_into().unwrap(), + }, + Message::ZoomIn => { + let zoom_in = |size: &mut NonZeroU16, min: u16, max: u16| { + let mut step = min; + while step <= max { + if size.get() < step { + *size = step.try_into().unwrap(); + break; + } + step += 25; + } + if size.get() > step { + *size = step.try_into().unwrap(); + } + }; + match self.tab.config.view { + tab::View::List => zoom_in(&mut self.tab.config.icon_sizes.list, 50, 500), + tab::View::Grid => zoom_in(&mut self.tab.config.icon_sizes.grid, 50, 500), + } + } + Message::ZoomOut => { + let zoom_out = |size: &mut NonZeroU16, min: u16, max: u16| { + let mut step = max; + while step >= min { + if size.get() > step { + *size = step.try_into().unwrap(); + break; + } + step -= 25; + } + if size.get() < step { + *size = step.try_into().unwrap(); + } + }; + match self.tab.config.view { + tab::View::List => zoom_out(&mut self.tab.config.icon_sizes.list, 50, 500), + tab::View::Grid => zoom_out(&mut self.tab.config.icon_sizes.grid, 50, 500), + } + } } Command::none() diff --git a/src/menu.rs b/src/menu.rs index 0e18385..9160dfe 100644 --- a/src/menu.rs +++ b/src/menu.rs @@ -35,6 +35,18 @@ macro_rules! menu_button { ); } +fn menu_button_optional( + label: String, + action: Action, + enabled: bool, +) -> menu::Item { + if enabled { + menu::Item::Button(label, action) + } else { + menu::Item::ButtonDisabled(label, action) + } +} + pub fn context_menu<'a>( tab: &Tab, key_binds: &HashMap, @@ -291,6 +303,7 @@ pub fn context_menu<'a>( pub fn dialog_menu<'a>( tab: &Tab, key_binds: &HashMap, + show_details: bool, ) -> Element<'static, Message> { let (sort_name, sort_direction, _) = tab.sort_options(); let sort_item = |label, sort, dir| { @@ -302,12 +315,25 @@ pub fn dialog_menu<'a>( }; let in_trash = tab.location == Location::Trash; + let mut selected_gallery = 0; + tab.items_opt().map(|items| { + for item in items.iter() { + if item.selected { + if item.can_gallery() { + selected_gallery += 1; + } + } + } + }); + MenuBar::new(vec![ menu::Tree::with_children( widget::button::icon(widget::icon::from_name(match tab.config.view { tab::View::Grid => "view-grid-symbolic", tab::View::List => "view-list-symbolic", })) + // This prevents the button from being shown as insensitive + .on_press(Message::None) .padding(8), menu::items( key_binds, @@ -331,6 +357,8 @@ pub fn dialog_menu<'a>( } else { "view-sort-descending-symbolic" })) + // This prevents the button from being shown as insensitive + .on_press(Message::None) .padding(8), menu::items( key_binds, @@ -369,6 +397,38 @@ pub fn dialog_menu<'a>( ], ), ), + menu::Tree::with_children( + widget::button::icon(widget::icon::from_name("view-more-symbolic")) + // This prevents the button from being shown as insensitive + .on_press(Message::None) + .padding(8), + 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::Divider, + menu::Item::CheckBox( + fl!("show-hidden-files"), + tab.config.show_hidden, + Action::ToggleShowHidden, + ), + menu::Item::CheckBox( + fl!("list-directories-first"), + tab.config.folders_first, + Action::ToggleFoldersFirst, + ), + menu::Item::CheckBox(fl!("show-details"), show_details, Action::Preview), + menu::Item::Divider, + menu_button_optional( + fl!("gallery-preview"), + Action::Gallery, + selected_gallery > 0, + ), + ], + ), + ), ]) .item_height(ItemHeight::Dynamic(40)) .item_width(ItemWidth::Uniform(240)) @@ -395,6 +455,7 @@ pub fn menu_bar<'a>( let mut selected_dir = 0; let mut selected = 0; + let mut selected_gallery = 0; tab_opt.and_then(|tab| tab.items_opt()).map(|items| { for item in items.iter() { if item.selected { @@ -402,22 +463,13 @@ pub fn menu_bar<'a>( if item.metadata.is_dir() { selected_dir += 1; } + if item.can_gallery() { + selected_gallery += 1; + } } } }); - fn menu_button_optional( - label: String, - action: Action, - enabled: bool, - ) -> menu::Item { - if enabled { - menu::Item::Button(label, action) - } else { - menu::Item::ButtonDisabled(label, action) - } - } - MenuBar::new(vec![ menu::Tree::with_children( menu::root(fl!("file")), @@ -492,7 +544,11 @@ pub fn menu_bar<'a>( ), menu::Item::CheckBox(fl!("show-details"), config.show_details, Action::Preview), menu::Item::Divider, - menu_button_optional(fl!("gallery-preview"), Action::Gallery, selected > 0), + menu_button_optional( + fl!("gallery-preview"), + Action::Gallery, + selected_gallery > 0, + ), menu::Item::Divider, menu::Item::Button(fl!("menu-settings"), Action::Settings), menu::Item::Divider,