From 4b8eee7bd3a29230269f4d2fb9d1febcfba8b19a Mon Sep 17 00:00:00 2001 From: Dominic Gerhauser Date: Fri, 1 Mar 2024 08:48:19 +0100 Subject: [PATCH 1/5] visible columns --- i18n/en/cosmic_files.ftl | 7 ++ src/app.rs | 104 ++++++++++++++++-- src/config.rs | 26 ++++- src/menu.rs | 2 + src/tab.rs | 226 +++++++++++++++++++++++++++------------ 5 files changed, 291 insertions(+), 74 deletions(-) diff --git a/i18n/en/cosmic_files.ftl b/i18n/en/cosmic_files.ftl index 8c2b7ac6..8d7351a1 100644 --- a/i18n/en/cosmic_files.ftl +++ b/i18n/en/cosmic_files.ftl @@ -38,6 +38,8 @@ replace-warning = Do you want to replace it with the one you are saving? Replaci # List view name = Name modified = Modified +accessed = Accessed +created = Created size = Size # Context Pages @@ -97,3 +99,8 @@ grid-view = Grid view list-view = List view menu-settings = Settings... menu-about = About COSMIC Files... + +## Visible columns +visible-columns = Visible columns +move-up = Move up +move-down = Move down \ No newline at end of file diff --git a/src/app.rs b/src/app.rs index da2e334d..30f31f78 100644 --- a/src/app.rs +++ b/src/app.rs @@ -3,7 +3,9 @@ use cosmic::{ app::{message, Command, Core}, - cosmic_config, cosmic_theme, executor, + cosmic_config, + cosmic_theme::{self, Spacing}, + executor, iced::{ event, futures::{self, SinkExt}, @@ -12,6 +14,7 @@ use cosmic::{ widget::scrollable, window, Alignment, Event, Length, }, + iced_widget::horizontal_rule, style, theme, widget::{self, segmented_button}, Application, ApplicationExt, Element, @@ -27,12 +30,12 @@ use std::{ }; use crate::{ - config::{AppTheme, Config, IconSizes, TabConfig, CONFIG_VERSION}, + config::{AppTheme, Config, IconSizes, TabConfig, VisibleColumns, CONFIG_VERSION}, fl, home_dir, key_bind::{key_binds, KeyBind}, menu, operation::Operation, - tab::{self, ItemMetadata, Location, Tab}, + tab::{self, HeadingOptions, ItemMetadata, Location, Tab}, }; #[derive(Clone, Debug)] @@ -74,6 +77,7 @@ pub enum Action { ToggleShowHidden, WindowClose, WindowNew, + VisibleColumns, } impl Action { @@ -114,6 +118,7 @@ impl Action { Action::ToggleShowHidden => Message::TabMessage(None, tab::Message::ToggleShowHidden), Action::WindowClose => Message::WindowClose, Action::WindowNew => Message::WindowNew, + Action::VisibleColumns => Message::ToggleContextPage(ContextPage::VisibleColumns), } } } @@ -124,6 +129,7 @@ pub enum Message { AppTheme(AppTheme), Config(Config), Copy(Option), + ChangeVisibleColumnPopover(bool, HeadingOptions), Cut(Option), DialogCancel, DialogComplete, @@ -162,6 +168,7 @@ pub enum ContextPage { Operations, Properties, Settings, + VisibleColumns, } impl ContextPage { @@ -171,6 +178,7 @@ impl ContextPage { Self::Operations => fl!("operations"), Self::Properties => fl!("properties"), Self::Settings => fl!("settings"), + Self::VisibleColumns => fl!("visible-columns"), } } } @@ -226,6 +234,7 @@ pub struct App { complete_operations: BTreeMap, failed_operations: BTreeMap, watcher_opt: Option<(notify::RecommendedWatcher, HashSet)>, + visible_column_move_selected: Option, } impl App { @@ -477,7 +486,7 @@ impl App { list: NonZeroU16::new(list).unwrap(), ..tab_config.icon_sizes }, - ..tab_config + ..tab_config.clone() }) }) .step(25u16) @@ -496,7 +505,7 @@ impl App { grid: NonZeroU16::new(grid).unwrap(), ..tab_config.icon_sizes }, - ..tab_config + ..tab_config.clone() }) }) .step(25u16) @@ -512,7 +521,7 @@ impl App { move |show_hidden| { Message::TabConfig(TabConfig { show_hidden, - ..tab_config + ..tab_config.clone() }) }, ) @@ -521,6 +530,84 @@ impl App { ]) .into() } + fn visible_columns(&self) -> Element { + let column_options = &self.config.tab.visible_columns; + let Spacing { space_xxs, .. } = self.core.system_theme().cosmic().spacing; + let column_item = |col: VisibleColumns, idx: usize| -> Element { + let is_selected = self + .visible_column_move_selected + .is_some_and(|c| c == col.heading); + let mut popover = widget::popover( + widget::button(widget::icon::from_name("open-menu-symbolic")) + .on_press(Message::ChangeVisibleColumnPopover( + !is_selected, + col.heading, + )) + .style(cosmic::style::Button::Icon), + ); + + let move_item = |mut config: TabConfig, direction: bool| { + if direction && idx < config.visible_columns.len() - 1 { + config.visible_columns.swap(idx, idx + 1) + } else if !direction && idx != 0 { + config.visible_columns.swap(idx, idx - 1) + } + config + }; + + if is_selected { + popover = popover + .popup( + widget::container( + widget::column::with_children(vec![ + widget::button(widget::text(fl!("move-up"))) + .on_press(Message::TabConfig(move_item( + self.config.tab.clone(), + false, + ))) + .padding(space_xxs) + .style(theme::Button::Text) + .into(), + horizontal_rule(1).into(), + widget::button(widget::text(fl!("move-down"))) + .on_press(Message::TabConfig(move_item( + self.config.tab.clone(), + true, + ))) + .padding(space_xxs) + .style(theme::Button::Text) + .into(), + ]) + .width(Length::Shrink), + ) + .style(theme::Container::Background), + ) + .position(widget::popover::Position::Bottom) + .into() + } + + widget::settings::item::builder(col.heading.to_string()) + .control( + widget::row::with_children(vec![ + widget::toggler(None, col.active, move |t| { + let mut config = self.config.tab.clone(); + config.visible_columns[idx].active = t; + Message::TabConfig(config) + }) + .into(), + popover.into(), + ]) + .align_items(Alignment::Center), + ) + .into() + }; + + let mut view_section = widget::settings::view_section(""); + for (idx, col) in column_options.iter().enumerate() { + view_section = view_section.add(column_item(col.clone(), idx)); + } + widget::settings::view_column(vec![view_section.into()]).into() + } } /// Implement [`Application`] to integrate with COSMIC. @@ -601,6 +688,7 @@ impl Application for App { complete_operations: BTreeMap::new(), failed_operations: BTreeMap::new(), watcher_opt: None, + visible_column_move_selected: None, }; let mut commands = Vec::new(); @@ -735,6 +823,9 @@ impl Application for App { Message::Copy(_entity_opt) => { log::warn!("TODO: COPY"); } + Message::ChangeVisibleColumnPopover(active, column) => { + self.visible_column_move_selected = active.then_some(column); + } Message::Cut(_entity_opt) => { log::warn!("TODO: CUT"); } @@ -1129,6 +1220,7 @@ impl Application for App { ContextPage::Operations => self.operations(), ContextPage::Properties => self.properties(), ContextPage::Settings => self.settings(), + ContextPage::VisibleColumns => self.visible_columns(), }) } diff --git a/src/config.rs b/src/config.rs index 1087f700..c9019a19 100644 --- a/src/config.rs +++ b/src/config.rs @@ -8,6 +8,8 @@ use cosmic::{ }; use serde::{Deserialize, Serialize}; +use crate::tab::HeadingOptions; + pub const CONFIG_VERSION: u64 = 1; // Default icon sizes @@ -54,7 +56,7 @@ impl Default for Config { /// [`TabConfig`] contains options that are passed to each instance of [`crate::tab::Tab`]. /// These options are set globally through the main config, but each tab may change options /// locally. Local changes aren't saved to the main config. -#[derive(Clone, Copy, Debug, Eq, PartialEq, CosmicConfigEntry, Deserialize, Serialize)] +#[derive(Clone, Debug, Eq, PartialEq, CosmicConfigEntry, Deserialize, Serialize)] pub struct TabConfig { /// Show hidden files and folders pub show_hidden: bool, @@ -62,6 +64,7 @@ pub struct TabConfig { // pub sort_by: fn(&PathBuf, &PathBuf) -> Ordering, // Icon zoom pub icon_sizes: IconSizes, + pub visible_columns: Vec, } impl Default for TabConfig { @@ -69,6 +72,7 @@ impl Default for TabConfig { Self { show_hidden: false, icon_sizes: IconSizes::default(), + visible_columns: VisibleColumns::default(), } } } @@ -94,6 +98,26 @@ impl Default for IconSizes { } } +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq)] +pub struct VisibleColumns { + pub active: bool, + pub heading: HeadingOptions, +} +impl VisibleColumns { + pub fn new(active: bool, heading: HeadingOptions) -> Self { + Self { active, heading } + } + fn default() -> Vec { + vec![ + VisibleColumns::new(true, HeadingOptions::Name), + VisibleColumns::new(true, HeadingOptions::Modified), + VisibleColumns::new(false, HeadingOptions::Accessed), + VisibleColumns::new(false, HeadingOptions::Created), + VisibleColumns::new(true, HeadingOptions::Size), + ] + } +} + impl IconSizes { pub fn list(&self) -> u16 { percent!(self.list, ICON_SIZE_LIST) as _ diff --git a/src/menu.rs b/src/menu.rs index e71fddc8..02b410f2 100644 --- a/src/menu.rs +++ b/src/menu.rs @@ -190,6 +190,8 @@ pub fn menu_bar<'a>(key_binds: &HashMap) -> Element<'a, Message MenuTree::new(horizontal_rule(1)), menu_item(fl!("menu-settings"), Action::Settings), MenuTree::new(horizontal_rule(1)), + menu_item(fl!("visible-columns"), Action::VisibleColumns), + MenuTree::new(horizontal_rule(1)), menu_item(fl!("menu-about"), Action::About), ], ), diff --git a/src/tab.rs b/src/tab.rs index eebf8f82..4e865484 100644 --- a/src/tab.rs +++ b/src/tab.rs @@ -22,6 +22,7 @@ use cosmic::{ }; use mime_guess::MimeGuess; use once_cell::sync::Lazy; +use serde::{Deserialize, Serialize}; use std::{ cell::Cell, cmp::Ordering, @@ -566,12 +567,29 @@ pub enum View { Grid, List, } -#[derive(Clone, Copy, Debug, Hash, PartialEq, PartialOrd, Ord, Eq)] +#[derive(Clone, Copy, Debug, Hash, PartialEq, PartialOrd, Ord, Eq, Serialize, Deserialize)] pub enum HeadingOptions { Name, Modified, + Accessed, + Created, Size, } +impl fmt::Display for HeadingOptions { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!( + f, + "{}", + match self { + HeadingOptions::Name => fl!("name"), + HeadingOptions::Modified => fl!("modified"), + HeadingOptions::Size => fl!("size"), + HeadingOptions::Accessed => fl!("accessed"), + HeadingOptions::Created => fl!("created"), + } + ) + } +} #[derive(Clone, Debug)] pub struct Tab { @@ -1197,6 +1215,20 @@ impl Tab { }; let mut items: Vec<_> = self.items_opt.as_ref()?.iter().enumerate().collect(); let heading_sort = self.sort_direction; + macro_rules! date_sort { + ($name: ident) => { + items.sort_by(|a, b| { + let get_field = |x: &Item| match &x.metadata { + ItemMetadata::Path { metadata, .. } => metadata.$name().ok(), + ItemMetadata::Trash { .. } => None, + }; + let a = get_field(a.1); + let b = get_field(b.1); + check_reverse(a.cmp(&b), heading_sort) + }) + }; + } + match self.sort_name { HeadingOptions::Size => { items.sort_by(|a, b| { @@ -1234,16 +1266,13 @@ impl Tab { check_reverse(ord, heading_sort) }), HeadingOptions::Modified => { - items.sort_by(|a, b| { - let get_modified = |x: &Item| match &x.metadata { - ItemMetadata::Path { metadata, .. } => metadata.modified().ok(), - ItemMetadata::Trash { .. } => None, - }; - - let a = get_modified(a.1); - let b = get_modified(b.1); - check_reverse(a.cmp(&b), heading_sort) - }); + date_sort!(modified); + } + HeadingOptions::Accessed => { + date_sort!(accessed) + } + HeadingOptions::Created => { + date_sort!(created) } } Some(items) @@ -1431,6 +1460,7 @@ impl Tab { let TabConfig { show_hidden, icon_sizes, + .. } = self.config; let text_height = 40; // Height of two lines of text @@ -1576,7 +1606,8 @@ impl Tab { let TabConfig { show_hidden, icon_sizes, - } = self.config; + visible_columns, + } = &self.config; let size = self.size_opt.unwrap_or_else(|| Size::new(0.0, 0.0)); //TODO: allow resizing? @@ -1613,24 +1644,38 @@ impl Tab { }; let mut children: Vec> = Vec::new(); + + let get_column_width = |col: HeadingOptions| match col { + HeadingOptions::Name => Length::Fill, + HeadingOptions::Modified => Length::Fixed(modified_width), + HeadingOptions::Size | HeadingOptions::Accessed | HeadingOptions::Created => { + Length::Fixed(size_width) + } + }; + + let heading = self + .config + .visible_columns + .iter() + .filter(|col| col.active) + .map(|col| { + heading_item( + col.heading.to_string(), + get_column_width(col.heading), + col.heading, + ) + }) + .collect(); + let mut y = 0; if !condensed { children.push( - widget::row::with_children(vec![ - heading_item(fl!("name"), Length::Fill, HeadingOptions::Name), - //TODO: do not show modified column when in the trash - heading_item( - fl!("modified"), - Length::Fixed(modified_width), - HeadingOptions::Modified, - ), - heading_item(fl!("size"), Length::Fixed(size_width), HeadingOptions::Size), - ]) - .align_items(Alignment::Center) - .height(Length::Fixed(row_height as f32)) - .padding(space_xxs) - .spacing(space_xxs) - .into(), + widget::row::with_children(heading) + .align_items(Alignment::Center) + .height(Length::Fixed(row_height as f32)) + .padding(space_xxs) + .spacing(space_xxs) + .into(), ); y += row_height; children.push(horizontal_rule(1).into()); @@ -1658,7 +1703,21 @@ impl Tab { y += 1; } - let modified_text = match &item.metadata { + macro_rules! date_format { + ($name: ident) => { + match &item.metadata { + ItemMetadata::Path { metadata, .. } => match metadata.$name() { + Ok(time) => chrono::DateTime::::from(time) + .format(TIME_FORMAT) + .to_string(), + Err(_) => String::new(), + }, + ItemMetadata::Trash { .. } => String::new(), + } + }; + } + + let date_format = match &item.metadata { ItemMetadata::Path { metadata, .. } => match metadata.modified() { Ok(time) => chrono::DateTime::::from(time) .format(TIME_FORMAT) @@ -1668,7 +1727,7 @@ impl Tab { ItemMetadata::Trash { .. } => String::new(), }; - let size_text = match &item.metadata { + let size_text = || match &item.metadata { ItemMetadata::Path { metadata, children } => { if metadata.is_dir() { format!("{} items", children) @@ -1688,47 +1747,80 @@ impl Tab { trash::TrashItemSize::Bytes(bytes) => format_size(bytes), }, }; + let column_text = |col: HeadingOptions| match col { + HeadingOptions::Name => item.name.clone(), - let row = if condensed { - widget::row::with_children(vec![ - widget::icon::icon(item.icon_handle_list_condensed.clone()) - .content_fit(ContentFit::Contain) - .size(icon_size) - .into(), - widget::column::with_children(vec![ - widget::text(item.name.clone()).into(), - //TODO: translate? - widget::text(format!("{} - {}", modified_text, size_text)).into(), - ]) - .into(), - ]) - .align_items(Alignment::Center) - .spacing(space_xxs) - } else { - widget::row::with_children(vec![ - widget::icon::icon(item.icon_handle_list.clone()) - .content_fit(ContentFit::Contain) - .size(icon_size) - .into(), - widget::text(item.name.clone()).width(Length::Fill).into(), - widget::text(modified_text) - .width(Length::Fixed(modified_width)) - .into(), - widget::text(size_text) - .width(Length::Fixed(size_width)) - .into(), - ]) - .align_items(Alignment::Center) - .spacing(space_xxs) + HeadingOptions::Size => size_text(), + HeadingOptions::Modified => date_format!(modified), + HeadingOptions::Accessed => date_format!(accessed), + HeadingOptions::Created => date_format!(created), }; - let button = widget::button(row) - .width(Length::Fill) - .height(Length::Fixed(row_height as f32)) - .id(item.button_id.clone()) - .padding(space_xxs) - .style(button_style(item.selected, true)) - .on_press(Message::Click(Some(i))); + let mut columns = vec![widget::icon::icon(item.icon_handle_list.clone()) + .content_fit(ContentFit::Contain) + .size(icon_sizes.list()) + .into()]; + + let column_text = |col: HeadingOptions| match col { + HeadingOptions::Name => item.name.clone(), + + HeadingOptions::Size => size_text(), + HeadingOptions::Modified => date_format!(modified), + HeadingOptions::Accessed => date_format!(accessed), + HeadingOptions::Created => date_format!(created), + }; + + let columns_content = visible_columns.iter().filter(|col| col.active).map(|col| { + widget::text(column_text(col.heading)) + .width(get_column_width(col.heading)) + .into() + }); + columns.extend(columns_content); + + // let row = if condensed { + // widget::row::with_children(vec![ + // widget::icon::icon(item.icon_handle_list_condensed.clone()) + // .content_fit(ContentFit::Contain) + // .size(icon_size) + // .into(), + // widget::column::with_children(vec![ + // widget::text(item.name.clone()).into(), + // //TODO: translate? + // widget::text(format!("{} - {}", date_format, size_text())).into(), + // ]) + // .into(), + // ]) + // .align_items(Alignment::Center) + // .spacing(space_xxs) + // } else { + // widget::row::with_children(vec![ + // widget::icon::icon(item.icon_handle_list.clone()) + // .content_fit(ContentFit::Contain) + // .size(icon_size) + // .into(), + // widget::text(item.name.clone()).width(Length::Fill).into(), + // widget::text(date_format) + // .width(Length::Fixed(modified_width)) + // .into(), + // widget::text(size_text()) + // .width(Length::Fixed(size_width)) + // .into(), + // ]) + // .align_items(Alignment::Center) + // .spacing(space_xxs) + // }; + + let button = widget::button( + widget::row::with_children(columns) + .align_items(Alignment::Center) + .spacing(space_xxs), + ) + .width(Length::Fill) + .height(Length::Fixed(row_height as f32)) + .id(item.button_id.clone()) + .padding(space_xxs) + .style(button_style(item.selected, true)) + .on_press(Message::Click(Some(i))); if self.context_menu.is_some() { children.push(button.into()); } else { From 158f19dc1031654543236c9d8a04bb67e30ae862 Mon Sep 17 00:00:00 2001 From: Dominic Gerhauser Date: Fri, 1 Mar 2024 08:58:11 +0100 Subject: [PATCH 2/5] visible columns --- src/tab.rs | 18 ------------------ 1 file changed, 18 deletions(-) diff --git a/src/tab.rs b/src/tab.rs index 4e865484..b787280b 100644 --- a/src/tab.rs +++ b/src/tab.rs @@ -1717,16 +1717,6 @@ impl Tab { }; } - let date_format = match &item.metadata { - ItemMetadata::Path { metadata, .. } => match metadata.modified() { - Ok(time) => chrono::DateTime::::from(time) - .format(TIME_FORMAT) - .to_string(), - Err(_) => String::new(), - }, - ItemMetadata::Trash { .. } => String::new(), - }; - let size_text = || match &item.metadata { ItemMetadata::Path { metadata, children } => { if metadata.is_dir() { @@ -1747,14 +1737,6 @@ impl Tab { trash::TrashItemSize::Bytes(bytes) => format_size(bytes), }, }; - let column_text = |col: HeadingOptions| match col { - HeadingOptions::Name => item.name.clone(), - - HeadingOptions::Size => size_text(), - HeadingOptions::Modified => date_format!(modified), - HeadingOptions::Accessed => date_format!(accessed), - HeadingOptions::Created => date_format!(created), - }; let mut columns = vec![widget::icon::icon(item.icon_handle_list.clone()) .content_fit(ContentFit::Contain) From c8fc42d3e70fa125aafd85f7fe9d7c9bf6c814be Mon Sep 17 00:00:00 2001 From: Dominic Gerhauser Date: Fri, 1 Mar 2024 17:35:10 +0100 Subject: [PATCH 3/5] visible columns: add condensed view --- src/tab.rs | 54 ++++++++++++++++++++---------------------------------- 1 file changed, 20 insertions(+), 34 deletions(-) diff --git a/src/tab.rs b/src/tab.rs index b787280b..a87ec503 100644 --- a/src/tab.rs +++ b/src/tab.rs @@ -1757,40 +1757,26 @@ impl Tab { .width(get_column_width(col.heading)) .into() }); - columns.extend(columns_content); - - // let row = if condensed { - // widget::row::with_children(vec![ - // widget::icon::icon(item.icon_handle_list_condensed.clone()) - // .content_fit(ContentFit::Contain) - // .size(icon_size) - // .into(), - // widget::column::with_children(vec![ - // widget::text(item.name.clone()).into(), - // //TODO: translate? - // widget::text(format!("{} - {}", date_format, size_text())).into(), - // ]) - // .into(), - // ]) - // .align_items(Alignment::Center) - // .spacing(space_xxs) - // } else { - // widget::row::with_children(vec![ - // widget::icon::icon(item.icon_handle_list.clone()) - // .content_fit(ContentFit::Contain) - // .size(icon_size) - // .into(), - // widget::text(item.name.clone()).width(Length::Fill).into(), - // widget::text(date_format) - // .width(Length::Fixed(modified_width)) - // .into(), - // widget::text(size_text()) - // .width(Length::Fixed(size_width)) - // .into(), - // ]) - // .align_items(Alignment::Center) - // .spacing(space_xxs) - // }; + + let condensed_view = || { + visible_columns + .iter() + .filter(|col| col.active) + .map(|col| column_text(col.heading)) + .collect::>() + .join(" - ") + }; + + if condensed { + columns.push( + widget::column::with_capacity(1) + .push(widget::text(condensed_view())) + .into(), + ) + } else { + columns.extend(columns_content) + } + //TODO: translate? let button = widget::button( widget::row::with_children(columns) From 0d327de8998b05033208292a85146048de516925 Mon Sep 17 00:00:00 2001 From: Dominic Gerhauser Date: Fri, 1 Mar 2024 17:39:01 +0100 Subject: [PATCH 4/5] visible columns: add condensed view --- src/tab.rs | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/tab.rs b/src/tab.rs index a87ec503..157810be 100644 --- a/src/tab.rs +++ b/src/tab.rs @@ -1752,11 +1752,13 @@ impl Tab { HeadingOptions::Created => date_format!(created), }; - let columns_content = visible_columns.iter().filter(|col| col.active).map(|col| { - widget::text(column_text(col.heading)) - .width(get_column_width(col.heading)) - .into() - }); + let columns_content = || { + visible_columns.iter().filter(|col| col.active).map(|col| { + widget::text(column_text(col.heading)) + .width(get_column_width(col.heading)) + .into() + }) + }; let condensed_view = || { visible_columns @@ -1774,7 +1776,7 @@ impl Tab { .into(), ) } else { - columns.extend(columns_content) + columns.extend(columns_content()) } //TODO: translate? From 0bf20f3276c92a3bc32a638f116ad5f4659cde4d Mon Sep 17 00:00:00 2001 From: Dominic Gerhauser Date: Fri, 1 Mar 2024 22:37:01 +0100 Subject: [PATCH 5/5] visible columns: fix wrong column with --- src/tab.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/tab.rs b/src/tab.rs index 157810be..a140c085 100644 --- a/src/tab.rs +++ b/src/tab.rs @@ -1647,10 +1647,10 @@ impl Tab { let get_column_width = |col: HeadingOptions| match col { HeadingOptions::Name => Length::Fill, - HeadingOptions::Modified => Length::Fixed(modified_width), - HeadingOptions::Size | HeadingOptions::Accessed | HeadingOptions::Created => { - Length::Fixed(size_width) + HeadingOptions::Modified | HeadingOptions::Accessed | HeadingOptions::Created => { + Length::Fixed(modified_width) } + HeadingOptions::Size => Length::Fixed(size_width), }; let heading = self