utilities/tables: add x axis scroll support
Signed-off-by: Manos Pitsidianakis <manos@pitsidianak.is>pull/312/head
parent
bcec745c24
commit
ba7a97e90b
|
@ -770,10 +770,10 @@ Start new mail draft in new tab.
|
|||
.Pq Em m \" default value
|
||||
.It Ic next_account
|
||||
Go to next account.
|
||||
.Pq Em h \" default value
|
||||
.Pq Em H \" default value
|
||||
.It Ic prev_account
|
||||
Go to previous account.
|
||||
.Pq Em l \" default value
|
||||
.Pq Em L \" default value
|
||||
.It Ic next_mailbox
|
||||
Go to next mailbox.
|
||||
.Pq Em J \" default value
|
||||
|
@ -874,10 +874,10 @@ Mail contact under cursor.
|
|||
.Pq Em m \" default value
|
||||
.It Ic next_account
|
||||
Go to next account.
|
||||
.Pq Em h \" default value
|
||||
.Pq Em H \" default value
|
||||
.It Ic prev_account
|
||||
Go to previous account.
|
||||
.Pq Em l \" default value
|
||||
.Pq Em L \" default value
|
||||
.It Ic toggle_menu_visibility
|
||||
Toggle visibility of side menu in mail list.
|
||||
.Pq Em ` \" default value
|
||||
|
|
|
@ -153,10 +153,10 @@ shortcut_key_values! { "listing",
|
|||
scroll_up |> "Scroll up list." |> Key::Char('k'),
|
||||
scroll_down |> "Scroll down list." |> Key::Char('j'),
|
||||
new_mail |> "Start new mail draft in new tab." |> Key::Char('m'),
|
||||
next_account |> "Go to next account." |> Key::Char('h'),
|
||||
next_account |> "Go to next account." |> Key::Char('H'),
|
||||
next_mailbox |> "Go to next mailbox." |> Key::Char('J'),
|
||||
next_page |> "Go to next page." |> Key::PageDown,
|
||||
prev_account |> "Go to previous account." |> Key::Char('l'),
|
||||
prev_account |> "Go to previous account." |> Key::Char('L'),
|
||||
prev_mailbox |> "Go to previous mailbox." |> Key::Char('K'),
|
||||
open_mailbox |> "Open selected mailbox" |> Key::Char('\n'),
|
||||
toggle_mailbox_collapse |> "Toggle mailbox collapse in menu." |> Key::Char(' '),
|
||||
|
@ -189,8 +189,8 @@ shortcut_key_values! { "contact-list",
|
|||
edit_contact |> "Edit contact under cursor." |> Key::Char('e'),
|
||||
delete_contact |> "Delete contact under cursor." |> Key::Char('d'),
|
||||
mail_contact |> "Mail contact under cursor." |> Key::Char('m'),
|
||||
next_account |> "Go to next account." |> Key::Char('h'),
|
||||
prev_account |> "Go to previous account." |> Key::Char('l'),
|
||||
next_account |> "Go to next account." |> Key::Char('H'),
|
||||
prev_account |> "Go to previous account." |> Key::Char('L'),
|
||||
toggle_menu_visibility |> "Toggle visibility of side menu in mail list." |> Key::Char('`')
|
||||
}
|
||||
}
|
||||
|
@ -212,8 +212,8 @@ shortcut_key_values! { "general",
|
|||
quit |> "Quit meli." |> Key::Char('q'),
|
||||
go_to_tab |> "Go to the nth tab" |> Key::Alt('n'),
|
||||
next_tab |> "Next tab." |> Key::Char('T'),
|
||||
scroll_right |> "Generic scroll right (catch-all setting)" |> Key::Right,
|
||||
scroll_left |> "Generic scroll left (catch-all setting)" |> Key::Left,
|
||||
scroll_right |> "Generic scroll right (catch-all setting)" |> Key::Char('l'),
|
||||
scroll_left |> "Generic scroll left (catch-all setting)" |>Key::Char('h'),
|
||||
scroll_up |> "Generic scroll up (catch-all setting)" |> Key::Char('k'),
|
||||
scroll_down |> "Generic scroll down (catch-all setting)" |> Key::Char('j'),
|
||||
next_page |> "Go to next page. (catch-all setting)" |> Key::PageDown,
|
||||
|
|
|
@ -422,6 +422,45 @@ macro_rules! address_list {
|
|||
}};
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! digits_of_num {
|
||||
($num:expr) => {{
|
||||
const GUESS: [usize; 65] = [
|
||||
1, 0, 0, 0, 1, 1, 1, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 5, 5, 5, 6, 6, 6, 6, 7, 7, 7, 8, 8,
|
||||
8, 9, 9, 9, 9, 10, 10, 10, 11, 11, 11, 12, 12, 12, 12, 13, 13, 13, 14, 14, 14, 15, 15,
|
||||
15, 15, 16, 16, 16, 17, 17, 17, 18, 18, 18, 18, 19,
|
||||
];
|
||||
const TENS: [usize; 20] = [
|
||||
1,
|
||||
10,
|
||||
100,
|
||||
1000,
|
||||
10000,
|
||||
100000,
|
||||
1000000,
|
||||
10000000,
|
||||
100000000,
|
||||
1000000000,
|
||||
10000000000,
|
||||
100000000000,
|
||||
1000000000000,
|
||||
10000000000000,
|
||||
100000000000000,
|
||||
1000000000000000,
|
||||
10000000000000000,
|
||||
100000000000000000,
|
||||
1000000000000000000,
|
||||
10000000000000000000,
|
||||
];
|
||||
const SIZE_IN_BITS: usize = std::mem::size_of::<usize>() * 8;
|
||||
|
||||
let leading_zeros = $num.leading_zeros() as usize;
|
||||
let base_two_digits: usize = SIZE_IN_BITS - leading_zeros;
|
||||
let x = GUESS[base_two_digits];
|
||||
x + if $num >= TENS[x] { 1 } else { 0 }
|
||||
}};
|
||||
}
|
||||
|
||||
macro_rules! column_str {
|
||||
(
|
||||
struct $name:ident($($t:ty),+)) => {
|
||||
|
@ -1658,6 +1697,52 @@ impl Component for Listing {
|
|||
self.component.set_movement(PageMovement::Down(amount));
|
||||
return true;
|
||||
}
|
||||
UIEvent::Input(ref key)
|
||||
if shortcut!(key == shortcuts[Shortcuts::GENERAL]["scroll_right"]) =>
|
||||
{
|
||||
let amount = if self.cmd_buf.is_empty() {
|
||||
1
|
||||
} else if let Ok(amount) = self.cmd_buf.parse::<usize>() {
|
||||
self.cmd_buf.clear();
|
||||
self.component.set_modifier_active(false);
|
||||
context
|
||||
.replies
|
||||
.push_back(UIEvent::StatusEvent(StatusEvent::BufClear));
|
||||
amount
|
||||
} else {
|
||||
self.cmd_buf.clear();
|
||||
self.component.set_modifier_active(false);
|
||||
context
|
||||
.replies
|
||||
.push_back(UIEvent::StatusEvent(StatusEvent::BufClear));
|
||||
return true;
|
||||
};
|
||||
self.component.set_movement(PageMovement::Right(amount));
|
||||
return true;
|
||||
}
|
||||
UIEvent::Input(ref key)
|
||||
if shortcut!(key == shortcuts[Shortcuts::GENERAL]["scroll_left"]) =>
|
||||
{
|
||||
let amount = if self.cmd_buf.is_empty() {
|
||||
1
|
||||
} else if let Ok(amount) = self.cmd_buf.parse::<usize>() {
|
||||
self.cmd_buf.clear();
|
||||
self.component.set_modifier_active(false);
|
||||
context
|
||||
.replies
|
||||
.push_back(UIEvent::StatusEvent(StatusEvent::BufClear));
|
||||
amount
|
||||
} else {
|
||||
self.cmd_buf.clear();
|
||||
self.component.set_modifier_active(false);
|
||||
context
|
||||
.replies
|
||||
.push_back(UIEvent::StatusEvent(StatusEvent::BufClear));
|
||||
return true;
|
||||
};
|
||||
self.component.set_movement(PageMovement::Left(amount));
|
||||
return true;
|
||||
}
|
||||
UIEvent::Input(ref key)
|
||||
if shortcut!(key == shortcuts[Shortcuts::LISTING]["prev_page"]) =>
|
||||
{
|
||||
|
|
|
@ -27,60 +27,6 @@ use melib::{SortField, SortOrder, TagHash, Threads};
|
|||
use super::*;
|
||||
use crate::{components::PageMovement, jobs::JoinHandle};
|
||||
|
||||
macro_rules! digits_of_num {
|
||||
($num:expr) => {{
|
||||
const GUESS: [usize; 65] = [
|
||||
1, 0, 0, 0, 1, 1, 1, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 5, 5, 5, 6, 6, 6, 6, 7, 7, 7, 8, 8,
|
||||
8, 9, 9, 9, 9, 10, 10, 10, 11, 11, 11, 12, 12, 12, 12, 13, 13, 13, 14, 14, 14, 15, 15,
|
||||
15, 15, 16, 16, 16, 17, 17, 17, 18, 18, 18, 18, 19,
|
||||
];
|
||||
const TENS: [usize; 20] = [
|
||||
1,
|
||||
10,
|
||||
100,
|
||||
1000,
|
||||
10000,
|
||||
100000,
|
||||
1000000,
|
||||
10000000,
|
||||
100000000,
|
||||
1000000000,
|
||||
10000000000,
|
||||
100000000000,
|
||||
1000000000000,
|
||||
10000000000000,
|
||||
100000000000000,
|
||||
1000000000000000,
|
||||
10000000000000000,
|
||||
100000000000000000,
|
||||
1000000000000000000,
|
||||
10000000000000000000,
|
||||
];
|
||||
const SIZE_IN_BITS: usize = std::mem::size_of::<usize>() * 8;
|
||||
|
||||
let leading_zeros = $num.leading_zeros() as usize;
|
||||
let base_two_digits: usize = SIZE_IN_BITS - leading_zeros;
|
||||
let x = GUESS[base_two_digits];
|
||||
x + if $num >= TENS[x] { 1 } else { 0 }
|
||||
}};
|
||||
}
|
||||
|
||||
macro_rules! address_list {
|
||||
(($name:expr) as comma_sep_list) => {{
|
||||
let mut ret: String =
|
||||
$name
|
||||
.into_iter()
|
||||
.fold(String::new(), |mut s: String, n: &Address| {
|
||||
s.extend(n.to_string().chars());
|
||||
s.push_str(", ");
|
||||
s
|
||||
});
|
||||
ret.pop();
|
||||
ret.pop();
|
||||
ret
|
||||
}};
|
||||
}
|
||||
|
||||
macro_rules! row_attr {
|
||||
($color_cache:expr, $even: expr, $unseen:expr, $highlighted:expr, $selected:expr $(,)*) => {{
|
||||
let color_cache = &$color_cache;
|
||||
|
|
|
@ -445,7 +445,20 @@ impl ListingTrait for PlainListing {
|
|||
self.new_cursor_pos.2 = (self.length.saturating_sub(1) / rows) * rows;
|
||||
}
|
||||
}
|
||||
PageMovement::Right(_) | PageMovement::Left(_) => {}
|
||||
PageMovement::Right(amount) => {
|
||||
self.data_columns.x_offset += amount;
|
||||
self.data_columns.x_offset = self.data_columns.x_offset.min(
|
||||
self.data_columns
|
||||
.widths
|
||||
.iter()
|
||||
.map(|w| w + 2)
|
||||
.sum::<usize>()
|
||||
.saturating_sub(2),
|
||||
);
|
||||
}
|
||||
PageMovement::Left(amount) => {
|
||||
self.data_columns.x_offset = self.data_columns.x_offset.saturating_sub(amount);
|
||||
}
|
||||
PageMovement::Home => {
|
||||
self.new_cursor_pos.2 = 0;
|
||||
}
|
||||
|
@ -788,6 +801,18 @@ impl PlainListing {
|
|||
self.rows.clear();
|
||||
self.length = 0;
|
||||
let mut min_width = (0, 0, 0, 0, 0);
|
||||
#[allow(clippy::type_complexity)]
|
||||
let mut row_widths: (
|
||||
SmallVec<[u8; 1024]>,
|
||||
SmallVec<[u8; 1024]>,
|
||||
SmallVec<[u8; 1024]>,
|
||||
SmallVec<[u8; 1024]>,
|
||||
) = (
|
||||
SmallVec::new(),
|
||||
SmallVec::new(),
|
||||
SmallVec::new(),
|
||||
SmallVec::new(),
|
||||
);
|
||||
|
||||
for i in iter {
|
||||
if !context.accounts[&self.cursor_pos.0].contains_key(i) {
|
||||
|
@ -824,6 +849,28 @@ impl PlainListing {
|
|||
self.rows.row_attr_cache.insert(self.length, row_attr);
|
||||
|
||||
let entry_strings = self.make_entry_string(&envelope, context);
|
||||
row_widths.1.push(
|
||||
entry_strings
|
||||
.date
|
||||
.grapheme_width()
|
||||
.try_into()
|
||||
.unwrap_or(255),
|
||||
);
|
||||
row_widths.2.push(
|
||||
entry_strings
|
||||
.from
|
||||
.grapheme_width()
|
||||
.try_into()
|
||||
.unwrap_or(255),
|
||||
);
|
||||
row_widths.3.push(
|
||||
(entry_strings.flag.grapheme_width()
|
||||
+ entry_strings.subject.grapheme_width()
|
||||
+ 1
|
||||
+ entry_strings.tags.grapheme_width())
|
||||
.try_into()
|
||||
.unwrap_or(255),
|
||||
);
|
||||
min_width.1 = cmp::max(min_width.1, entry_strings.date.grapheme_width()); /* date */
|
||||
min_width.2 = cmp::max(min_width.2, entry_strings.from.grapheme_width()); /* from */
|
||||
min_width.3 = cmp::max(
|
||||
|
@ -842,6 +889,9 @@ impl PlainListing {
|
|||
|
||||
self.length += 1;
|
||||
}
|
||||
row_widths
|
||||
.0
|
||||
.push(digits_of_num!(self.length).try_into().unwrap_or(255));
|
||||
|
||||
min_width.0 = self.length.saturating_sub(1).to_string().len();
|
||||
|
||||
|
@ -868,6 +918,10 @@ impl PlainListing {
|
|||
_ = self.data_columns.columns[2].resize_with_context(min_width.2, self.rows.len(), context);
|
||||
/* subject column */
|
||||
_ = self.data_columns.columns[3].resize_with_context(min_width.3, self.rows.len(), context);
|
||||
self.data_columns.segment_tree[0] = row_widths.0.into();
|
||||
self.data_columns.segment_tree[1] = row_widths.1.into();
|
||||
self.data_columns.segment_tree[2] = row_widths.2.into();
|
||||
self.data_columns.segment_tree[3] = row_widths.3.into();
|
||||
|
||||
let iter = if self.filter_term.is_empty() {
|
||||
Box::new(self.local_collection.iter().cloned())
|
||||
|
|
|
@ -241,38 +241,35 @@ impl<const N: usize> DataColumns<N> {
|
|||
}
|
||||
|
||||
pub fn draw(
|
||||
&self,
|
||||
&mut self,
|
||||
grid: &mut CellBuffer,
|
||||
top_idx: usize,
|
||||
cursor_pos: usize,
|
||||
mut bounds: BoundsIterator,
|
||||
) {
|
||||
let mut _relative_x_offset = 0;
|
||||
let mut skip_cols = (0, 0);
|
||||
let mut start_col = 0;
|
||||
let total_area = bounds.area();
|
||||
let height = total_area.height();
|
||||
while _relative_x_offset < self.x_offset && start_col < N {
|
||||
_relative_x_offset += self.widths[start_col] + 2;
|
||||
if self.x_offset <= _relative_x_offset {
|
||||
skip_cols.0 = start_col;
|
||||
skip_cols.1 = _relative_x_offset - self.x_offset;
|
||||
_relative_x_offset = self.x_offset;
|
||||
if self.width_accum > 0 && self.x_offset + total_area.width() > self.width_accum {
|
||||
self.x_offset = self.width_accum.saturating_sub(total_area.width());
|
||||
}
|
||||
let mut x_offset = self.x_offset;
|
||||
for col in 0..N {
|
||||
start_col = col;
|
||||
if x_offset == 0 || self.widths[col] > x_offset {
|
||||
break;
|
||||
}
|
||||
start_col += 1;
|
||||
x_offset -= self.widths[col];
|
||||
x_offset = x_offset.saturating_sub(2);
|
||||
}
|
||||
|
||||
for col in skip_cols.0..N {
|
||||
for col in start_col..N {
|
||||
if bounds.is_empty() {
|
||||
break;
|
||||
}
|
||||
|
||||
let mut column_width = self.widths[col];
|
||||
if column_width > bounds.width() {
|
||||
column_width = bounds.width();
|
||||
} else if column_width == 0 {
|
||||
skip_cols.1 = 0;
|
||||
let column_width = self.widths[col];
|
||||
if column_width == 0 {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -282,11 +279,11 @@ impl<const N: usize> DataColumns<N> {
|
|||
self.columns[col]
|
||||
.area()
|
||||
.skip_rows(top_idx)
|
||||
.skip_cols(skip_cols.1)
|
||||
.take_cols(column_width),
|
||||
.skip_cols(x_offset)
|
||||
.take_cols(column_width - x_offset),
|
||||
);
|
||||
bounds.add_x(column_width + 2);
|
||||
skip_cols.1 = 0;
|
||||
bounds.add_x(column_width - x_offset + 2);
|
||||
x_offset = 0;
|
||||
}
|
||||
|
||||
match self.theme_config.theme {
|
||||
|
|
Loading…
Reference in New Issue