Implement view menu, fixes #184
This commit is contained in:
parent
e947bee833
commit
322dad2b8a
6 changed files with 114 additions and 10 deletions
|
|
@ -115,8 +115,13 @@ paste = Paste
|
||||||
select-all = Select all
|
select-all = Select all
|
||||||
|
|
||||||
## View
|
## View
|
||||||
|
zoom-in = Zoom in
|
||||||
|
default-size = Default size
|
||||||
|
zoom-out = Zoom out
|
||||||
view = View
|
view = View
|
||||||
grid-view = Grid view
|
grid-view = Grid view
|
||||||
list-view = List view
|
list-view = List view
|
||||||
|
show-hidden-files = Show hidden files
|
||||||
|
list-directories-first = List directories first
|
||||||
menu-settings = Settings...
|
menu-settings = Settings...
|
||||||
menu-about = About COSMIC Files...
|
menu-about = About COSMIC Files...
|
||||||
|
|
|
||||||
20
src/app.rs
20
src/app.rs
|
|
@ -93,10 +93,14 @@ pub enum Action {
|
||||||
TabPrev,
|
TabPrev,
|
||||||
TabViewGrid,
|
TabViewGrid,
|
||||||
TabViewList,
|
TabViewList,
|
||||||
|
ToggleFoldersFirst,
|
||||||
ToggleShowHidden,
|
ToggleShowHidden,
|
||||||
ToggleSort(HeadingOptions),
|
ToggleSort(HeadingOptions),
|
||||||
WindowClose,
|
WindowClose,
|
||||||
WindowNew,
|
WindowNew,
|
||||||
|
ZoomDefault,
|
||||||
|
ZoomIn,
|
||||||
|
ZoomOut,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Action {
|
impl Action {
|
||||||
|
|
@ -137,10 +141,20 @@ impl Action {
|
||||||
Action::TabViewList => {
|
Action::TabViewList => {
|
||||||
Message::TabMessage(entity_opt, tab::Message::View(tab::View::List))
|
Message::TabMessage(entity_opt, tab::Message::View(tab::View::List))
|
||||||
}
|
}
|
||||||
Action::ToggleShowHidden => Message::TabMessage(None, tab::Message::ToggleShowHidden),
|
Action::ToggleFoldersFirst => {
|
||||||
Action::ToggleSort(sort) => Message::TabMessage(None, tab::Message::ToggleSort(*sort)),
|
Message::TabMessage(entity_opt, tab::Message::ToggleFoldersFirst)
|
||||||
|
}
|
||||||
|
Action::ToggleShowHidden => {
|
||||||
|
Message::TabMessage(entity_opt, tab::Message::ToggleShowHidden)
|
||||||
|
}
|
||||||
|
Action::ToggleSort(sort) => {
|
||||||
|
Message::TabMessage(entity_opt, tab::Message::ToggleSort(*sort))
|
||||||
|
}
|
||||||
Action::WindowClose => Message::WindowClose,
|
Action::WindowClose => Message::WindowClose,
|
||||||
Action::WindowNew => Message::WindowNew,
|
Action::WindowNew => Message::WindowNew,
|
||||||
|
Action::ZoomDefault => Message::TabMessage(entity_opt, tab::Message::ZoomDefault),
|
||||||
|
Action::ZoomIn => Message::TabMessage(entity_opt, tab::Message::ZoomIn),
|
||||||
|
Action::ZoomOut => Message::TabMessage(entity_opt, tab::Message::ZoomOut),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1951,7 +1965,7 @@ impl Application for App {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn header_start(&self) -> Vec<Element<Self::Message>> {
|
fn header_start(&self) -> Vec<Element<Self::Message>> {
|
||||||
vec![menu::menu_bar(&self.key_binds).into()]
|
vec![menu::menu_bar(self.tab_model.active_data::<Tab>(), &self.key_binds).into()]
|
||||||
}
|
}
|
||||||
|
|
||||||
fn header_end(&self) -> Vec<Element<Self::Message>> {
|
fn header_end(&self) -> Vec<Element<Self::Message>> {
|
||||||
|
|
|
||||||
|
|
@ -111,6 +111,8 @@ impl Default for Config {
|
||||||
/// locally. Local changes aren't saved to the main config.
|
/// locally. Local changes aren't saved to the main config.
|
||||||
#[derive(Clone, Copy, Debug, Eq, PartialEq, CosmicConfigEntry, Deserialize, Serialize)]
|
#[derive(Clone, Copy, Debug, Eq, PartialEq, CosmicConfigEntry, Deserialize, Serialize)]
|
||||||
pub struct TabConfig {
|
pub struct TabConfig {
|
||||||
|
/// Show folders before files
|
||||||
|
pub folders_first: bool,
|
||||||
/// Show hidden files and folders
|
/// Show hidden files and folders
|
||||||
pub show_hidden: bool,
|
pub show_hidden: bool,
|
||||||
/// Sorter
|
/// Sorter
|
||||||
|
|
@ -123,6 +125,7 @@ pub struct TabConfig {
|
||||||
impl Default for TabConfig {
|
impl Default for TabConfig {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self {
|
Self {
|
||||||
|
folders_first: true,
|
||||||
show_hidden: false,
|
show_hidden: false,
|
||||||
sort_name: HeadingOptions::Name,
|
sort_name: HeadingOptions::Name,
|
||||||
sort_direction: true,
|
sort_direction: true,
|
||||||
|
|
|
||||||
|
|
@ -51,6 +51,9 @@ pub fn key_binds() -> HashMap<KeyBind, Action> {
|
||||||
bind!([Ctrl], Key::Character("h".into()), ToggleShowHidden);
|
bind!([Ctrl], Key::Character("h".into()), ToggleShowHidden);
|
||||||
bind!([Ctrl], Key::Character("q".into()), WindowClose);
|
bind!([Ctrl], Key::Character("q".into()), WindowClose);
|
||||||
bind!([Ctrl], Key::Character("n".into()), WindowNew);
|
bind!([Ctrl], Key::Character("n".into()), WindowNew);
|
||||||
|
bind!([Ctrl], Key::Character("=".into()), ZoomIn);
|
||||||
|
bind!([Ctrl], Key::Character("0".into()), ZoomDefault);
|
||||||
|
bind!([Ctrl], Key::Character("-".into()), ZoomOut);
|
||||||
|
|
||||||
key_binds
|
key_binds
|
||||||
}
|
}
|
||||||
|
|
|
||||||
32
src/menu.rs
32
src/menu.rs
|
|
@ -169,7 +169,10 @@ pub fn context_menu<'a>(
|
||||||
.into()
|
.into()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn menu_bar<'a>(key_binds: &HashMap<KeyBind, Action>) -> Element<'a, Message> {
|
pub fn menu_bar<'a>(
|
||||||
|
tab_opt: Option<&Tab>,
|
||||||
|
key_binds: &HashMap<KeyBind, Action>,
|
||||||
|
) -> Element<'a, Message> {
|
||||||
MenuBar::new(vec![
|
MenuBar::new(vec![
|
||||||
menu::Tree::with_children(
|
menu::Tree::with_children(
|
||||||
menu::root(fl!("file")),
|
menu::root(fl!("file")),
|
||||||
|
|
@ -212,8 +215,31 @@ pub fn menu_bar<'a>(key_binds: &HashMap<KeyBind, Action>) -> Element<'a, Message
|
||||||
menu::items(
|
menu::items(
|
||||||
key_binds,
|
key_binds,
|
||||||
vec![
|
vec![
|
||||||
menu::Item::Button(fl!("grid-view"), Action::TabViewGrid),
|
menu::Item::Button(fl!("zoom-in"), Action::ZoomIn),
|
||||||
menu::Item::Button(fl!("list-view"), Action::TabViewList),
|
menu::Item::Button(fl!("default-size"), Action::ZoomDefault),
|
||||||
|
menu::Item::Button(fl!("zoom-out"), Action::ZoomOut),
|
||||||
|
menu::Item::Divider,
|
||||||
|
menu::Item::CheckBox(
|
||||||
|
fl!("grid-view"),
|
||||||
|
tab_opt.map_or(false, |tab| matches!(tab.view, tab::View::Grid)),
|
||||||
|
Action::TabViewGrid,
|
||||||
|
),
|
||||||
|
menu::Item::CheckBox(
|
||||||
|
fl!("list-view"),
|
||||||
|
tab_opt.map_or(false, |tab| matches!(tab.view, tab::View::List)),
|
||||||
|
Action::TabViewList,
|
||||||
|
),
|
||||||
|
menu::Item::Divider,
|
||||||
|
menu::Item::CheckBox(
|
||||||
|
fl!("show-hidden-files"),
|
||||||
|
tab_opt.map_or(false, |tab| tab.config.show_hidden),
|
||||||
|
Action::ToggleShowHidden,
|
||||||
|
),
|
||||||
|
menu::Item::CheckBox(
|
||||||
|
fl!("list-directories-first"),
|
||||||
|
tab_opt.map_or(false, |tab| tab.config.folders_first),
|
||||||
|
Action::ToggleFoldersFirst,
|
||||||
|
),
|
||||||
menu::Item::Divider,
|
menu::Item::Divider,
|
||||||
menu::Item::Button(fl!("menu-settings"), Action::Settings),
|
menu::Item::Button(fl!("menu-settings"), Action::Settings),
|
||||||
menu::Item::Divider,
|
menu::Item::Divider,
|
||||||
|
|
|
||||||
61
src/tab.rs
61
src/tab.rs
|
|
@ -36,6 +36,7 @@ use std::{
|
||||||
collections::HashMap,
|
collections::HashMap,
|
||||||
fmt,
|
fmt,
|
||||||
fs::{self, Metadata},
|
fs::{self, Metadata},
|
||||||
|
num::NonZeroU16,
|
||||||
path::PathBuf,
|
path::PathBuf,
|
||||||
time::{Duration, Instant},
|
time::{Duration, Instant},
|
||||||
};
|
};
|
||||||
|
|
@ -465,6 +466,7 @@ pub enum Message {
|
||||||
Scroll(Viewport),
|
Scroll(Viewport),
|
||||||
SelectAll,
|
SelectAll,
|
||||||
Thumbnail(PathBuf, ItemThumbnail),
|
Thumbnail(PathBuf, ItemThumbnail),
|
||||||
|
ToggleFoldersFirst,
|
||||||
ToggleShowHidden,
|
ToggleShowHidden,
|
||||||
View(View),
|
View(View),
|
||||||
ToggleSort(HeadingOptions),
|
ToggleSort(HeadingOptions),
|
||||||
|
|
@ -472,6 +474,9 @@ pub enum Message {
|
||||||
DndHover(Location),
|
DndHover(Location),
|
||||||
DndEnter(Location),
|
DndEnter(Location),
|
||||||
DndLeave(Location),
|
DndLeave(Location),
|
||||||
|
ZoomDefault,
|
||||||
|
ZoomIn,
|
||||||
|
ZoomOut,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
|
|
@ -1394,6 +1399,7 @@ impl Tab {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Message::ToggleFoldersFirst => self.config.folders_first = !self.config.folders_first,
|
||||||
Message::ToggleShowHidden => self.config.show_hidden = !self.config.show_hidden,
|
Message::ToggleShowHidden => self.config.show_hidden = !self.config.show_hidden,
|
||||||
|
|
||||||
Message::View(view) => {
|
Message::View(view) => {
|
||||||
|
|
@ -1453,6 +1459,48 @@ impl Tab {
|
||||||
self.dnd_hovered = None;
|
self.dnd_hovered = None;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Message::ZoomDefault => match self.view {
|
||||||
|
View::List => self.config.icon_sizes.list = 100.try_into().unwrap(),
|
||||||
|
View::Grid => self.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.view {
|
||||||
|
View::List => zoom_in(&mut self.config.icon_sizes.list, 100, 500),
|
||||||
|
View::Grid => zoom_in(&mut self.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.view {
|
||||||
|
View::List => zoom_out(&mut self.config.icon_sizes.list, 100, 500),
|
||||||
|
View::Grid => zoom_out(&mut self.config.icon_sizes.grid, 50, 500),
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if let Some(location) = cd {
|
if let Some(location) = cd {
|
||||||
if location != self.location {
|
if location != self.location {
|
||||||
|
|
@ -1509,10 +1557,14 @@ impl Tab {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
HeadingOptions::Name => items.sort_by(|a, b| {
|
HeadingOptions::Name => items.sort_by(|a, b| {
|
||||||
let ord = match (a.1.metadata.is_dir(), b.1.metadata.is_dir()) {
|
let ord = if self.config.folders_first {
|
||||||
(true, false) => Ordering::Less,
|
match (a.1.metadata.is_dir(), b.1.metadata.is_dir()) {
|
||||||
(false, true) => Ordering::Greater,
|
(true, false) => Ordering::Less,
|
||||||
_ => lexical_sort::natural_lexical_cmp(&a.1.name, &b.1.name),
|
(false, true) => Ordering::Greater,
|
||||||
|
_ => lexical_sort::natural_lexical_cmp(&a.1.name, &b.1.name),
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
lexical_sort::natural_lexical_cmp(&a.1.name, &b.1.name)
|
||||||
};
|
};
|
||||||
check_reverse(ord, heading_sort)
|
check_reverse(ord, heading_sort)
|
||||||
}),
|
}),
|
||||||
|
|
@ -1993,6 +2045,7 @@ impl Tab {
|
||||||
icon_sizes,
|
icon_sizes,
|
||||||
sort_name,
|
sort_name,
|
||||||
sort_direction,
|
sort_direction,
|
||||||
|
..
|
||||||
} = self.config;
|
} = self.config;
|
||||||
|
|
||||||
let size = self.size_opt.unwrap_or_else(|| Size::new(0.0, 0.0));
|
let size = self.size_opt.unwrap_or_else(|| Size::new(0.0, 0.0));
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue