mirror of
https://github.com/FliegendeWurst/cursive.git
synced 2024-11-23 17:35:00 +00:00
printer: add doc
This commit is contained in:
parent
8c2ff6bd4f
commit
5586403080
@ -14,12 +14,12 @@ use with::With;
|
|||||||
///
|
///
|
||||||
/// The area it can print on is defined by `offset` and `size`.
|
/// The area it can print on is defined by `offset` and `size`.
|
||||||
///
|
///
|
||||||
/// The part of the content it will print there is defined by `content_offset`
|
/// The part of the content it will print is defined by `content_offset`
|
||||||
/// and `size`.
|
/// and `size`.
|
||||||
pub struct Printer<'a> {
|
pub struct Printer<'a> {
|
||||||
/// Offset into the window this printer should start drawing at.
|
/// Offset into the window this printer should start drawing at.
|
||||||
///
|
///
|
||||||
/// Printing at `x` will really print at `x + offset`.
|
/// A print request at `x` will really print at `x + offset`.
|
||||||
pub offset: Vec2,
|
pub offset: Vec2,
|
||||||
|
|
||||||
/// Size of the area we are allowed to draw on.
|
/// Size of the area we are allowed to draw on.
|
||||||
@ -29,7 +29,7 @@ pub struct Printer<'a> {
|
|||||||
|
|
||||||
/// Offset into the view for this printer.
|
/// Offset into the view for this printer.
|
||||||
///
|
///
|
||||||
/// Printing at `x`, will really print at `x - content_offset`.
|
/// A print request `x`, will really print at `x - content_offset`.
|
||||||
pub content_offset: Vec2,
|
pub content_offset: Vec2,
|
||||||
|
|
||||||
/// Whether the view to draw is currently focused or not.
|
/// Whether the view to draw is currently focused or not.
|
||||||
@ -86,16 +86,19 @@ impl<'a> Printer<'a> {
|
|||||||
// 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 relative to the window.
|
||||||
pub fn print<S: Into<Vec2>>(&self, pos: S, text: &str) {
|
pub fn print<S: Into<Vec2>>(&self, start: S, text: &str) {
|
||||||
let pos = pos.into();
|
let start = start.into();
|
||||||
|
|
||||||
if !pos.fits_in(self.size + self.content_offset) {
|
// We accept requests between `content_offset` and
|
||||||
|
// `content_offset + size`
|
||||||
|
if !start.fits_in(self.size + self.content_offset) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// This is the part of the text that's hidden
|
// If start < content_offset, part of the text will not be visible.
|
||||||
// (smaller than the content offset)
|
// This is the part of the text that's hidden:
|
||||||
let hidden_part = self.content_offset.saturating_sub(pos);
|
// (It should always be smaller than the content offset)
|
||||||
|
let hidden_part = self.content_offset.saturating_sub(start);
|
||||||
if hidden_part.y > 0 {
|
if hidden_part.y > 0 {
|
||||||
// Since we are printing a single line, there's nothing we can do.
|
// Since we are printing a single line, there's nothing we can do.
|
||||||
return;
|
return;
|
||||||
@ -112,6 +115,7 @@ impl<'a> Printer<'a> {
|
|||||||
let tail = suffix(text.graphemes(true), text_width - hidden_part.x, "");
|
let tail = suffix(text.graphemes(true), text_width - hidden_part.x, "");
|
||||||
let skipped_len = text.len() - tail.length;
|
let skipped_len = text.len() - tail.length;
|
||||||
let skipped_width = text_width - tail.width;
|
let skipped_width = text_width - tail.width;
|
||||||
|
assert_eq!(text[..skipped_len].width(), skipped_width);
|
||||||
|
|
||||||
// This should be equal most of the time, except when there's a double
|
// This should be equal most of the time, except when there's a double
|
||||||
// character preventing us from splitting perfectly.
|
// character preventing us from splitting perfectly.
|
||||||
@ -119,80 +123,90 @@ impl<'a> Printer<'a> {
|
|||||||
|
|
||||||
// Drop part of the text, and move the cursor correspondingly.
|
// Drop part of the text, and move the cursor correspondingly.
|
||||||
let text = &text[skipped_len..];
|
let text = &text[skipped_len..];
|
||||||
let pos = pos + (skipped_width, 0);
|
let start = start + (skipped_width, 0);
|
||||||
|
assert!(start.fits(self.content_offset));
|
||||||
|
|
||||||
// What we did before should guarantee that this won't overflow.
|
// What we did before should guarantee that this won't overflow.
|
||||||
let pos = pos - self.content_offset;
|
let start = start - self.content_offset;
|
||||||
|
|
||||||
// Do we have enough room for the entire line?
|
// Do we have enough room for the entire line?
|
||||||
let room = self.size.x - pos.x;
|
let room = self.size.x - start.x;
|
||||||
|
|
||||||
// Drop the end of the text if it's too long
|
// Drop the end of the text if it's too long
|
||||||
// We want the number of CHARACTERS, not bytes.
|
// We want the number of CHARACTERS, not bytes.
|
||||||
// (Actually we want the "width" of the string, see unicode-width)
|
// (Actually we want the "width" of the string, see unicode-width)
|
||||||
let prefix_len = prefix(text.graphemes(true), room, "").length;
|
let prefix_len = prefix(text.graphemes(true), room, "").length;
|
||||||
let text = &text[..prefix_len];
|
let text = &text[..prefix_len];
|
||||||
|
assert!(text.width() <= room);
|
||||||
|
|
||||||
let pos = pos + self.offset;
|
let start = start + self.offset;
|
||||||
self.backend.print_at(pos, text);
|
self.backend.print_at(start, text);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Prints a vertical line using the given character.
|
/// Prints a vertical line using the given character.
|
||||||
pub fn print_vline<T: Into<Vec2>>(&self, start: T, len: usize, c: &str) {
|
pub fn print_vline<T: Into<Vec2>>(&self, start: T, height: usize, c: &str) {
|
||||||
let start = start.into();
|
let start = start.into();
|
||||||
|
|
||||||
|
// Here again, we can abort if we're trying to print too far right or
|
||||||
|
// too low.
|
||||||
if !start.fits_in(self.size + self.content_offset) {
|
if !start.fits_in(self.size + self.content_offset) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// hidden_part describes how far to the top left of the viewport we are.
|
||||||
let hidden_part = self.content_offset.saturating_sub(start);
|
let hidden_part = self.content_offset.saturating_sub(start);
|
||||||
if hidden_part.x > 0 || hidden_part.y >= len {
|
if hidden_part.x > 0 || hidden_part.y >= height {
|
||||||
// We're printing a single column, so we can't do much here.
|
// We're printing a single column, so we can't do much here.
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Skip `hidden_part`
|
// Skip `hidden_part`
|
||||||
let start = start + hidden_part;
|
let start = start + hidden_part;
|
||||||
let len = len - hidden_part.y;
|
assert!(start.fits(self.content_offset));
|
||||||
|
|
||||||
|
let height = height - hidden_part.y;
|
||||||
|
|
||||||
// What we did before ensures this won't overflow.
|
// What we did before ensures this won't overflow.
|
||||||
let start = start - self.content_offset;
|
let start = start - self.content_offset;
|
||||||
|
|
||||||
// Don't go overboard
|
// Don't go overboard
|
||||||
let len = min(len, self.size.y - start.y);
|
let height = min(height, self.size.y - start.y);
|
||||||
|
|
||||||
let start = start + self.offset;
|
let start = start + self.offset;
|
||||||
for y in 0..len {
|
for y in 0..height {
|
||||||
self.backend.print_at(start + (0,y), c);
|
self.backend.print_at(start + (0,y), c);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Prints a horizontal line using the given character.
|
/// Prints a horizontal line using the given character.
|
||||||
pub fn print_hline<T: Into<Vec2>>(&self, start: T, len: usize, c: &str) {
|
pub fn print_hline<T: Into<Vec2>>(&self, start: T, width: usize, c: &str) {
|
||||||
let start = start.into();
|
let start = start.into();
|
||||||
|
|
||||||
|
// Nothing to be done if the start if too far to the bottom/right
|
||||||
if !start.fits_in(self.size + self.content_offset) {
|
if !start.fits_in(self.size + self.content_offset) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let hidden_part = self.content_offset.saturating_sub(start);
|
let hidden_part = self.content_offset.saturating_sub(start);
|
||||||
if hidden_part.y > 0 || hidden_part.x >= len {
|
if hidden_part.y > 0 || hidden_part.x >= width {
|
||||||
// We're printing a single line, so we can't do much here.
|
// We're printing a single line, so we can't do much here.
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Skip `hidden_part`
|
// Skip `hidden_part`
|
||||||
let start = start + hidden_part;
|
let start = start + hidden_part;
|
||||||
let len = len - hidden_part.x;
|
assert!(start.fits(self.content_offset));
|
||||||
|
|
||||||
// Don't go overboard
|
let width = width - hidden_part.x;
|
||||||
|
|
||||||
|
// Don't go too far
|
||||||
let start = start - self.content_offset;
|
let start = start - self.content_offset;
|
||||||
|
|
||||||
// Don't write too much if we're close to the end
|
// Don't write too much if we're close to the end
|
||||||
let len = min(len, (self.size.x - start.x) / c.width());
|
let width = min(width, (self.size.x - start.x) / c.width());
|
||||||
|
|
||||||
// Could we avoid allocating?
|
// Could we avoid allocating?
|
||||||
let text: String = ::std::iter::repeat(c).take(len).collect();
|
let text: String = ::std::iter::repeat(c).take(width).collect();
|
||||||
|
|
||||||
let start = start + self.offset;
|
let start = start + self.offset;
|
||||||
self.backend.print_at(start, &text);
|
self.backend.print_at(start, &text);
|
||||||
@ -396,16 +410,23 @@ impl<'a> Printer<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Returns a sub-printer with the given offset.
|
/// Returns a sub-printer with the given offset.
|
||||||
|
///
|
||||||
|
/// It will print in an area slightly to the bottom/right.
|
||||||
pub fn offset<S>(&self, offset: S) -> Printer
|
pub fn offset<S>(&self, offset: S) -> Printer
|
||||||
where
|
where
|
||||||
S: Into<Vec2>,
|
S: Into<Vec2>,
|
||||||
{
|
{
|
||||||
let offset = offset.into();
|
let offset = offset.into();
|
||||||
self.clone().with(|s| {
|
self.clone().with(|s| {
|
||||||
|
// If we are drawing a part of the content,
|
||||||
|
// let's reduce this first.
|
||||||
let consumed = Vec2::min(s.content_offset, offset);
|
let consumed = Vec2::min(s.content_offset, offset);
|
||||||
|
|
||||||
|
let offset = offset - consumed;
|
||||||
s.content_offset = s.content_offset - consumed;
|
s.content_offset = s.content_offset - consumed;
|
||||||
s.offset = s.offset + offset - consumed;
|
|
||||||
|
s.offset = s.offset + offset;
|
||||||
|
|
||||||
s.size = s.size.saturating_sub(offset);
|
s.size = s.size.saturating_sub(offset);
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user