widgets: allow text overflow in text fields
Show text content of a text field that exceeds the visible width properly.jmap-eventsource
parent
f69f623818
commit
d4f508642a
|
@ -33,6 +33,8 @@ pub use wcwidth::*;
|
|||
pub trait Truncate {
|
||||
fn truncate_at_boundary(&mut self, new_len: usize);
|
||||
fn trim_at_boundary(&self, new_len: usize) -> &str;
|
||||
fn trim_left_at_boundary(&self, new_len: usize) -> &str;
|
||||
fn truncate_left_at_boundary(&mut self, new_len: usize);
|
||||
}
|
||||
|
||||
impl Truncate for &str {
|
||||
|
@ -67,6 +69,39 @@ impl Truncate for &str {
|
|||
self
|
||||
}
|
||||
}
|
||||
|
||||
fn trim_left_at_boundary(&self, skip_len: usize) -> &str {
|
||||
if skip_len >= self.len() {
|
||||
return "";
|
||||
}
|
||||
|
||||
extern crate unicode_segmentation;
|
||||
use unicode_segmentation::UnicodeSegmentation;
|
||||
if let Some((first, _)) = UnicodeSegmentation::grapheme_indices(*self, true)
|
||||
.skip(skip_len)
|
||||
.next()
|
||||
{
|
||||
&self[first..]
|
||||
} else {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
fn truncate_left_at_boundary(&mut self, skip_len: usize) {
|
||||
if skip_len >= self.len() {
|
||||
*self = "";
|
||||
return;
|
||||
}
|
||||
|
||||
extern crate unicode_segmentation;
|
||||
use unicode_segmentation::UnicodeSegmentation;
|
||||
if let Some((first, _)) = UnicodeSegmentation::grapheme_indices(*self, true)
|
||||
.skip(skip_len)
|
||||
.next()
|
||||
{
|
||||
*self = &self[first..];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Truncate for String {
|
||||
|
@ -101,6 +136,39 @@ impl Truncate for String {
|
|||
self.as_str()
|
||||
}
|
||||
}
|
||||
|
||||
fn trim_left_at_boundary(&self, skip_len: usize) -> &str {
|
||||
if skip_len >= self.len() {
|
||||
return "";
|
||||
}
|
||||
|
||||
extern crate unicode_segmentation;
|
||||
use unicode_segmentation::UnicodeSegmentation;
|
||||
if let Some((first, _)) = UnicodeSegmentation::grapheme_indices(self.as_str(), true)
|
||||
.skip(skip_len)
|
||||
.next()
|
||||
{
|
||||
&self[first..]
|
||||
} else {
|
||||
self.as_str()
|
||||
}
|
||||
}
|
||||
|
||||
fn truncate_left_at_boundary(&mut self, skip_len: usize) {
|
||||
if skip_len >= self.len() {
|
||||
self.clear();
|
||||
return;
|
||||
}
|
||||
|
||||
extern crate unicode_segmentation;
|
||||
use unicode_segmentation::UnicodeSegmentation;
|
||||
if let Some((first, _)) = UnicodeSegmentation::grapheme_indices(self.as_str(), true)
|
||||
.skip(skip_len)
|
||||
.next()
|
||||
{
|
||||
*self = self[first..].to_string();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub trait GlobMatch {
|
||||
|
|
|
@ -111,12 +111,15 @@ impl Field {
|
|||
let upper_left = upper_left!(area);
|
||||
match self {
|
||||
Text(ref term, auto_complete_fn) => {
|
||||
let width = width!(area);
|
||||
let pos = if width < term.grapheme_pos() {
|
||||
width
|
||||
} else {
|
||||
term.grapheme_pos()
|
||||
};
|
||||
change_colors(
|
||||
grid,
|
||||
(
|
||||
pos_inc(upper_left, (term.grapheme_pos(), 0)),
|
||||
(pos_inc(upper_left, (term.grapheme_pos(), 0))),
|
||||
),
|
||||
(pos_inc(upper_left, (pos, 0)), pos_inc(upper_left, (pos, 0))),
|
||||
Color::Default,
|
||||
Color::Byte(248),
|
||||
);
|
||||
|
@ -137,15 +140,89 @@ impl Field {
|
|||
impl Component for Field {
|
||||
fn draw(&mut self, grid: &mut CellBuffer, area: Area, context: &mut Context) {
|
||||
let theme_attr = crate::conf::value(context, "widgets.form.field");
|
||||
write_string_to_grid(
|
||||
self.as_str(),
|
||||
grid,
|
||||
theme_attr.fg,
|
||||
theme_attr.bg,
|
||||
theme_attr.attrs,
|
||||
area,
|
||||
None,
|
||||
);
|
||||
let width = width!(area);
|
||||
let str = self.as_str();
|
||||
match self {
|
||||
Text(ref term, _) => {
|
||||
/* Calculate which part of the str is visible
|
||||
* ##########################################
|
||||
*
|
||||
* Example:
|
||||
* For the string "The quick brown fox jumps over the lazy dog" with visible width
|
||||
* of field of 10 columns
|
||||
*
|
||||
*
|
||||
* Cursor <= width
|
||||
* =================
|
||||
* Cursor at:
|
||||
* ⇩
|
||||
* The quick brown fox jumps over the lazy dog
|
||||
*
|
||||
* cursor
|
||||
* ⇩
|
||||
* ┌──────────┐
|
||||
* │The quick │ brown fox jumps over the lazy dog
|
||||
* └──────────┘
|
||||
*
|
||||
* No skip.
|
||||
*
|
||||
* Cursor at the end
|
||||
* =================
|
||||
* Cursor at:
|
||||
* ⇩
|
||||
* The quick brown fox jumps over the lazy dog
|
||||
*
|
||||
* remainder cursor
|
||||
* ⇩⇩⇩⇩⇩ ⇩
|
||||
* +╌╌╌+╭┅┅┅┅┅┅┅┅┅┅╮╭┅┅┅┅┅┅┅┅┅┅╮╭┅┅┅┅┅┅┅┅┅┅╮┌──────────┐
|
||||
* |The|┊ quick bro┊┊wn fox jum┊┊ps over th┊│e lazy dog│
|
||||
* +╌╌╌+╰┅┅┅┅┅┅┅┅┅┅╯╰┅┅┅┅┅┅┅┅┅┅╯╰┅┅┅┅┅┅┅┅┅┅╯└──────────┘
|
||||
* ⇧⇧⇧++⇧⇧⇧⇧⇧⇧⇧⇧⇧⇧++⇧⇧⇧⇧⇧⇧⇧⇧⇧⇧++⇧⇧⇧⇧⇧⇧⇧⇧⇧⇧
|
||||
* skip offset
|
||||
*
|
||||
* Intermediate cursor
|
||||
* ===================
|
||||
* Cursor at:
|
||||
* ⇩
|
||||
* The quick brown fox jumps over the lazy dog
|
||||
*
|
||||
* remainder cursor
|
||||
* ⇩ ⇩
|
||||
* +╭┅┅┅┅┅┅┅┅┅┅╮╭┅┅┅┅┅┅┅┅┅┅╮┌──────────┐
|
||||
* T|he quick b┊┊rown fox j┊│umps over │ the lazy dog
|
||||
* +╰┅┅┅┅┅┅┅┅┅┅╯╰┅┅┅┅┅┅┅┅┅┅╯└──────────┘
|
||||
* ⇧+⇧⇧⇧⇧⇧⇧⇧⇧⇧⇧++⇧⇧⇧⇧⇧⇧⇧⇧⇧⇧
|
||||
* skip offset
|
||||
*/
|
||||
write_string_to_grid(
|
||||
if width < term.grapheme_pos() {
|
||||
str.trim_left_at_boundary(
|
||||
width * term.grapheme_pos().wrapping_div(width).saturating_sub(1)
|
||||
+ term.grapheme_pos().wrapping_rem(width),
|
||||
)
|
||||
} else {
|
||||
str
|
||||
},
|
||||
grid,
|
||||
theme_attr.fg,
|
||||
theme_attr.bg,
|
||||
theme_attr.attrs,
|
||||
area,
|
||||
None,
|
||||
);
|
||||
}
|
||||
Choice(_, _) => {
|
||||
write_string_to_grid(
|
||||
str,
|
||||
grid,
|
||||
theme_attr.fg,
|
||||
theme_attr.bg,
|
||||
theme_attr.attrs,
|
||||
area,
|
||||
None,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
fn process_event(&mut self, event: &mut UIEvent, context: &mut Context) -> bool {
|
||||
match *event {
|
||||
|
@ -496,10 +573,7 @@ impl<T: 'static + std::fmt::Debug + Copy + Default + Send + Sync> Component for
|
|||
grid,
|
||||
(
|
||||
pos_inc(upper_left, (self.field_name_max_length + 3, i)),
|
||||
(
|
||||
get_x(upper_left) + self.field_name_max_length + 3,
|
||||
i + get_y(upper_left),
|
||||
),
|
||||
(get_x(bottom_right), i + get_y(upper_left)),
|
||||
),
|
||||
(
|
||||
pos_inc(upper_left, (self.field_name_max_length + 3, i + 1)),
|
||||
|
|
Loading…
Reference in New Issue