mirror of
https://github.com/FliegendeWurst/cursive.git
synced 2024-11-27 11:16:03 +00:00
New TextView layout computation
Lines are now computed during layout. Draw is simpler. This is in preparation to scrolling addition to TextView.
This commit is contained in:
parent
1f3e17b591
commit
bfccae1b8e
@ -8,6 +8,13 @@ use printer::Printer;
|
|||||||
/// A simple view showing a fixed text
|
/// A simple view showing a fixed text
|
||||||
pub struct TextView {
|
pub struct TextView {
|
||||||
content: String,
|
content: String,
|
||||||
|
rows: Vec<Row>,
|
||||||
|
start_line: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Row {
|
||||||
|
start: usize,
|
||||||
|
end: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn strip_last_newline(content: &str) -> &str {
|
fn strip_last_newline(content: &str) -> &str {
|
||||||
@ -40,6 +47,8 @@ impl TextView {
|
|||||||
let content = strip_last_newline(content);
|
let content = strip_last_newline(content);
|
||||||
TextView {
|
TextView {
|
||||||
content: content.to_string(),
|
content: content.to_string(),
|
||||||
|
start_line: 0,
|
||||||
|
rows: Vec::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -82,70 +91,81 @@ impl TextView {
|
|||||||
}
|
}
|
||||||
|
|
||||||
struct LinesIterator<'a> {
|
struct LinesIterator<'a> {
|
||||||
line: &'a str,
|
content: &'a str,
|
||||||
start: usize,
|
start: usize,
|
||||||
width: usize,
|
width: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl <'a> LinesIterator<'a> {
|
impl <'a> LinesIterator<'a> {
|
||||||
fn new(line: &'a str, width: usize) -> Self {
|
fn new(content: &'a str, width: usize) -> Self {
|
||||||
if line.len() == 0 {
|
|
||||||
LinesIterator {
|
LinesIterator {
|
||||||
line: " ",
|
content: content,
|
||||||
width: width,
|
width: width,
|
||||||
start: 0,
|
start: 0,
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
LinesIterator {
|
|
||||||
line: line,
|
|
||||||
width: width,
|
|
||||||
start: 0,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl <'a> Iterator for LinesIterator<'a> {
|
impl <'a> Iterator for LinesIterator<'a> {
|
||||||
|
|
||||||
type Item = &'a str;
|
type Item = Row;
|
||||||
|
|
||||||
fn next(&mut self) -> Option<&'a str> {
|
fn next(&mut self) -> Option<Row> {
|
||||||
if self.start >= self.line.len() {
|
if self.start >= self.content.len() {
|
||||||
None
|
// This is the end
|
||||||
} else if self.start + self.width >= self.line.len() {
|
return None;
|
||||||
let start = self.start;
|
|
||||||
self.start = self.line.len();
|
|
||||||
Some(&self.line[start..])
|
|
||||||
} else {
|
|
||||||
let start = self.start;
|
|
||||||
let (end,skip_space) = match self.line[start..start+self.width].rfind(" ") {
|
|
||||||
// Hard break
|
|
||||||
None => (start + self.width, false),
|
|
||||||
Some(i) => (start+i, true),
|
|
||||||
};
|
|
||||||
self.start = end;
|
|
||||||
if skip_space {
|
|
||||||
self.start += 1;
|
|
||||||
}
|
}
|
||||||
Some(&self.line[start..end])
|
|
||||||
|
let start = self.start;
|
||||||
|
let content = &self.content[self.start..];
|
||||||
|
|
||||||
|
if let Some(next) = content.find("\n") {
|
||||||
|
if next < self.width {
|
||||||
|
self.start += next+1;
|
||||||
|
return Some(Row {
|
||||||
|
start: start,
|
||||||
|
end: next + start,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if content.len() <= self.width {
|
||||||
|
self.start += content.len();
|
||||||
|
return Some(Row{
|
||||||
|
start: start,
|
||||||
|
end: start + content.len(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if let Some(i) = content[..self.width].rfind(" ") {
|
||||||
|
self.start += i+1;
|
||||||
|
return Some(Row {
|
||||||
|
start: start,
|
||||||
|
end: i + start,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
self.start += self.width;
|
||||||
|
return Some(Row {
|
||||||
|
start: start,
|
||||||
|
end: start + self.width,
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl View for TextView {
|
impl View for TextView {
|
||||||
fn draw(&mut self, printer: &Printer, _: bool) {
|
fn draw(&mut self, printer: &Printer, _: bool) {
|
||||||
// We don't have a focused view
|
// We don't have a focused view
|
||||||
|
for (i,line) in self.rows.iter().skip(self.start_line).map(|row| &self.content[row.start..row.end]).enumerate() {
|
||||||
let lines = self.content.split("\n")
|
|
||||||
.flat_map(|line| LinesIterator::new(line, printer.size.x as usize));
|
|
||||||
for (i, line) in lines.enumerate() {
|
|
||||||
printer.print((0,i), line);
|
printer.print((0,i), line);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_min_size(&self, size: SizeRequest) -> Vec2 {
|
fn get_min_size(&self, size: SizeRequest) -> Vec2 {
|
||||||
match (size.w,size.h) {
|
match (size.w,size.h) {
|
||||||
|
// If we have no directive, ask for a single big line.
|
||||||
|
// TODO: what if the text has newlines??
|
||||||
(DimensionRequest::Unknown, DimensionRequest::Unknown) => Vec2::new(self.content.len() as u32, 1),
|
(DimensionRequest::Unknown, DimensionRequest::Unknown) => Vec2::new(self.content.len() as u32, 1),
|
||||||
(DimensionRequest::Fixed(w),_) => {
|
(DimensionRequest::Fixed(w),_) => {
|
||||||
let h = self.get_num_lines(w as usize) as u32;
|
let h = self.get_num_lines(w as usize) as u32;
|
||||||
@ -156,6 +176,7 @@ impl View for TextView {
|
|||||||
Vec2::new(w, h)
|
Vec2::new(w, h)
|
||||||
},
|
},
|
||||||
(DimensionRequest::AtMost(w),_) => {
|
(DimensionRequest::AtMost(w),_) => {
|
||||||
|
// Don't _force_ the max width, but take it if we have to.
|
||||||
let ideal = self.get_ideal_size();
|
let ideal = self.get_ideal_size();
|
||||||
|
|
||||||
if w >= ideal.x {
|
if w >= ideal.x {
|
||||||
@ -168,4 +189,10 @@ impl View for TextView {
|
|||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn layout(&mut self, size: Vec2) {
|
||||||
|
// Compute the text rows.
|
||||||
|
|
||||||
|
self.rows = LinesIterator::new(&self.content, size.x as usize).collect();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user