Use StyledString in SelectView

This commit is contained in:
Alexandre Bury 2018-11-30 13:19:08 -08:00
parent 612c7d9ea7
commit 6b278495d5
3 changed files with 51 additions and 32 deletions

View File

@ -84,9 +84,24 @@ impl<'a, 'b> Printer<'a, 'b> {
.clear(self.theme.palette[PaletteColor::Background]); .clear(self.theme.palette[PaletteColor::Background]);
} }
/// Prints some styled text at the given position.
pub fn print_styled<S>(
&self, start: S, text: ::utils::span::SpannedStr<'_, Style>,
) where
S: Into<Vec2>,
{
let Vec2 { mut x, y } = start.into();
for span in text.spans() {
self.with_style(*span.attr, |printer| {
printer.print((x, y), span.content);
x += span.content.width();
});
}
}
// TODO: use &mut self? We don't *need* it, but it may make sense. // TODO: use &mut self? We don't *need* it, but it may make sense.
// We don't want people to start calling prints in parallel? // We don't want people to start calling prints in parallel?
/// Prints some text at the given position relative to the window. /// Prints some text at the given position
pub fn print<S: Into<Vec2>>(&self, start: S, text: &str) { pub fn print<S: Into<Vec2>>(&self, start: S, text: &str) {
// Where we are asked to start printing. Oh boy. // Where we are asked to start printing. Oh boy.
let start = start.into(); let start = start.into();

View File

@ -3,6 +3,7 @@
//! This module defines various structs describing a span of text from a //! This module defines various structs describing a span of text from a
//! larger string. //! larger string.
use std::borrow::Cow; use std::borrow::Cow;
use unicode_width::UnicodeWidthStr;
/// A string with associated spans. /// A string with associated spans.
/// ///
@ -117,11 +118,12 @@ where
} }
/// Gives access to the parsed styled spans. /// Gives access to the parsed styled spans.
pub fn spans(&self) -> Vec<Span<'a, T>> { pub fn spans<'b>(&'b self) -> impl Iterator<Item = Span<'a, T>> + 'b
self.spans where
.iter() 'a: 'b,
.map(|span| span.resolve(self.source)) {
.collect() let source = self.source;
self.spans.iter().map(move |span| span.resolve(source))
} }
/// Returns a reference to the indexed spans. /// Returns a reference to the indexed spans.
@ -232,12 +234,9 @@ impl<T> SpannedString<T> {
} }
/// Gives access to the parsed styled spans. /// Gives access to the parsed styled spans.
#[cfg_attr(feature = "cargo-clippy", allow(needless_lifetimes))] pub fn spans<'a>(&'a self) -> impl Iterator<Item = Span<'a, T>> {
pub fn spans<'a>(&'a self) -> Vec<Span<'a, T>> { let source = &self.source;
self.spans self.spans.iter().map(move |span| span.resolve(source))
.iter()
.map(|span| span.resolve(&self.source))
.collect()
} }
/// Returns a reference to the indexed spans. /// Returns a reference to the indexed spans.
@ -256,6 +255,13 @@ impl<T> SpannedString<T> {
pub fn is_empty(&self) -> bool { pub fn is_empty(&self) -> bool {
self.source.is_empty() || self.spans.is_empty() self.source.is_empty() || self.spans.is_empty()
} }
/// Returns the width taken by this string.
///
/// This is the sum of the width of each span.
pub fn width(&self) -> usize {
self.spans().map(|s| s.content.width()).sum()
}
} }
impl<'a, T> From<&'a SpannedString<T>> for SpannedStr<'a, T> { impl<'a, T> From<&'a SpannedString<T>> for SpannedStr<'a, T> {

View File

@ -8,7 +8,7 @@ use std::cell::Cell;
use std::cmp::min; use std::cmp::min;
use std::rc::Rc; use std::rc::Rc;
use theme::ColorStyle; use theme::ColorStyle;
use unicode_width::UnicodeWidthStr; use utils::markup::StyledString;
use vec::Vec2; use vec::Vec2;
use view::{Position, View}; use view::{Position, View};
use views::MenuPopup; use views::MenuPopup;
@ -253,7 +253,7 @@ impl<T: 'static> SelectView<T> {
} }
/// Adds a item to the list, with given label and value. /// Adds a item to the list, with given label and value.
pub fn add_item<S: Into<String>>(&mut self, label: S, value: T) { pub fn add_item<S: Into<StyledString>>(&mut self, label: S, value: T) {
self.items.push(Item::new(label.into(), value)); self.items.push(Item::new(label.into(), value));
} }
@ -267,13 +267,13 @@ impl<T: 'static> SelectView<T> {
/// assert_eq!(select.get_item(0), Some(("Short", &1))); /// assert_eq!(select.get_item(0), Some(("Short", &1)));
/// ``` /// ```
pub fn get_item(&self, i: usize) -> Option<(&str, &T)> { pub fn get_item(&self, i: usize) -> Option<(&str, &T)> {
self.items self.iter().nth(i)
.get(i)
.map(|item| (item.label.as_ref(), &*item.value))
} }
/// Gets a mut item at given idx or None. /// Gets a mut item at given idx or None.
pub fn get_item_mut(&mut self, i: usize) -> Option<(&mut String, &mut T)> { pub fn get_item_mut(
&mut self, i: usize,
) -> Option<(&mut StyledString, &mut T)> {
if i >= self.items.len() { if i >= self.items.len() {
None None
} else { } else {
@ -293,7 +293,7 @@ impl<T: 'static> SelectView<T> {
pub fn iter(&self) -> impl Iterator<Item = (&str, &T)> { pub fn iter(&self) -> impl Iterator<Item = (&str, &T)> {
self.items self.items
.iter() .iter()
.map(|item| (item.label.as_str(), &*item.value)) .map(|item| (item.label.source(), &*item.value))
} }
/// Removes an item from the list. /// Removes an item from the list.
@ -315,7 +315,7 @@ impl<T: 'static> SelectView<T> {
/// the right. /// the right.
pub fn insert_item<S>(&mut self, index: usize, label: S, value: T) pub fn insert_item<S>(&mut self, index: usize, label: S, value: T)
where where
S: Into<String>, S: Into<StyledString>,
{ {
self.items.insert(index, Item::new(label.into(), value)); self.items.insert(index, Item::new(label.into(), value));
} }
@ -328,7 +328,7 @@ impl<T: 'static> SelectView<T> {
/// Adds all items from from an iterator. /// Adds all items from from an iterator.
pub fn add_all<S, I>(&mut self, iter: I) pub fn add_all<S, I>(&mut self, iter: I)
where where
S: Into<String>, S: Into<StyledString>,
I: IntoIterator<Item = (S, T)>, I: IntoIterator<Item = (S, T)>,
{ {
for (s, t) in iter { for (s, t) in iter {
@ -351,7 +351,7 @@ impl<T: 'static> SelectView<T> {
let l = self.items[i].label.width(); let l = self.items[i].label.width();
let x = self.align.h.get_offset(l, printer.size.x); let x = self.align.h.get_offset(l, printer.size.x);
printer.print_hline((0, 0), x, " "); printer.print_hline((0, 0), x, " ");
printer.print((x, 0), &self.items[i].label); printer.print_styled((x, 0), (&self.items[i].label).into());
if l < printer.size.x { if l < printer.size.x {
assert!((l + x) <= printer.size.x); assert!((l + x) <= printer.size.x);
printer.print_hline((x + l, 0), printer.size.x - (l + x), " "); printer.print_hline((x + l, 0), printer.size.x - (l + x), " ");
@ -554,7 +554,7 @@ impl<T: 'static> SelectView<T> {
let focus = Rc::clone(&self.focus); let focus = Rc::clone(&self.focus);
let on_submit = self.on_submit.as_ref().cloned(); let on_submit = self.on_submit.as_ref().cloned();
let value = Rc::clone(&item.value); let value = Rc::clone(&item.value);
tree.add_leaf(item.label.clone(), move |s| { tree.add_leaf(item.label.source(), move |s| {
// TODO: What if an item was removed in the meantime? // TODO: What if an item was removed in the meantime?
focus.set(i); focus.set(i);
if let Some(ref on_submit) = on_submit { if let Some(ref on_submit) = on_submit {
@ -570,7 +570,7 @@ impl<T: 'static> SelectView<T> {
// This is the offset for the label text. // This is the offset for the label text.
// We'll want to show the popup so that the text matches. // We'll want to show the popup so that the text matches.
// It'll be soo cool. // It'll be soo cool.
let item_length = self.items[focus].label.len(); let item_length = self.items[focus].label.width();
let text_offset = (self.last_size.x.saturating_sub(item_length)) / 2; let text_offset = (self.last_size.x.saturating_sub(item_length)) / 2;
// The total offset for the window is: // The total offset for the window is:
// * the last absolute offset at which we drew this view // * the last absolute offset at which we drew this view
@ -698,9 +698,9 @@ impl<T: 'static> View for SelectView<T> {
let label = &self.items[self.focus()].label; let label = &self.items[self.focus()].label;
// And center the text? // And center the text?
let offset = HAlign::Center.get_offset(label.len(), x + 1); let offset = HAlign::Center.get_offset(label.width(), x + 1);
printer.print((offset, 0), label); printer.print_styled((offset, 0), label.into());
}); });
} else { } else {
// Non-popup mode: we always print the entire list. // Non-popup mode: we always print the entire list.
@ -772,15 +772,13 @@ impl<T: 'static> View for SelectView<T> {
// We wrap each value in a `Rc` and add a label // We wrap each value in a `Rc` and add a label
struct Item<T> { struct Item<T> {
label: String, label: StyledString,
value: Rc<T>, value: Rc<T>,
} }
impl<T> Item<T> { impl<T> Item<T> {
fn new(label: String, value: T) -> Self { fn new(label: StyledString, value: T) -> Self {
Item { let value = Rc::new(value);
label, Item { label, value }
value: Rc::new(value),
}
} }
} }